"use client";

/**
 * 생산실적관리(PC) — 하드코딩 페이지
 *
 * 좌측: 작업지시 목록 (work_instruction + detail + item_info JOIN)
 * 우측: 선택된 작업지시의 공정별 실적 (work_order_process)
 *  - 요약 카드 (지시수량/양품/불량/달성률)
 *  - 탭: 실적내역 / 불량내역
 *  - 상세 모달
 */

import React, { useState, useEffect, useCallback, useMemo } from "react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
import {
  Download, Loader2, Inbox, Search, BarChart3, AlertTriangle,
  CheckCircle2, Package, ChevronDown, ChevronRight, ClipboardList,
  ChevronLeft, ChevronsLeft, ChevronsRight,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { apiClient } from "@/lib/api/client";
import { useAuth } from "@/hooks/useAuth";
import { toast } from "sonner";
import { exportToExcel } from "@/lib/utils/excelExport";
import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter";

const WI_TABLE = "work_instruction";
const WOP_TABLE = "work_order_process";

const fmtNum = (v: any) => {
  const n = Number(v);
  return isNaN(n) ? "0" : n.toLocaleString();
};

const fmtDate = (v: any) => {
  if (!v) return "-";
  const s = String(v);
  // "2026-04-06 19:29:07+09" or "2026-04-06T19:29:07"
  return s.split(/[T ]/)[0] || "-";
};
const fmtDateTime = (v: any) => {
  if (!v) return "-";
  const s = String(v);
  // "2026-04-06 19:29:07.049337+09" → "04-06 19:29"
  const match = s.match(/(\d{2})(\d{2})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})/);
  if (match) return `${match[2]}-${match[3]}-${match[4]} ${match[5]}:${match[6]}`;
  return s.substring(0, 16);
};

// 상태 뱃지
const STATUS_CLS: Record<string, string> = {
  "일반": "bg-muted text-foreground",
  "긴급": "bg-destructive/10 text-destructive",
};
const PROGRESS_CLS: Record<string, string> = {
  "대기": "bg-amber-100 text-amber-700",
  "진행중": "bg-blue-100 text-blue-700",
  "완료": "bg-emerald-100 text-emerald-700",
  "acceptable": "bg-blue-100 text-blue-700",
  "completed": "bg-emerald-100 text-emerald-700",
};
const PROGRESS_LABEL: Record<string, string> = {
  "대기": "대기",
  "진행중": "진행중",
  "완료": "완료",
  "acceptable": "진행중",
  "completed": "완료",
};

export default function ProductionResultPage() {
  const { user } = useAuth();

  // ── 좌측: 작업지시 ──
  const [wiList, setWiList] = useState<any[]>([]);
  const [wiLoading, setWiLoading] = useState(false);
  const [searchFilters, setSearchFilters] = useState<FilterValue[]>([]);
  const [selectedWiId, setSelectedWiId] = useState<string | null>(null);
  const [groupBy, setGroupBy] = useState("none");
  const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set());

  // 페이지네이션
  const [currentPage, setCurrentPage] = useState(1);
  const [pageSize, setPageSize] = useState(20);
  const [pageSizeInput, setPageSizeInput] = useState("20");

  // ── 우측: 실적 ──
  const [rightTab, setRightTab] = useState<"result" | "defect">("result");
  const [processData, setProcessData] = useState<any[]>([]);
  const [processLoading, setProcessLoading] = useState(false);

  // ── 카테고리 ──
  const [catOptions, setCatOptions] = useState<Record<string, { code: string; label: string }[]>>({});

  // ── 상세 모달 ──
  const [detailOpen, setDetailOpen] = useState(false);
  const [detailRow, setDetailRow] = useState<any>(null);

  // ════════ 카테고리 로드 ════════
  useEffect(() => {
    const load = async () => {
      const opts: Record<string, { code: string; label: string }[]> = {};
      const flatten = (vals: any[]): { code: string; label: string }[] => {
        const result: { code: string; label: string }[] = [];
        for (const v of vals) {
          result.push({ code: v.valueCode || v.value || v.code, label: v.valueLabel || v.label || v.value });
          if (v.children?.length) result.push(...flatten(v.children));
        }
        return result;
      };
      for (const col of ["status", "work_team"]) {
        try {
          const res = await apiClient.get(`/table-categories/${WI_TABLE}/${col}/values`);
          if (res.data?.success && res.data.data?.length > 0) opts[col] = flatten(res.data.data);
        } catch { /* skip */ }
      }
      setCatOptions(opts);
    };
    load();
  }, []);

  const resolveCategory = (col: string, code: string) => {
    if (!code) return code;
    return catOptions[col]?.find((o) => o.code === code)?.label || code;
  };

  // ════════ 데이터 로드 ════════

  const fetchWiList = useCallback(async () => {
    setWiLoading(true);
    try {
      const params: Record<string, string> = {};
      for (const f of searchFilters) {
        if (f.value) {
          if (f.columnName === "progress_status") params.progressStatus = f.value;
          else if (f.columnName === "status") params.status = f.value;
          else params.keyword = f.value;
        }
      }
      const res = await apiClient.get("/work-instruction/list", { params });
      const raw: any[] = res.data?.data || [];

      // work_instruction_no 기준 중복 제거 (detail JOIN으로 여러 행 반환)
      const seen = new Set<string>();
      const deduped = raw.filter((r) => {
        const key = r.work_instruction_no;
        if (!key || seen.has(key)) return false;
        seen.add(key);
        return true;
      });

      // 진행률 계산
      const enriched = deduped.map((r) => {
        const qty = Number(r.total_qty || r.qty) || 0;
        const completed = Number(r.completed_qty) || 0;
        return {
          ...r,
          _qty: qty,
          _completed: completed,
          _rate: qty > 0 ? Math.round((completed / qty) * 100) : 0,
        };
      });
      setWiList(enriched);
    } catch {
      toast.error("작업지시 목록 조회 실패");
    } finally {
      setWiLoading(false);
    }
  }, [searchFilters]);

  useEffect(() => { fetchWiList(); }, [fetchWiList]);

  // 실적 로드
  useEffect(() => {
    if (!selectedWiId) { setProcessData([]); return; }
    const load = async () => {
      setProcessLoading(true);
      try {
        // 1) 공정 마스터 조회
        const res = await apiClient.post(`/table-management/tables/${WOP_TABLE}/data`, {
          page: 1, size: 0,
          dataFilter: { enabled: true, filters: [{ columnName: "wo_id", operator: "equals", value: selectedWiId }] },
          autoFilter: true,
          sort: { columnName: "seq_no", order: "asc" },
        });
        const wops: any[] = res.data?.data?.data || res.data?.data?.rows || [];

        // 2) 공정별 실적(work_order_process_result) 합계 조인 — 화면이 양품/불량/입력 합계를 보여주려면 result를 별도 집계해 매핑해야 함
        if (wops.length > 0) {
          const wopIds = wops.map((w) => w.id);
          try {
            const wr = await apiClient.post(`/table-management/tables/work_order_process_result/data`, {
              page: 1, size: 0,
              dataFilter: { enabled: true, filters: [{ columnName: "wop_id", operator: "in", value: wopIds }] },
              autoFilter: true,
            });
            const results: any[] = wr.data?.data?.data || wr.data?.data?.rows || [];
            const agg = new Map<string, { good: number; defect: number; input: number; firstStart: string | null; lastEnd: string | null; statuses: Set<string> }>();
            for (const r of results) {
              const cur = agg.get(r.wop_id) || { good: 0, defect: 0, input: 0, firstStart: null, lastEnd: null, statuses: new Set<string>() };
              cur.good   += Number(r.good_qty)   || 0;
              cur.defect += Number(r.defect_qty) || 0;
              cur.input  += Number(r.input_qty)  || 0;
              if (r.started_at && (!cur.firstStart || String(r.started_at) < cur.firstStart)) cur.firstStart = String(r.started_at);
              if (r.completed_at && (!cur.lastEnd || String(r.completed_at) > cur.lastEnd)) cur.lastEnd = String(r.completed_at);
              if (r.status) cur.statuses.add(String(r.status));
              agg.set(r.wop_id, cur);
            }
            const enriched = wops.map((w) => {
              const a = agg.get(w.id);
              return {
                ...w,
                good_qty: a?.good ?? 0,
                defect_qty: a?.defect ?? 0,
                input_qty: a?.input ?? 0,
                started_at: a?.firstStart ?? null,
                completed_at: a?.lastEnd ?? null,
                result_status: a?.statuses.has("completed") ? "completed" : (a?.statuses.values().next().value ?? null),
              };
            });
            setProcessData(enriched);
          } catch {
            setProcessData(wops);
          }
        } else {
          setProcessData([]);
        }
      } catch { setProcessData([]); }
      finally { setProcessLoading(false); }
    };
    load();
  }, [selectedWiId]);

  // ════════ 계산 ════════

  const selectedWi = wiList.find((w) => (w.wi_id || w.id) === selectedWiId);

  const summary = useMemo(() => {
    const instructionQty = selectedWi?._qty || 0;
    const goodQty = processData.reduce((s, r) => s + (Number(r.good_qty) || 0), 0);
    const defectQty = processData.reduce((s, r) => s + (Number(r.defect_qty) || 0), 0);
    const rate = instructionQty > 0 ? Math.round((goodQty / instructionQty) * 100) : 0;
    return { instructionQty, goodQty, defectQty, rate };
  }, [selectedWi, processData]);

  const defectRows = useMemo(() => processData.filter((r) => Number(r.defect_qty) > 0), [processData]);

  const totals = useMemo(() => ({
    input_qty: processData.reduce((s, r) => s + (Number(r.input_qty) || 0), 0),
    good_qty: processData.reduce((s, r) => s + (Number(r.good_qty) || 0), 0),
    defect_qty: processData.reduce((s, r) => s + (Number(r.defect_qty) || 0), 0),
  }), [processData]);

  // ════════ 그룹핑 ════════

  const groupedData = useMemo(() => {
    if (groupBy === "none") return wiList;
    const groups = new Map<string, any[]>();
    for (const wi of wiList) {
      let key = wi[groupBy] || "미지정";
      if (groupBy === "progress_status") key = PROGRESS_LABEL[key] || key;
      else if (groupBy === "work_team" || groupBy === "status") key = resolveCategory(groupBy, key) || key;
      if (!groups.has(key)) groups.set(key, []);
      groups.get(key)!.push(wi);
    }
    const result: any[] = [];
    groups.forEach((items, gk) => {
      result.push({ _group: true, _key: gk, _count: items.length });
      result.push(...items);
    });
    // 기본 전개
    if (expandedGroups.size === 0) setExpandedGroups(new Set(Array.from(groups.keys())));
    return result;
  }, [wiList, groupBy]);

  // 페이지네이션 계산
  const totalPages = Math.max(1, Math.ceil(wiList.length / pageSize));
  const safePage = Math.min(Math.max(1, currentPage), totalPages);
  const paginatedRows = useMemo(() => {
    const start = (safePage - 1) * pageSize;
    return wiList.slice(start, start + pageSize);
  }, [wiList, safePage, pageSize]);

  const paginatedGroupedData = useMemo(() => {
    if (groupBy === "none") return paginatedRows;
    const groups = new Map<string, any[]>();
    for (const wi of paginatedRows) {
      let key = wi[groupBy] || "미지정";
      if (groupBy === "progress_status") key = PROGRESS_LABEL[key] || key;
      else if (groupBy === "work_team" || groupBy === "status") key = resolveCategory(groupBy, key) || key;
      if (!groups.has(key)) groups.set(key, []);
      groups.get(key)!.push(wi);
    }
    const result: any[] = [];
    groups.forEach((items, gk) => {
      result.push({ _group: true, _key: gk, _count: items.length });
      result.push(...items);
    });
    return result;
  }, [paginatedRows, groupBy]);

  const applyPageSize = () => {
    const n = parseInt(pageSizeInput, 10);
    if (!isNaN(n) && n >= 1) { setPageSize(n); setCurrentPage(1); }
    else setPageSizeInput(String(pageSize));
  };

  const getPageNumbers = (): (number | "...")[] => {
    const pages: (number | "...")[] = [];
    if (totalPages <= 7) {
      for (let i = 1; i <= totalPages; i++) pages.push(i);
    } else {
      pages.push(1);
      if (safePage > 3) pages.push("...");
      for (let i = Math.max(2, safePage - 1); i <= Math.min(totalPages - 1, safePage + 1); i++) pages.push(i);
      if (safePage < totalPages - 2) pages.push("...");
      pages.push(totalPages);
    }
    return pages;
  };

  // 필터 변경 시 첫 페이지로 이동
  useEffect(() => { setCurrentPage(1); }, [wiList.length]);

  const toggleGroup = (key: string) => {
    setExpandedGroups((prev) => {
      const next = new Set(prev);
      if (next.has(key)) next.delete(key); else next.add(key);
      return next;
    });
  };

  // ════════ 엑셀 ════════

  const handleExcel = async () => {
    if (!selectedWi || processData.length === 0) {
      toast.error("다운로드할 데이터가 없습니다.");
      return;
    }
    const data = processData.map((r, i) => ({
      No: i + 1,
      공정: r.process_name || "-",
      설비: r.equipment_code || "-",
      생산수량: Number(r.input_qty) || 0,
      양품수량: Number(r.good_qty) || 0,
      불량수량: Number(r.defect_qty) || 0,
      "불량률(%)": Number(r.input_qty) > 0 ? ((Number(r.defect_qty) / Number(r.input_qty)) * 100).toFixed(1) : "0.0",
      시작: r.started_at || "",
      완료: r.completed_at || "",
      비고: r.result_note || r.remark || "",
    }));
    await exportToExcel(data, `생산실적_${selectedWi.work_instruction_no || ""}.xlsx`, "실적내역");
    toast.success("다운로드 완료");
  };

  // defect_detail JSON 파싱
  const parseDefectDetail = (raw: any) => {
    if (!raw) return [];
    try {
      const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
      return Array.isArray(parsed) ? parsed : [];
    } catch { return []; }
  };

  // ════════ 렌더 ════════

  const wiKey = (r: any) => r.wi_id || r.id;

  return (
    <div className="flex h-full flex-col gap-3 p-3">
      {/* 검색 */}
      <DynamicSearchFilter
        tableName={WI_TABLE}
        filterId="c16-production-result"
        onFilterChange={setSearchFilters}
        dataCount={wiList.length}
      />

      {/* 메인 */}
      <div className="flex-1 overflow-hidden rounded-lg border border-border bg-card">
        <ResizablePanelGroup direction="horizontal">
          {/* ────── 좌측: 작업지시 목록 ────── */}
          <ResizablePanel defaultSize={45} minSize={25}>
            <div className="flex flex-col h-full">
              {/* 헤더 */}
              <div className="flex items-center justify-between px-4 py-3 border-b bg-muted/30 shrink-0">
                <div className="flex items-center gap-2">
                  <ClipboardList className="w-4 h-4 text-muted-foreground" />
                  <span className="text-sm font-semibold">작업지시 목록</span>
                  <Badge variant="secondary" className="font-mono text-xs">{wiList.length}건</Badge>
                </div>
                <Select value={groupBy} onValueChange={(v) => { setGroupBy(v); setExpandedGroups(new Set()); }}>
                  <SelectTrigger className="h-8 w-[120px] text-xs">
                    <SelectValue placeholder="그룹없음" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="none">그룹없음</SelectItem>
                    <SelectItem value="progress_status">진행상태별</SelectItem>
                    <SelectItem value="equipment_name">설비별</SelectItem>
                    <SelectItem value="work_team">작업조별</SelectItem>
                  </SelectContent>
                </Select>
              </div>

              {/* 테이블 */}
              <div className="flex-1 overflow-auto">
                {wiLoading ? (
                  <div className="flex items-center justify-center h-full"><Loader2 className="w-6 h-6 animate-spin text-muted-foreground" /></div>
                ) : wiList.length === 0 ? (
                  <div className="flex flex-col items-center justify-center h-full text-muted-foreground gap-2">
                    <Inbox className="w-10 h-10 opacity-30" />
                    <span className="text-sm">작업지시가 없어요</span>
                  </div>
                ) : (
                  <Table>
                    <TableHeader className="sticky top-0 z-10">
                      <TableRow className="bg-muted hover:bg-muted">
                        <TableHead className="w-[130px] text-[11px]">작업지시번호</TableHead>
                        <TableHead className="w-[60px] text-center text-[11px]">상태</TableHead>
                        <TableHead className="w-[60px] text-center text-[11px]">진행</TableHead>
                        <TableHead className="w-[140px] text-[11px]">품목명</TableHead>
                        <TableHead className="w-[80px] text-right text-[11px]">지시수량</TableHead>
                        <TableHead className="w-[100px] text-[11px]">진행률</TableHead>
                        <TableHead className="w-[90px] text-[11px]">설비</TableHead>
                        <TableHead className="w-[60px] text-center text-[11px]">작업조</TableHead>
                        <TableHead className="w-[80px] text-[11px]">시작일</TableHead>
                        <TableHead className="w-[80px] text-[11px]">완료일</TableHead>
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      {paginatedGroupedData.map((row, idx) => {
                        if (row._group) {
                          const expanded = expandedGroups.has(row._key);
                          return (
                            <TableRow key={`g-${row._key}`} className="bg-muted/60 cursor-pointer hover:bg-muted" onClick={() => toggleGroup(row._key)}>
                              <TableCell colSpan={10} className="py-2 px-4">
                                <div className="flex items-center gap-2 text-sm font-semibold">
                                  {expanded ? <ChevronDown className="w-4 h-4" /> : <ChevronRight className="w-4 h-4" />}
                                  {row._key}
                                  <Badge variant="outline" className="text-[10px]">{row._count}건</Badge>
                                </div>
                              </TableCell>
                            </TableRow>
                          );
                        }
                        // 그룹 접힘 체크
                        if (groupBy !== "none") {
                          let gk = row[groupBy] || "미지정";
                          if (groupBy === "progress_status") gk = PROGRESS_LABEL[gk] || gk;
                          else if (groupBy === "work_team" || groupBy === "status") gk = resolveCategory(groupBy, gk) || gk;
                          if (!expandedGroups.has(gk)) return null;
                        }
                        const id = wiKey(row);
                        const selected = id === selectedWiId;
                        const barColor = row._rate >= 100 ? "bg-emerald-500" : row._rate >= 50 ? "bg-primary" : "bg-amber-500";
                        const statusLabel = resolveCategory("status", row.status) || row.status || "-";
                        const progressLabel = PROGRESS_LABEL[row.progress_status] || row.progress_status || "-";
                        return (
                          <TableRow
                            key={id || idx}
                            className={cn("cursor-pointer", selected ? "bg-primary/5 border-l-[3px] border-l-primary" : "hover:bg-accent/50")}
                            onClick={() => setSelectedWiId(id)}
                          >
                            <TableCell className="text-[13px] font-mono text-primary font-semibold">{row.work_instruction_no}</TableCell>
                            <TableCell className="text-center">
                              <span className={cn("text-[10px] font-semibold px-2 py-0.5 rounded-full", STATUS_CLS[statusLabel] || "bg-muted text-foreground")}>{statusLabel}</span>
                            </TableCell>
                            <TableCell className="text-center">
                              <span className={cn("text-[10px] font-semibold px-2 py-0.5 rounded-full", PROGRESS_CLS[row.progress_status] || "bg-muted text-foreground")}>{progressLabel}</span>
                            </TableCell>
                            <TableCell className="text-[13px] truncate max-w-[140px]">{row.item_name || "-"}</TableCell>
                            <TableCell className="text-[13px] text-right font-mono">{fmtNum(row._qty)}</TableCell>
                            <TableCell>
                              <div className="flex items-center gap-1.5">
                                <div className="flex-1 h-1.5 bg-muted rounded-full overflow-hidden">
                                  <div className={cn("h-full rounded-full", barColor)} style={{ width: `${Math.min(row._rate, 100)}%` }} />
                                </div>
                                <span className="text-[11px] text-muted-foreground w-7 text-right">{row._rate}%</span>
                              </div>
                            </TableCell>
                            <TableCell className="text-[12px] text-muted-foreground truncate">{row.equipment_name || "-"}</TableCell>
                            <TableCell className="text-[12px] text-center">{resolveCategory("work_team", row.work_team) || "-"}</TableCell>
                            <TableCell className="text-[12px]">{fmtDate(row.start_date)}</TableCell>
                            <TableCell className="text-[12px]">{fmtDate(row.end_date)}</TableCell>
                          </TableRow>
                        );
                      })}
                    </TableBody>
                  </Table>
                )}
              </div>

              {/* 페이지네이션 */}
              <div className="flex items-center justify-between border-t px-4 py-2.5 text-xs text-muted-foreground shrink-0">
                <div className="flex items-center gap-3">
                  <div className="flex items-center gap-1">
                    <span>전체</span>
                    <span className="font-medium text-foreground">{wiList.length.toLocaleString()}</span>
                    <span>건</span>
                  </div>
                  <div className="flex items-center gap-1.5">
                    <Input
                      type="number"
                      min={1}
                      value={pageSizeInput}
                      onChange={(e) => setPageSizeInput(e.target.value)}
                      onBlur={applyPageSize}
                      onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); applyPageSize(); } }}
                      className="h-7 w-16 text-center text-xs"
                    />
                    <span>건씩 보기</span>
                  </div>
                </div>
                <div className="flex items-center gap-0.5">
                  <button onClick={() => setCurrentPage(1)} disabled={safePage === 1}
                    className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed">
                    <ChevronsLeft className="h-3.5 w-3.5" />
                  </button>
                  <button onClick={() => setCurrentPage((p) => Math.max(1, p - 1))} disabled={safePage === 1}
                    className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed">
                    <ChevronLeft className="h-3.5 w-3.5" />
                  </button>
                  {getPageNumbers().map((page, idx) =>
                    page === "..." ? (
                      <span key={`dot-${idx}`} className="h-7 w-7 flex items-center justify-center text-muted-foreground">...</span>
                    ) : (
                      <button key={page} onClick={() => setCurrentPage(page as number)}
                        className={cn("h-7 w-7 flex items-center justify-center rounded text-xs",
                          page === safePage ? "bg-primary text-primary-foreground font-medium" : "hover:bg-muted")}>
                        {page}
                      </button>
                    )
                  )}
                  <button onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))} disabled={safePage === totalPages}
                    className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed">
                    <ChevronRight className="h-3.5 w-3.5" />
                  </button>
                  <button onClick={() => setCurrentPage(totalPages)} disabled={safePage === totalPages}
                    className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed">
                    <ChevronsRight className="h-3.5 w-3.5" />
                  </button>
                </div>
                <div className="flex items-center gap-1.5">
                  <Input
                    type="number"
                    min={1}
                    max={totalPages}
                    placeholder={String(safePage)}
                    className="h-7 w-14 text-center text-xs"
                    onKeyDown={(e) => {
                      if (e.key === "Enter") {
                        const val = parseInt((e.target as HTMLInputElement).value, 10);
                        if (!isNaN(val) && val >= 1 && val <= totalPages) {
                          setCurrentPage(val);
                          (e.target as HTMLInputElement).value = "";
                          (e.target as HTMLInputElement).blur();
                        }
                      }
                    }}
                    onBlur={(e) => {
                      const val = parseInt(e.target.value, 10);
                      if (!isNaN(val) && val >= 1 && val <= totalPages) {
                        setCurrentPage(val);
                      }
                      e.target.value = "";
                    }}
                  />
                  <span>/ {totalPages} 페이지</span>
                </div>
              </div>
            </div>
          </ResizablePanel>

          <ResizableHandle withHandle />

          {/* ────── 우측: 실적 데이터 ────── */}
          <ResizablePanel defaultSize={55} minSize={30}>
            {!selectedWiId ? (
              <div className="flex flex-col items-center justify-center h-full text-muted-foreground gap-3">
                <Package className="w-12 h-12 opacity-30" />
                <span className="text-sm">좌측에서 작업지시를 선택해주세요</span>
              </div>
            ) : (
              <div className="flex flex-col h-full">
                {/* 헤더 */}
                <div className="flex items-center justify-between px-4 py-3 border-b shrink-0">
                  <div className="flex items-center gap-2">
                    <BarChart3 className="w-4 h-4 text-primary" />
                    <span className="text-sm font-semibold">생산실적(PC)</span>
                    {selectedWi && <span className="text-xs text-muted-foreground">{selectedWi.item_name} / {selectedWi.work_instruction_no}</span>}
                  </div>
                  <Button variant="outline" size="sm" onClick={handleExcel} disabled={processData.length === 0}>
                    <Download className="w-3.5 h-3.5 mr-1" /> 엑셀
                  </Button>
                </div>

                {/* 요약 카드 */}
                <div className="grid grid-cols-4 gap-3 px-4 py-3 border-b bg-muted/20 shrink-0">
                  {[
                    { label: "지시수량", value: fmtNum(summary.instructionQty), icon: Package, color: "text-primary" },
                    { label: "양품수량", value: fmtNum(summary.goodQty), icon: CheckCircle2, color: "text-emerald-600" },
                    { label: "불량수량", value: fmtNum(summary.defectQty), icon: AlertTriangle, color: "text-destructive" },
                    { label: "달성률", value: `${summary.rate}%`, icon: BarChart3, color: "text-violet-600" },
                  ].map((card) => (
                    <div key={card.label} className="bg-card border rounded-lg px-3 py-2.5 text-center">
                      <div className="text-[10px] font-semibold text-muted-foreground mb-1">{card.label}</div>
                      <div className={cn("text-lg font-bold", card.color)}>{card.value}</div>
                    </div>
                  ))}
                </div>

                {/* 탭 */}
                <div className="flex border-b shrink-0">
                  {(["result", "defect"] as const).map((tab) => (
                    <button
                      key={tab}
                      className={cn(
                        "px-4 py-2.5 text-xs font-semibold border-b-2 transition-colors",
                        rightTab === tab ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground"
                      )}
                      onClick={() => setRightTab(tab)}
                    >
                      {tab === "result" ? "📊 실적내역" : "⚠️ 불량내역"}
                      {tab === "defect" && defectRows.length > 0 && (
                        <Badge variant="destructive" className="ml-1.5 text-[9px] px-1.5 py-0">{defectRows.length}</Badge>
                      )}
                    </button>
                  ))}
                </div>

                {/* 탭 콘텐츠 */}
                <div className="flex-1 overflow-auto">
                  {processLoading ? (
                    <div className="flex items-center justify-center h-full"><Loader2 className="w-5 h-5 animate-spin text-muted-foreground" /></div>
                  ) : processData.length === 0 ? (
                    <div className="flex flex-col items-center justify-center h-full text-muted-foreground gap-2">
                      <Inbox className="w-8 h-8 opacity-30" />
                      <span className="text-sm">등록된 실적이 없습니다</span>
                      <span className="text-xs">POP에서 실적을 등록해주세요</span>
                    </div>
                  ) : rightTab === "result" ? (
                    /* ── 실적내역 ── */
                    <Table>
                      <TableHeader className="sticky top-0 z-10">
                        <TableRow className="bg-muted hover:bg-muted">
                          <TableHead className="w-[40px] text-center text-[11px]">No</TableHead>
                          <TableHead className="w-[80px] text-[11px]">공정</TableHead>
                          <TableHead className="w-[90px] text-[11px]">설비</TableHead>
                          <TableHead className="w-[80px] text-right text-[11px]">생산수량</TableHead>
                          <TableHead className="w-[80px] text-right text-[11px]">양품수량</TableHead>
                          <TableHead className="w-[80px] text-right text-[11px]">불량수량</TableHead>
                          <TableHead className="w-[60px] text-center text-[11px]">불량률</TableHead>
                          <TableHead className="w-[100px] text-[11px]">작업시간</TableHead>
                          <TableHead className="w-[60px] text-[11px]">상태</TableHead>
                          <TableHead className="text-[11px]">비고</TableHead>
                        </TableRow>
                      </TableHeader>
                      <TableBody>
                        {processData.map((r, i) => {
                          const inputQty = Number(r.input_qty) || 0;
                          const defectQty = Number(r.defect_qty) || 0;
                          const defRate = inputQty > 0 ? ((defectQty / inputQty) * 100).toFixed(1) : "0.0";
                          return (
                            <TableRow key={r.id || i} className="cursor-pointer hover:bg-accent/50" onClick={() => { setDetailRow(r); setDetailOpen(true); }}>
                              <TableCell className="text-center text-[13px]">{i + 1}</TableCell>
                              <TableCell className="text-[13px]">
                                <span className="px-2 py-0.5 rounded bg-amber-50 text-amber-700 text-[11px] font-medium">{r.process_name || "-"}</span>
                              </TableCell>
                              <TableCell className="text-[12px] text-muted-foreground">{r.equipment_code || "-"}</TableCell>
                              <TableCell className="text-[13px] text-right font-mono font-semibold">{fmtNum(r.input_qty)}</TableCell>
                              <TableCell className="text-[13px] text-right font-mono text-emerald-600 font-semibold">{fmtNum(r.good_qty)}</TableCell>
                              <TableCell className={cn("text-[13px] text-right font-mono font-semibold", defectQty > 0 ? "text-destructive" : "text-muted-foreground")}>{fmtNum(r.defect_qty)}</TableCell>
                              <TableCell className="text-center">
                                <span className={cn("text-[10px] font-semibold px-2 py-0.5 rounded-full", parseFloat(defRate) > 2 ? "bg-red-100 text-red-700" : "bg-emerald-100 text-emerald-700")}>{defRate}%</span>
                              </TableCell>
                              <TableCell className="text-[12px]">{fmtDateTime(r.started_at)} ~ {fmtDateTime(r.completed_at)}</TableCell>
                              <TableCell className="text-[12px]">
                                <span className={cn("text-[10px] px-2 py-0.5 rounded-full font-medium", r.status === "completed" ? "bg-emerald-100 text-emerald-700" : r.status === "in_progress" ? "bg-blue-100 text-blue-700" : "bg-muted text-muted-foreground")}>{r.status || "-"}</span>
                              </TableCell>
                              <TableCell className="text-[12px] text-muted-foreground truncate max-w-[120px]">{r.result_note || r.remark || "-"}</TableCell>
                            </TableRow>
                          );
                        })}
                        {/* 합계 */}
                        <TableRow className="bg-muted/60 font-bold border-t-2">
                          <TableCell colSpan={3} className="text-center text-[13px]">합계</TableCell>
                          <TableCell className="text-right font-mono text-[13px]">{fmtNum(totals.input_qty)}</TableCell>
                          <TableCell className="text-right font-mono text-[13px] text-emerald-600">{fmtNum(totals.good_qty)}</TableCell>
                          <TableCell className="text-right font-mono text-[13px] text-destructive">{fmtNum(totals.defect_qty)}</TableCell>
                          <TableCell className="text-center text-[12px]">
                            {totals.input_qty > 0 ? ((totals.defect_qty / totals.input_qty) * 100).toFixed(1) : "0.0"}%
                          </TableCell>
                          <TableCell colSpan={3} />
                        </TableRow>
                      </TableBody>
                    </Table>
                  ) : (
                    /* ── 불량내역 ── */
                    defectRows.length === 0 ? (
                      <div className="flex flex-col items-center justify-center h-full text-muted-foreground gap-2">
                        <CheckCircle2 className="w-8 h-8 opacity-30" />
                        <span className="text-sm">불량 내역이 없습니다</span>
                      </div>
                    ) : (
                      <Table>
                        <TableHeader className="sticky top-0 z-10">
                          <TableRow className="bg-muted hover:bg-muted">
                            <TableHead className="w-[40px] text-center text-[11px]">No</TableHead>
                            <TableHead className="w-[80px] text-[11px]">공정</TableHead>
                            <TableHead className="w-[90px] text-[11px]">설비</TableHead>
                            <TableHead className="w-[80px] text-right text-[11px]">불량수량</TableHead>
                            <TableHead className="w-[100px] text-[11px]">불량유형</TableHead>
                            <TableHead className="w-[120px] text-[11px]">불량원인</TableHead>
                            <TableHead className="text-[11px]">비고</TableHead>
                          </TableRow>
                        </TableHeader>
                        <TableBody>
                          {defectRows.map((r, i) => {
                            const details = parseDefectDetail(r.defect_detail);
                            const defType = details.map((d: any) => d.defect_name || d.defect_code).filter(Boolean).join(", ") || "-";
                            return (
                              <TableRow key={r.id || i} className="cursor-pointer hover:bg-accent/50" onClick={() => { setDetailRow(r); setDetailOpen(true); }}>
                                <TableCell className="text-center text-[13px]">{i + 1}</TableCell>
                                <TableCell className="text-[13px]">
                                  <span className="px-2 py-0.5 rounded bg-amber-50 text-amber-700 text-[11px] font-medium">{r.process_name || "-"}</span>
                                </TableCell>
                                <TableCell className="text-[12px] text-muted-foreground">{r.equipment_code || "-"}</TableCell>
                                <TableCell className="text-[13px] text-right font-mono font-bold text-destructive">{fmtNum(r.defect_qty)}</TableCell>
                                <TableCell className="text-[12px]">
                                  <span className="px-2 py-0.5 rounded bg-amber-50 text-amber-700 text-[11px]">{defType}</span>
                                </TableCell>
                                <TableCell className="text-[12px] text-muted-foreground">{r.result_note || "-"}</TableCell>
                                <TableCell className="text-[12px] text-muted-foreground truncate">{r.remark || "-"}</TableCell>
                              </TableRow>
                            );
                          })}
                        </TableBody>
                      </Table>
                    )
                  )}
                </div>
              </div>
            )}
          </ResizablePanel>
        </ResizablePanelGroup>
      </div>

      {/* ── 상세 모달 ── */}
      <Dialog open={detailOpen} onOpenChange={setDetailOpen}>
        <DialogContent className="max-w-[600px] max-h-[80vh] overflow-y-auto">
          <DialogHeader>
            <DialogTitle className="flex items-center gap-2"><BarChart3 className="w-5 h-5" /> 실적 상세</DialogTitle>
            <DialogDescription>생산 실적의 상세 정보입니다</DialogDescription>
          </DialogHeader>
          {detailRow && (
            <div className="space-y-4 pt-2">
              <div>
                <p className="text-sm font-semibold mb-2 pb-1.5 border-b">기본 정보</p>
                <div className="grid grid-cols-2 gap-3">
                  <div><Label className="text-xs">공정</Label><Input value={detailRow.process_name || "-"} readOnly className="h-8 text-xs bg-muted/50" /></div>
                  <div><Label className="text-xs">설비</Label><Input value={detailRow.equipment_code || "-"} readOnly className="h-8 text-xs bg-muted/50" /></div>
                  <div><Label className="text-xs">순번</Label><Input value={detailRow.seq_no || "-"} readOnly className="h-8 text-xs bg-muted/50" /></div>
                  <div><Label className="text-xs">상태</Label><Input value={detailRow.status || "-"} readOnly className="h-8 text-xs bg-muted/50" /></div>
                </div>
              </div>
              <div>
                <p className="text-sm font-semibold mb-2 pb-1.5 border-b">수량 정보</p>
                <div className="grid grid-cols-3 gap-3">
                  <div><Label className="text-xs">생산수량</Label><Input value={fmtNum(detailRow.input_qty)} readOnly className="h-8 text-xs bg-muted/50" /></div>
                  <div><Label className="text-xs">양품수량</Label><Input value={fmtNum(detailRow.good_qty)} readOnly className="h-8 text-xs bg-muted/50 text-emerald-600 font-semibold" /></div>
                  <div><Label className="text-xs">불량수량</Label><Input value={fmtNum(detailRow.defect_qty)} readOnly className={cn("h-8 text-xs bg-muted/50 font-semibold", Number(detailRow.defect_qty) > 0 ? "text-destructive" : "")} /></div>
                </div>
              </div>
              <div>
                <p className="text-sm font-semibold mb-2 pb-1.5 border-b">작업 시간</p>
                <div className="grid grid-cols-2 gap-3">
                  <div><Label className="text-xs">시작</Label><Input value={detailRow.started_at ? String(detailRow.started_at).replace("T", " ") : "-"} readOnly className="h-8 text-xs bg-muted/50" /></div>
                  <div><Label className="text-xs">완료</Label><Input value={detailRow.completed_at ? String(detailRow.completed_at).replace("T", " ") : "-"} readOnly className="h-8 text-xs bg-muted/50" /></div>
                </div>
              </div>
              {Number(detailRow.defect_qty) > 0 && (
                <div>
                  <p className="text-sm font-semibold mb-2 pb-1.5 border-b">불량 정보</p>
                  {parseDefectDetail(detailRow.defect_detail).length > 0 ? (
                    <div className="space-y-1">
                      {parseDefectDetail(detailRow.defect_detail).map((d: any, i: number) => (
                        <div key={i} className="flex items-center gap-3 text-xs bg-red-50 px-3 py-1.5 rounded">
                          <span className="font-medium">{d.defect_name || d.defect_code || "-"}</span>
                          <span className="text-muted-foreground">수량: {d.qty || 0}</span>
                          {d.disposition && <span className="text-muted-foreground">처리: {d.disposition}</span>}
                        </div>
                      ))}
                    </div>
                  ) : (
                    <p className="text-xs text-muted-foreground">상세 불량 데이터 없음</p>
                  )}
                </div>
              )}
              {(detailRow.result_note || detailRow.remark) && (
                <div>
                  <p className="text-sm font-semibold mb-2 pb-1.5 border-b">비고</p>
                  <p className="text-xs bg-muted/50 p-2 rounded">{detailRow.result_note || detailRow.remark}</p>
                </div>
              )}
            </div>
          )}
        </DialogContent>
      </Dialog>
    </div>
  );
}
