"use client";

import React, { useState, useMemo, useEffect, useCallback } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
  DialogDescription,
} from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import {
  Plus,
  Save,
  Inbox,
  Pencil,
  FileText,
  XCircle,
  ArrowRight,
  Paperclip,
  Upload,
  Loader2,
  Settings2,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { toast } from "sonner";
import {
  getDesignRequestList,
  createDesignRequest,
  updateDesignRequest,
  addRequestHistory,
  getEcnList,
  createEcn,
  updateEcn,
} from "@/lib/api/design";
import { useTableSettings } from "@/hooks/useTableSettings";
import { TableSettingsModal } from "@/components/common/TableSettingsModal";
import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter";

// --- Types ---
type ChangeType = "설계오류" | "원가절감" | "고객요청" | "공정개선" | "법규대응";
type EcrStatus = "요청접수" | "영향도분석" | "ECN발행" | "기각";
type EcnStatus = "ECN발행" | "도면변경" | "통보완료" | "적용완료";
type TabType = "ecr" | "ecn";

interface EcrHistory {
  status: string;
  date: string;
  user: string;
  desc: string;
}

interface EcrItem {
  id: string;
  _id?: string;
  date: string;
  changeType: ChangeType;
  urgency: "보통" | "긴급";
  status: EcrStatus;
  target: string;
  drawingNo: string;
  reqDept: string;
  requester: string;
  reason: string;
  content: string;
  impact: string[];
  applyTiming: string;
  ecnNo: string;
  history: EcrHistory[];
}

interface EcnItem {
  id: string;
  _id?: string;
  ecrNo: string;
  ecrId?: string;
  date: string;
  applyDate: string;
  status: EcnStatus;
  target: string;
  drawingBefore: string;
  drawingAfter: string;
  designer: string;
  before: string;
  after: string;
  reason: string;
  notifyDepts: string[];
  remark: string;
  history: EcrHistory[];
}

// --- Style Helpers ---
const getChangeTypeStyle = (type: ChangeType) => {
  switch (type) {
    case "설계오류":
      return "bg-destructive/10 text-destructive border-destructive/20";
    case "원가절감":
      return "bg-success/10 text-success border-success/20";
    case "고객요청":
      return "bg-info/10 text-info border-info/20";
    case "공정개선":
      return "bg-warning/10 text-warning border-warning/20";
    case "법규대응":
      return "bg-primary/10 text-primary border-primary/20";
    default:
      return "bg-muted text-muted-foreground border-border";
  }
};

const getEcrStatusStyle = (status: EcrStatus) => {
  switch (status) {
    case "요청접수":
      return "bg-info/10 text-info border-info/20";
    case "영향도분석":
      return "bg-warning/10 text-warning border-warning/20";
    case "ECN발행":
      return "bg-success/10 text-success border-success/20";
    case "기각":
      return "bg-muted text-muted-foreground border-border";
    default:
      return "bg-muted text-muted-foreground border-border";
  }
};

const getEcnStatusStyle = (status: EcnStatus) => {
  switch (status) {
    case "ECN발행":
      return "bg-info/10 text-info border-info/20";
    case "도면변경":
      return "bg-primary/10 text-primary border-primary/20";
    case "통보완료":
      return "bg-warning/10 text-warning border-warning/20";
    case "적용완료":
      return "bg-success/10 text-success border-success/20";
    default:
      return "bg-muted text-muted-foreground border-border";
  }
};

const getImpactBadgeStyle = (impact: string) => {
  switch (impact) {
    case "BOM":
      return "bg-info/10 text-info border-info/20";
    case "공정":
      return "bg-warning/10 text-warning border-warning/20";
    case "금형":
      return "bg-destructive/10 text-destructive border-destructive/20";
    case "검사기준":
      return "bg-primary/10 text-primary border-primary/20";
    case "구매":
    case "원가":
      return "bg-success/10 text-success border-success/20";
    default:
      return "bg-muted text-muted-foreground border-border";
  }
};

const getTimelineStatusStyle = (status: string) => {
  switch (status) {
    case "기각":
      return "bg-muted text-muted-foreground border-border";
    case "적용완료":
    case "ECN발행":
      return "bg-success/10 text-success border-success/20";
    case "영향도분석":
      return "bg-warning/10 text-warning border-warning/20";
    case "도면변경":
      return "bg-primary/10 text-primary border-primary/20";
    case "통보완료":
      return "bg-info/10 text-info border-info/20";
    default:
      return "bg-info/10 text-info border-info/20";
  }
};

// --- Constants ---
const CHANGE_TYPES: ChangeType[] = ["설계오류", "원가절감", "고객요청", "공정개선", "법규대응"];
const ECR_STATUSES: EcrStatus[] = ["요청접수", "영향도분석", "ECN발행", "기각"];
const ECN_STATUSES: EcnStatus[] = ["ECN발행", "도면변경", "통보완료", "적용완료"];
const DEPARTMENTS = ["품질팀", "생산팀", "영업팀", "구매팀", "설계팀"];
const DESIGNERS = ["이설계", "박도면", "최기구", "김전장"];
const IMPACT_OPTIONS = [
  { key: "BOM", label: "BOM 변경" },
  { key: "공정", label: "공정 변경" },
  { key: "금형", label: "금형 변경" },
  { key: "검사기준", label: "검사기준 변경" },
  { key: "구매", label: "구매 변경" },
  { key: "원가", label: "원가 영향" },
];
const NOTIFY_DEPTS = [
  { key: "생산팀", label: "생산팀" },
  { key: "품질팀", label: "품질팀" },
  { key: "구매팀", label: "구매팀" },
  { key: "영업팀", label: "영업팀" },
  { key: "물류팀", label: "물류팀" },
  { key: "금형팀", label: "금형팀" },
];

// --- API Response Mapping ---
function mapEcrFromApi(raw: any): EcrItem {
  const history = (raw.history || []).map((h: any) => ({
    status: h.step || h.status || "",
    date: h.history_date || "",
    user: h.user_name || "",
    desc: h.description || "",
  }));
  return {
    id: raw.request_no || raw.id || "",
    _id: raw.id,
    date: raw.request_date || "",
    changeType: (raw.change_type as ChangeType) || "설계오류",
    urgency: (raw.urgency as "보통" | "긴급") || "보통",
    status: (raw.status as EcrStatus) || "요청접수",
    target: raw.target_name || "",
    drawingNo: raw.drawing_no || "",
    reqDept: raw.req_dept || "",
    requester: raw.requester || "",
    reason: raw.reason || "",
    content: raw.content || "",
    impact: Array.isArray(raw.impact) ? raw.impact : [],
    applyTiming: raw.apply_timing || "",
    ecnNo: raw.ecn_no || "",
    history,
  };
}

function mapEcnFromApi(raw: any, ecrData: EcrItem[]): EcnItem {
  const history = (raw.history || []).map((h: any) => ({
    status: h.status || "",
    date: h.history_date || "",
    user: h.user_name || "",
    desc: h.description || "",
  }));
  const ecrNo = raw.ecr_id
    ? ecrData.find((e) => e._id === raw.ecr_id)?.id ?? raw.ecr_id
    : "";
  return {
    id: raw.ecn_no || raw.id || "",
    _id: raw.id,
    ecrNo,
    ecrId: raw.ecr_id,
    date: raw.ecn_date || "",
    applyDate: raw.apply_date || "",
    status: (raw.status as EcnStatus) || "ECN발행",
    target: raw.target || "",
    drawingBefore: raw.drawing_before || "",
    drawingAfter: raw.drawing_after || "",
    designer: raw.designer || "",
    before: raw.before_content || "",
    after: raw.after_content || "",
    reason: raw.reason || "",
    notifyDepts: Array.isArray(raw.notify_depts) ? raw.notify_depts : [],
    remark: raw.remark || "",
    history,
  };
}

// --- Timeline Component ---
function Timeline({ history }: { history: EcrHistory[] }) {
  return (
    <div className="space-y-0">
      {history.map((h, idx) => {
        const isLast = idx === history.length - 1;
        const isRejected = h.status === "기각";
        const isCompleted = h.status === "적용완료";
        return (
          <div key={idx} className="flex gap-3 relative">
            <div className="flex flex-col items-center">
              <div
                className={cn(
                  "w-3 h-3 rounded-full border-2 mt-1.5 shrink-0",
                  isLast && isRejected
                    ? "bg-destructive border-destructive/60"
                    : isLast && isCompleted
                      ? "bg-success border-success/60"
                      : isLast
                        ? "bg-primary border-primary/50 ring-4 ring-primary/10"
                        : "bg-success border-success/60"
                )}
              />
              {!isLast && (
                <div className="w-px flex-1 bg-border min-h-[24px]" />
              )}
            </div>
            <div className="pb-4 min-w-0">
              <div className="flex items-center gap-2 mb-0.5">
                <span
                  className={cn(
                    "px-2 py-0.5 rounded-full text-[10px] font-medium border",
                    getTimelineStatusStyle(h.status)
                  )}
                >
                  {h.status}
                </span>
              </div>
              <p className="text-xs text-foreground">{h.desc}</p>
              <p className="text-[11px] text-muted-foreground mt-0.5">
                {h.date} · {h.user}
              </p>
            </div>
          </div>
        );
      })}
    </div>
  );
}

// --- Grid Columns ---
const ECR_GRID_COLUMNS = [
  { key: "request_no", label: "ECR번호" },
  { key: "change_type", label: "변경유형" },
  { key: "status", label: "상태" },
  { key: "urgency", label: "긴급" },
  { key: "target_name", label: "대상 품목/설비" },
  { key: "drawing_no", label: "도면번호" },
  { key: "req_dept", label: "요청부서" },
  { key: "requester", label: "요청자" },
  { key: "request_date", label: "요청일자" },
  { key: "ecn_no", label: "관련 ECN" },
];

const ECN_GRID_COLUMNS = [
  { key: "ecn_no", label: "ECN번호" },
  { key: "status", label: "상태" },
  { key: "target", label: "대상 품목/설비" },
  { key: "drawing_after", label: "도면 (변경 후)" },
  { key: "designer", label: "설계담당" },
  { key: "ecn_date", label: "발행일자" },
  { key: "apply_date", label: "적용일자" },
  { key: "notify_depts", label: "통보 부서" },
  { key: "ecr_id", label: "관련 ECR" },
];

// --- Main Component ---
export default function DesignChangeManagementPage() {
  const tsEcr = useTableSettings("c16-change-management-ecr", "dsn_design_request", ECR_GRID_COLUMNS);
  const tsEcn = useTableSettings("c16-change-management-ecn", "dsn_ecn", ECN_GRID_COLUMNS);
  const [currentTab, setCurrentTab] = useState<TabType>("ecr");
  const [ecrData, setEcrData] = useState<EcrItem[]>([]);
  const [ecnData, setEcnData] = useState<EcnItem[]>([]);
  const [loading, setLoading] = useState(true);
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [detailOpen, setDetailOpen] = useState(false);

  // 검색 필터 (DynamicSearchFilter)
  const [searchFilters, setSearchFilters] = useState<FilterValue[]>([]);

  // ECR 모달
  const [isEcrModalOpen, setIsEcrModalOpen] = useState(false);
  const [isEcrEditMode, setIsEcrEditMode] = useState(false);
  const [ecrForm, setEcrForm] = useState<Partial<EcrItem>>({});
  const [ecrImpactChecks, setEcrImpactChecks] = useState<Record<string, boolean>>({});

  // ECN 모달
  const [isEcnModalOpen, setIsEcnModalOpen] = useState(false);
  const [ecnForm, setEcnForm] = useState<Partial<EcnItem>>({});
  const [ecnNotifyChecks, setEcnNotifyChecks] = useState<Record<string, boolean>>({});

  // 기각 모달
  const [isRejectModalOpen, setIsRejectModalOpen] = useState(false);
  const [rejectReason, setRejectReason] = useState("");
  const [rejectTargetId, setRejectTargetId] = useState("");


  const fetchData = useCallback(async () => {
    setLoading(true);
    try {
      const [ecrRes, ecnRes] = await Promise.all([
        getDesignRequestList({ source_type: "ecr" }),
        getEcnList(),
      ]);
      if (ecrRes.success && ecrRes.data) {
        setEcrData((ecrRes.data as any[]).map(mapEcrFromApi));
      }
      if (ecnRes.success && ecnRes.data) {
        const ecrList = ecrRes.success && ecrRes.data ? (ecrRes.data as any[]).map(mapEcrFromApi) : [];
        setEcnData((ecnRes.data as any[]).map((r) => mapEcnFromApi(r, ecrList)));
      }
    } catch {
      toast.error("데이터를 불러오는데 실패했어요.");
    } finally {
      setLoading(false);
    }
  }, []);

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

  // snake_case → camelCase 매핑 (ECR)
  const ecrFieldMap: Record<string, string> = {
    request_no: "id",
    request_date: "date",
    change_type: "changeType",
    target_name: "target",
    drawing_no: "drawingNo",
    req_dept: "reqDept",
    ecn_no: "ecnNo",
    apply_timing: "applyTiming",
  };
  // snake_case → camelCase 매핑 (ECN)
  const ecnFieldMap: Record<string, string> = {
    ecn_no: "id",
    ecn_date: "date",
    apply_date: "applyDate",
    drawing_before: "drawingBefore",
    drawing_after: "drawingAfter",
    ecr_id: "ecrNo",
    notify_depts: "notifyDepts",
  };
  const getFieldValue = (obj: any, colName: string, map: Record<string, string>): string => {
    const key = map[colName] || colName;
    const val = obj[key];
    if (Array.isArray(val)) return val.join(",");
    return val !== undefined && val !== null ? String(val) : "";
  };

  const applyFilters = (items: any[], map: Record<string, string>) => {
    if (searchFilters.length === 0) return items;
    return items.filter((item) => {
      for (const f of searchFilters) {
        const val = getFieldValue(item, f.columnName, map);
        if (f.operator === "contains") {
          if (!val.toLowerCase().includes(f.value.toLowerCase())) return false;
        } else if (f.operator === "equals") {
          if (val !== f.value) return false;
        } else if (f.operator === "in") {
          const allowed = f.value.split("|");
          if (!allowed.includes(val)) return false;
        } else if (f.operator === "between") {
          const [from, to] = f.value.split("|");
          if (from && val < from) return false;
          if (to && val > to) return false;
        }
      }
      return true;
    });
  };

  // --- Filtered Data ---
  const filteredEcr = useMemo(() => {
    return applyFilters(ecrData, ecrFieldMap)
      .sort((a: EcrItem, b: EcrItem) => b.date.localeCompare(a.date));
  }, [ecrData, searchFilters]);

  const filteredEcn = useMemo(() => {
    return applyFilters(ecnData, ecnFieldMap)
      .sort((a: EcnItem, b: EcnItem) => b.date.localeCompare(a.date));
  }, [ecnData, searchFilters]);

  // --- Status Counts ---
  const ecrStatusCounts = useMemo(() => {
    const counts: Record<string, number> = {};
    ECR_STATUSES.forEach((s) => (counts[s] = ecrData.filter((r) => r.status === s).length));
    return counts;
  }, [ecrData]);

  const ecnStatusCounts = useMemo(() => {
    const counts: Record<string, number> = {};
    ECN_STATUSES.forEach((s) => (counts[s] = ecnData.filter((r) => r.status === s).length));
    return counts;
  }, [ecnData]);

  // --- Selected Items ---
  const selectedEcr = useMemo(
    () => (currentTab === "ecr" ? ecrData.find((r) => r.id === selectedId) : null),
    [ecrData, selectedId, currentTab]
  );
  const selectedEcn = useMemo(
    () => (currentTab === "ecn" ? ecnData.find((r) => r.id === selectedId) : null),
    [ecnData, selectedId, currentTab]
  );

  // --- Tab Switch ---
  const handleTabSwitch = (tab: TabType) => {
    setCurrentTab(tab);
    setSelectedId(null);
  };

  const handleFilterByStatus = (_status: string) => {
    // Status filter now handled by DynamicSearchFilter
  };

  // --- ECR/ECN Navigation ---
  const navigateToLink = (targetId: string) => {
    setDetailOpen(false);
    if (targetId.startsWith("ECN")) {
      setCurrentTab("ecn");
      setSelectedId(targetId);
    } else if (targetId.startsWith("ECR")) {
      setCurrentTab("ecr");
      setSelectedId(targetId);
    }
  };

  // --- ECR Number Generator ---
  const generateEcrNo = useCallback(() => {
    const year = new Date().getFullYear();
    const prefix = `ECR-${year}-`;
    const existing = ecrData.filter((r) => r.id.startsWith(prefix));
    const maxNum = existing.reduce((max, r) => {
      const num = parseInt(r.id.split("-")[2]);
      return num > max ? num : max;
    }, 0);
    return `${prefix}${String(maxNum + 1).padStart(4, "0")}`;
  }, [ecrData]);

  const generateEcnNo = useCallback(() => {
    const year = new Date().getFullYear();
    const prefix = `ECN-${year}-`;
    const existing = ecnData.filter((r) => r.id.startsWith(prefix));
    const maxNum = existing.reduce((max, r) => {
      const num = parseInt(r.id.split("-")[2]);
      return num > max ? num : max;
    }, 0);
    return `${prefix}${String(maxNum + 1).padStart(4, "0")}`;
  }, [ecnData]);

  // --- ECR Modal ---
  const openEcrRegisterModal = () => {
    setIsEcrEditMode(false);
    setEcrForm({
      id: generateEcrNo(),
      date: new Date().toISOString().split("T")[0],
      changeType: undefined,
      urgency: "보통",
      target: "",
      drawingNo: "",
      reqDept: "",
      requester: "",
      reason: "",
      content: "",
      applyTiming: "즉시",
    });
    setEcrImpactChecks({});
    setIsEcrModalOpen(true);
  };

  const openEcrEditModal = (id: string) => {
    const item = ecrData.find((r) => r.id === id);
    if (!item) return;
    setIsEcrEditMode(true);
    setEcrForm({ ...item });
    const checks: Record<string, boolean> = {};
    IMPACT_OPTIONS.forEach((opt) => {
      checks[opt.key] = item.impact.includes(opt.key);
    });
    setEcrImpactChecks(checks);
    setIsEcrModalOpen(true);
  };

  const handleSaveEcr = async () => {
    if (!ecrForm.changeType) {
      toast.error("변경 유형을 선택해 주세요.");
      return;
    }
    if (!ecrForm.target?.trim()) {
      toast.error("대상 품목/설비를 입력해 주세요.");
      return;
    }
    if (!ecrForm.reason?.trim()) {
      toast.error("변경 사유를 입력해 주세요.");
      return;
    }
    if (!ecrForm.content?.trim()) {
      toast.error("변경 요구 내용을 입력해 주세요.");
      return;
    }

    const impact = IMPACT_OPTIONS.filter((opt) => ecrImpactChecks[opt.key]).map((opt) => opt.key);
    const reqDate = ecrForm.date || new Date().toISOString().split("T")[0];
    const historyEntry = {
      step: "요청접수",
      history_date: reqDate,
      user_name: ecrForm.requester || "시스템",
      description: `${ecrForm.reqDept || ""}에서 ECR 등록`,
    };

    if (isEcrEditMode && ecrForm._id) {
      const res = await updateDesignRequest(ecrForm._id, {
        request_no: ecrForm.id,
        request_date: reqDate,
        change_type: ecrForm.changeType,
        urgency: ecrForm.urgency || "보통",
        target_name: ecrForm.target,
        drawing_no: ecrForm.drawingNo || "",
        req_dept: ecrForm.reqDept || "",
        requester: ecrForm.requester || "",
        reason: ecrForm.reason,
        content: ecrForm.content,
        impact,
        apply_timing: ecrForm.applyTiming || "즉시",
      });
      if (res.success) {
        toast.success("ECR이 수정되었어요.");
        setIsEcrModalOpen(false);
        fetchData();
      } else {
        toast.error(res.message || "ECR 수정에 실패했어요.");
      }
    } else {
      const res = await createDesignRequest({
        request_no: ecrForm.id || generateEcrNo(),
        source_type: "ecr",
        request_date: reqDate,
        change_type: ecrForm.changeType,
        urgency: ecrForm.urgency || "보통",
        status: "요청접수",
        target_name: ecrForm.target,
        drawing_no: ecrForm.drawingNo || "",
        req_dept: ecrForm.reqDept || "",
        requester: ecrForm.requester || "",
        reason: ecrForm.reason,
        content: ecrForm.content,
        impact,
        apply_timing: ecrForm.applyTiming || "즉시",
        history: [historyEntry],
      });
      if (res.success) {
        toast.success("ECR이 등록되었어요.");
        setIsEcrModalOpen(false);
        fetchData();
      } else {
        toast.error(res.message || "ECR 등록에 실패했어요.");
      }
    }
  };

  // --- ECN Modal ---
  const openEcnIssueModal = (ecrId: string) => {
    const ecr = ecrData.find((r) => r.id === ecrId);
    if (!ecr) return;

    setEcnForm({
      id: generateEcnNo(),
      ecrNo: ecrId,
      ecrId: ecr._id,
      date: new Date().toISOString().split("T")[0],
      target: ecr.target,
      reason: ecr.reason,
      drawingBefore: ecr.drawingNo,
      drawingAfter: "",
      designer: "",
      before: "",
      after: "",
      applyDate: "",
      remark: "",
    });
    setEcnNotifyChecks({});
    setIsEcnModalOpen(true);
  };

  const handleSaveEcn = async () => {
    if (!ecnForm.after?.trim()) {
      toast.error("변경 후(TO-BE) 내용을 입력해 주세요.");
      return;
    }
    if (!ecnForm.applyDate) {
      toast.error("적용일자를 입력해 주세요.");
      return;
    }
    if (!ecnForm.ecrId) {
      toast.error("관련 ECR 정보가 없어요.");
      return;
    }

    const notifyDepts = NOTIFY_DEPTS.filter((d) => ecnNotifyChecks[d.key]).map((d) => d.key);
    const ecnDate = ecnForm.date || new Date().toISOString().split("T")[0];
    const historyEntry = {
      status: "ECN발행",
      history_date: ecnDate,
      user_name: ecnForm.designer || "시스템",
      description: "ECN 발행",
    };

    const ecnNo = ecnForm.id || generateEcnNo();
    const res = await createEcn({
      ecn_no: ecnNo,
      ecr_id: ecnForm.ecrId,
      ecn_date: ecnDate,
      apply_date: ecnForm.applyDate,
      status: "ECN발행",
      target: ecnForm.target || "",
      drawing_before: ecnForm.drawingBefore || "",
      drawing_after: ecnForm.drawingAfter || "(미정)",
      designer: ecnForm.designer || "",
      before_content: ecnForm.before || "",
      after_content: ecnForm.after || "",
      reason: ecnForm.reason || "",
      remark: ecnForm.remark || "",
      notify_depts: notifyDepts,
      history: [historyEntry],
    });

    if (res.success) {
      await updateDesignRequest(ecnForm.ecrId!, {
        status: "ECN발행",
        ecn_no: ecnNo,
      });
      await addRequestHistory(ecnForm.ecrId!, {
        step: "ECN발행",
        history_date: ecnDate,
        user_name: ecnForm.designer || "시스템",
        description: `${ecnNo} 발행`,
      });
      toast.success("ECN이 발행되었어요.");
      setIsEcnModalOpen(false);
      fetchData();
    } else {
      toast.error(res.message || "ECN 발행에 실패했어요.");
    }
  };

  // --- ECR Reject ---
  const openRejectModal = (id: string) => {
    setRejectTargetId(id);
    setRejectReason("");
    setIsRejectModalOpen(true);
  };

  const handleRejectSubmit = async () => {
    if (!rejectReason.trim()) {
      toast.error("기각 사유를 입력해 주세요.");
      return;
    }

    const ecr = ecrData.find((r) => r.id === rejectTargetId);
    if (!ecr?._id) {
      toast.error("ECR 정보를 찾을 수 없어요.");
      return;
    }

    const updateRes = await updateDesignRequest(ecr._id, { status: "기각", review_memo: rejectReason });
    if (!updateRes.success) {
      toast.error(updateRes.message || "ECR 기각에 실패했어요.");
      return;
    }
    await addRequestHistory(ecr._id, {
      step: "기각",
      history_date: new Date().toISOString().split("T")[0],
      user_name: "설계팀",
      description: rejectReason,
    });
    toast.success("ECR이 기각되었어요.");
    setIsRejectModalOpen(false);
    fetchData();
  };

  // --- Stat Cards ---
  const ecrStatCards = [
    { label: "요청접수", value: ecrStatusCounts["요청접수"] || 0, color: "text-info" },
    { label: "영향도분석", value: ecrStatusCounts["영향도분석"] || 0, color: "text-warning" },
    { label: "ECN발행", value: ecrStatusCounts["ECN발행"] || 0, color: "text-success" },
  ];

  const ecnStatCards = [
    { label: "도면변경", value: ecnStatusCounts["도면변경"] || 0, color: "text-primary" },
    { label: "통보완료", value: ecnStatusCounts["통보완료"] || 0, color: "text-info" },
    { label: "적용완료", value: ecnStatusCounts["적용완료"] || 0, color: "text-success" },
  ];

  const currentStatCards = currentTab === "ecr" ? ecrStatCards : ecnStatCards;
  const currentList = currentTab === "ecr" ? filteredEcr : filteredEcn;

  const handleRowClick = (id: string) => {
    setSelectedId(id);
    setDetailOpen(true);
  };

  return (
    <div className="flex flex-col h-full gap-3 p-3 relative">
      {loading && (
        <div className="absolute inset-0 bg-background/50 flex items-center justify-center z-50">
          <Loader2 className="h-8 w-8 animate-spin text-primary" />
        </div>
      )}

      {/* 탭 선택 + 검색 필터 */}
      <div className="shrink-0 flex flex-col gap-2">
        <div className="flex items-center gap-3 px-1">
          <Select value={currentTab} onValueChange={(v) => handleTabSwitch(v as TabType)}>
            <SelectTrigger className="w-[170px] h-9">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="ecr">ECR (변경요청)</SelectItem>
              <SelectItem value="ecn">ECN (변경통지)</SelectItem>
            </SelectContent>
          </Select>
        </div>
        {currentTab === "ecr" ? (
          <DynamicSearchFilter
            tableName="dsn_design_request"
            filterId="c16-change-management-ecr"
            onFilterChange={setSearchFilters}
            externalFilterConfig={tsEcr.filterConfig}
            dataCount={filteredEcr.length}
          />
        ) : (
          <DynamicSearchFilter
            tableName="dsn_ecn"
            filterId="c16-change-management-ecn"
            onFilterChange={setSearchFilters}
            externalFilterConfig={tsEcn.filterConfig}
            dataCount={filteredEcn.length}
          />
        )}
      </div>

      {/* 현황 카드 */}
      <div className="grid grid-cols-3 gap-3 shrink-0">
        {currentStatCards.map((card) => (
          <button
            key={card.label}
            onClick={() => handleFilterByStatus(card.label)}
            className="rounded-lg border bg-card px-3 py-2 text-left transition-colors hover:bg-accent/50"
          >
            <div className="text-[10px] text-muted-foreground">{card.label}</div>
            <div className={cn("text-xl font-bold", card.color)}>{card.value}</div>
          </button>
        ))}
      </div>

      {/* 액션 바 */}
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-2">
          <h2 className="text-lg font-semibold">
            {currentTab === "ecr" ? "설계변경요청(ECR) 목록" : "설계변경통지(ECN) 목록"}
          </h2>
          <Badge variant="secondary" className="font-mono">{currentList.length}건</Badge>
        </div>
        <div className="flex items-center gap-2">
          {currentTab === "ecr" && (
            <Button size="sm" onClick={openEcrRegisterModal}>
              <Plus className="w-4 h-4 mr-1.5" /> ECR 등록
            </Button>
          )}
          <Button variant="ghost" size="sm" onClick={() => (currentTab === "ecr" ? tsEcr : tsEcn).setOpen(true)} title="테이블 설정">
            <Settings2 className="h-4 w-4" />
          </Button>
        </div>
      </div>

      {/* 테이블 영역 */}
      <div className="flex-1 flex flex-col overflow-hidden border rounded-lg bg-card">
        <div className="flex-1 overflow-auto">
          {currentTab === "ecr" ? (
            <Table>
              <TableHeader className="sticky top-0 z-10">
                <TableRow className="bg-muted hover:bg-muted">
                  <TableHead className="w-[50px] text-center text-[11px] font-bold uppercase tracking-wide text-muted-foreground">No</TableHead>
                  {tsEcr.visibleColumns.map((col) => (
                    <TableHead
                      key={col.key}
                      className={cn(
                        col.key === "request_no" && "w-[140px]",
                        col.key === "change_type" && "w-[90px] text-center",
                        col.key === "status" && "w-[90px] text-center",
                        col.key === "urgency" && "w-[60px] text-center",
                        col.key === "target_name" && "w-[200px]",
                        col.key === "drawing_no" && "w-[150px]",
                        col.key === "req_dept" && "w-[80px]",
                        col.key === "requester" && "w-[70px]",
                        col.key === "request_date" && "w-[100px]",
                        col.key === "ecn_no" && "w-[130px]",
                      )}
                      style={tsEcr.getWidth(col.key) ? { width: tsEcr.getWidth(col.key) } : undefined}
                    >
                      {col.label}
                    </TableHead>
                  ))}
                </TableRow>
              </TableHeader>
              <TableBody>
                {filteredEcr.length === 0 ? (
                  <TableRow>
                    <TableCell colSpan={tsEcr.visibleColumns.length + 1} className="h-32 text-center text-muted-foreground">
                      <div className="flex flex-col items-center gap-2">
                        <Inbox className="w-8 h-8 text-muted-foreground/50" />
                        <span>조건에 맞는 ECR이 없어요</span>
                      </div>
                    </TableCell>
                  </TableRow>
                ) : (
                  filteredEcr.map((item, idx) => (
                    <TableRow
                      key={item.id}
                      className={cn(
                        "cursor-pointer hover:bg-muted/50 transition-colors",
                        selectedId === item.id && "bg-primary/5"
                      )}
                      onClick={() => handleRowClick(item.id)}
                    >
                      <TableCell className="text-center text-muted-foreground">{idx + 1}</TableCell>
                      {tsEcr.isVisible("request_no") && <TableCell className="font-semibold text-primary">{item.id}</TableCell>}
                      {tsEcr.isVisible("change_type") && (
                      <TableCell className="text-center">
                        <span className={cn("px-2 py-0.5 rounded-full text-[11px] font-medium border", getChangeTypeStyle(item.changeType))}>
                          {item.changeType}
                        </span>
                      </TableCell>
                      )}
                      {tsEcr.isVisible("status") && (
                      <TableCell className="text-center">
                        <span className={cn("px-2 py-0.5 rounded-full text-[11px] font-medium border", getEcrStatusStyle(item.status))}>
                          {item.status}
                        </span>
                      </TableCell>
                      )}
                      {tsEcr.isVisible("urgency") && (
                      <TableCell className="text-center">
                        {item.urgency === "긴급" ? (
                          <span className="px-2 py-0.5 rounded-full text-[11px] font-medium border bg-destructive/10 text-destructive border-destructive/20">
                            긴급
                          </span>
                        ) : (
                          "-"
                        )}
                      </TableCell>
                      )}
                      {tsEcr.isVisible("target_name") && <TableCell className="font-medium">{item.target}</TableCell>}
                      {tsEcr.isVisible("drawing_no") && <TableCell className="text-[13px] text-muted-foreground">{item.drawingNo}</TableCell>}
                      {tsEcr.isVisible("req_dept") && <TableCell>{item.reqDept}</TableCell>}
                      {tsEcr.isVisible("requester") && <TableCell>{item.requester}</TableCell>}
                      {tsEcr.isVisible("request_date") && <TableCell>{item.date}</TableCell>}
                      {tsEcr.isVisible("ecn_no") && (
                      <TableCell>
                        {item.ecnNo ? (
                          <button
                            className="px-2 py-0.5 rounded-full text-[11px] font-semibold bg-info/10 text-info border border-info/20 hover:bg-info/20 transition-colors"
                            onClick={(e) => {
                              e.stopPropagation();
                              navigateToLink(item.ecnNo);
                            }}
                          >
                            {item.ecnNo} <ArrowRight className="w-3 h-3 inline" />
                          </button>
                        ) : (
                          "-"
                        )}
                      </TableCell>
                      )}
                    </TableRow>
                  ))
                )}
              </TableBody>
            </Table>
          ) : (
            <Table>
              <TableHeader className="sticky top-0 z-10">
                <TableRow className="bg-muted hover:bg-muted">
                  <TableHead className="w-[50px] text-center text-[11px] font-bold uppercase tracking-wide text-muted-foreground">No</TableHead>
                  {tsEcn.visibleColumns.map((col) => (
                    <TableHead
                      key={col.key}
                      className={cn(
                        col.key === "ecn_no" && "w-[140px]",
                        col.key === "status" && "w-[90px] text-center",
                        col.key === "target" && "w-[200px]",
                        col.key === "drawing_after" && "w-[160px]",
                        col.key === "designer" && "w-[80px]",
                        col.key === "ecn_date" && "w-[100px]",
                        col.key === "apply_date" && "w-[100px]",
                        col.key === "notify_depts" && "w-[140px]",
                        col.key === "ecr_id" && "w-[130px]",
                      )}
                      style={tsEcn.getWidth(col.key) ? { width: tsEcn.getWidth(col.key) } : undefined}
                    >
                      {col.label}
                    </TableHead>
                  ))}
                </TableRow>
              </TableHeader>
              <TableBody>
                {filteredEcn.length === 0 ? (
                  <TableRow>
                    <TableCell colSpan={tsEcn.visibleColumns.length + 1} className="h-32 text-center text-muted-foreground">
                      <div className="flex flex-col items-center gap-2">
                        <Inbox className="w-8 h-8 text-muted-foreground/50" />
                        <span>조건에 맞는 ECN이 없어요</span>
                      </div>
                    </TableCell>
                  </TableRow>
                ) : (
                  filteredEcn.map((item, idx) => (
                    <TableRow
                      key={item.id}
                      className={cn(
                        "cursor-pointer hover:bg-muted/50 transition-colors",
                        selectedId === item.id && "bg-primary/5"
                      )}
                      onClick={() => handleRowClick(item.id)}
                    >
                      <TableCell className="text-center text-muted-foreground">{idx + 1}</TableCell>
                      {tsEcn.isVisible("ecn_no") && <TableCell className="font-semibold text-primary">{item.id}</TableCell>}
                      {tsEcn.isVisible("status") && (
                      <TableCell className="text-center">
                        <span className={cn("px-2 py-0.5 rounded-full text-[11px] font-medium border", getEcnStatusStyle(item.status))}>
                          {item.status}
                        </span>
                      </TableCell>
                      )}
                      {tsEcn.isVisible("target") && <TableCell className="font-medium">{item.target}</TableCell>}
                      {tsEcn.isVisible("drawing_after") && <TableCell className="text-[13px] text-success font-medium">{item.drawingAfter}</TableCell>}
                      {tsEcn.isVisible("designer") && <TableCell>{item.designer}</TableCell>}
                      {tsEcn.isVisible("ecn_date") && <TableCell>{item.date}</TableCell>}
                      {tsEcn.isVisible("apply_date") && <TableCell>{item.applyDate}</TableCell>}
                      {tsEcn.isVisible("notify_depts") && <TableCell className="text-[13px] text-muted-foreground">{item.notifyDepts.join(", ")}</TableCell>}
                      {tsEcn.isVisible("ecr_id") && (
                      <TableCell>
                        <button
                          className="px-2 py-0.5 rounded-full text-[11px] font-semibold bg-warning/10 text-warning border border-warning/20 hover:bg-warning/20 transition-colors"
                          onClick={(e) => {
                            e.stopPropagation();
                            navigateToLink(item.ecrNo);
                          }}
                        >
                          {item.ecrNo} <ArrowRight className="w-3 h-3 inline" />
                        </button>
                      </TableCell>
                      )}
                    </TableRow>
                  ))
                )}
              </TableBody>
            </Table>
          )}
        </div>
      </div>

      {/* 상세 정보 다이얼로그 */}
      <Dialog open={detailOpen} onOpenChange={setDetailOpen}>
        <DialogContent className="max-w-[900px] w-[95vw] max-h-[90vh] flex flex-col overflow-hidden">
          <DialogHeader>
            <DialogTitle>{currentTab === "ecr" ? `ECR 상세 — ${selectedEcr?.id || ""}` : `ECN 상세 — ${selectedEcn?.id || ""}`}</DialogTitle>
            <DialogDescription>{currentTab === "ecr" ? "설계변경요청의 상세 정보를 확인해요." : "설계변경통지의 상세 정보를 확인해요."}</DialogDescription>
          </DialogHeader>
          <div className="flex-1 overflow-y-auto">
        <div className="space-y-5">
          {/* ECR 상세 */}
          {selectedEcr ? (
            <>
              <section>
                <h3 className="text-sm font-semibold mb-3 flex items-center gap-2 pt-2 border-t">
                  기본 정보
                </h3>
                <div className="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">ECR번호</span>
                    <span className="font-medium text-primary">{selectedEcr.id}</span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">상태</span>
                    <span className={cn("px-2 py-0.5 rounded-full text-[11px] font-medium border inline-block", getEcrStatusStyle(selectedEcr.status))}>
                      {selectedEcr.status}
                    </span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">변경 유형</span>
                    <span className={cn("px-2 py-0.5 rounded-full text-[11px] font-medium border inline-block", getChangeTypeStyle(selectedEcr.changeType))}>
                      {selectedEcr.changeType}
                    </span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">긴급도</span>
                    <span>
                      {selectedEcr.urgency === "긴급" ? (
                        <span className="px-2 py-0.5 rounded-full text-[11px] font-medium border bg-destructive/10 text-destructive border-destructive/20">긴급</span>
                      ) : (
                        "보통"
                      )}
                    </span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">대상 품목/설비</span>
                    <span className="font-medium">{selectedEcr.target}</span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">도면번호</span>
                    <span>{selectedEcr.drawingNo}</span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">요청부서 / 요청자</span>
                    <span>{selectedEcr.reqDept} / {selectedEcr.requester}</span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">요청일자</span>
                    <span>{selectedEcr.date}</span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">희망 적용시점</span>
                    <span>{selectedEcr.applyTiming}</span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">관련 ECN</span>
                    {selectedEcr.ecnNo ? (
                      <button
                        className="px-2 py-0.5 rounded-full text-[11px] font-semibold bg-info/10 text-info border border-info/20 hover:bg-info/20 transition-colors"
                        onClick={() => navigateToLink(selectedEcr.ecnNo)}
                      >
                        {selectedEcr.ecnNo} <ArrowRight className="w-3 h-3 inline" />
                      </button>
                    ) : (
                      <span className="text-muted-foreground">미발행</span>
                    )}
                  </div>
                </div>
              </section>

              <section>
                <h3 className="text-sm font-semibold mb-2">변경 사유</h3>
                <div className="bg-muted/30 p-3 rounded-md border border-border/50 text-sm whitespace-pre-wrap min-h-[50px]">
                  {selectedEcr.reason}
                </div>
              </section>

              <section>
                <h3 className="text-sm font-semibold mb-2">변경 요구 내용</h3>
                <div className="bg-muted/30 p-3 rounded-md border border-border/50 text-sm whitespace-pre-wrap min-h-[50px]">
                  {selectedEcr.content}
                </div>
              </section>

              <section>
                <h3 className="text-sm font-semibold mb-2">영향 범위</h3>
                <div className="flex flex-wrap gap-1.5">
                  {selectedEcr.impact.map((imp) => (
                    <span key={imp} className={cn("px-2 py-0.5 rounded-full text-[11px] font-medium border", getImpactBadgeStyle(imp))}>
                      {imp}
                    </span>
                  ))}
                </div>
              </section>

              <section>
                <h3 className="text-sm font-semibold mb-3">처리 이력</h3>
                <Timeline history={selectedEcr.history} />
              </section>
            </>
          ) : selectedEcn ? (
            <>
              <section>
                <h3 className="text-sm font-semibold mb-3 flex items-center gap-2 pt-2 border-t">
                  ECN 기본 정보
                </h3>
                <div className="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">ECN번호</span>
                    <span className="font-medium text-primary">{selectedEcn.id}</span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">상태</span>
                    <span className={cn("px-2 py-0.5 rounded-full text-[11px] font-medium border inline-block", getEcnStatusStyle(selectedEcn.status))}>
                      {selectedEcn.status}
                    </span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">대상 품목/설비</span>
                    <span className="font-medium">{selectedEcn.target}</span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">설계담당</span>
                    <span>{selectedEcn.designer}</span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">발행일자</span>
                    <span>{selectedEcn.date}</span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">적용일자</span>
                    <span>{selectedEcn.applyDate}</span>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">관련 ECR</span>
                    <button
                      className="px-2 py-0.5 rounded-full text-[11px] font-semibold bg-warning/10 text-warning border border-warning/20 hover:bg-warning/20 transition-colors"
                      onClick={() => navigateToLink(selectedEcn.ecrNo)}
                    >
                      {selectedEcn.ecrNo} <ArrowRight className="w-3 h-3 inline" />
                    </button>
                  </div>
                  <div>
                    <span className="text-muted-foreground text-xs block mb-1">통보 부서</span>
                    <span className="text-xs">{selectedEcn.notifyDepts.join(", ")}</span>
                  </div>
                </div>
              </section>

              <section>
                <h3 className="text-sm font-semibold mb-2">변경 전/후 비교</h3>
                <div className="grid grid-cols-2 gap-3">
                  <div className="bg-destructive/5 p-3 rounded-md border border-destructive/20">
                    <div className="text-xs font-semibold text-destructive mb-1.5">
                      변경 전 ({selectedEcn.drawingBefore})
                    </div>
                    <div className="text-sm whitespace-pre-wrap">{selectedEcn.before}</div>
                  </div>
                  <div className="bg-success/5 p-3 rounded-md border border-success/20">
                    <div className="text-xs font-semibold text-success mb-1.5">
                      변경 후 ({selectedEcn.drawingAfter})
                    </div>
                    <div className="text-sm whitespace-pre-wrap">{selectedEcn.after}</div>
                  </div>
                </div>
              </section>

              <section>
                <h3 className="text-sm font-semibold mb-2">변경 사유</h3>
                <div className="bg-muted/30 p-3 rounded-md border border-border/50 text-sm whitespace-pre-wrap">
                  {selectedEcn.reason}
                </div>
                {selectedEcn.remark && (
                  <p className="text-xs text-muted-foreground mt-2">비고: {selectedEcn.remark}</p>
                )}
              </section>

              <section>
                <h3 className="text-sm font-semibold mb-3">처리 이력</h3>
                <Timeline history={selectedEcn.history} />
              </section>
            </>
          ) : null}
        </div>
          </div>
          <DialogFooter>
            {selectedEcr && (
              <>
                <Button variant="outline" size="sm" onClick={() => { setDetailOpen(false); openEcrEditModal(selectedEcr.id); }}>
                  <Pencil className="w-3.5 h-3.5 mr-1" /> 수정
                </Button>
                {selectedEcr.status === "영향도분석" && (
                  <>
                    <Button size="sm" onClick={() => { setDetailOpen(false); openEcnIssueModal(selectedEcr.id); }}>
                      <FileText className="w-3.5 h-3.5 mr-1" /> ECN 발행
                    </Button>
                    <Button variant="destructive" size="sm" onClick={() => { setDetailOpen(false); openRejectModal(selectedEcr.id); }}>
                      <XCircle className="w-3.5 h-3.5 mr-1" /> 기각
                    </Button>
                  </>
                )}
              </>
            )}
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* ECR 등록/수정 모달 */}
      <Dialog open={isEcrModalOpen} onOpenChange={setIsEcrModalOpen}>
        <DialogContent className="max-w-5xl w-[95vw] max-h-[90vh] flex flex-col overflow-hidden">
          <DialogHeader>
            <DialogTitle>{isEcrEditMode ? "설계변경요청(ECR) 수정" : "설계변경요청(ECR) 등록"}</DialogTitle>
            <DialogDescription>{isEcrEditMode ? "ECR 정보를 수정해요." : "새로운 설계변경요청을 등록해요."}</DialogDescription>
          </DialogHeader>
          <div className="flex-1 overflow-y-auto">
        <div className="flex flex-col md:flex-row gap-5 p-6">
              {/* 좌측: 요청 정보 */}
              <div className="md:w-[380px] shrink-0 space-y-3 bg-muted/30 p-4 rounded-lg border border-border/50">
                <h3 className="text-sm font-semibold pb-2 border-b">변경 요청 정보</h3>

                <div>
                  <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">ECR번호</Label>
                  <Input value={ecrForm.id || ""} readOnly className="h-8 text-xs sm:h-10 sm:text-sm bg-muted cursor-not-allowed" />
                </div>

                <div className="grid grid-cols-2 gap-3">
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">요청일자</Label>
                    <Input
                      type="date"
                      value={ecrForm.date || ""}
                      onChange={(e) => setEcrForm((p) => ({ ...p, date: e.target.value }))}
                      className="h-8 text-xs sm:h-10 sm:text-sm"
                    />
                  </div>
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">희망 적용시점</Label>
                    <Select value={ecrForm.applyTiming || "즉시"} onValueChange={(v) => setEcrForm((p) => ({ ...p, applyTiming: v }))}>
                      <SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="즉시">즉시 적용</SelectItem>
                        <SelectItem value="재고소진후">재고 소진 후</SelectItem>
                        <SelectItem value="특정일자">특정 일자</SelectItem>
                      </SelectContent>
                    </Select>
                  </div>
                </div>

                <div className="grid grid-cols-2 gap-3">
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">변경 유형 <span className="text-destructive">*</span></Label>
                    <Select value={ecrForm.changeType || ""} onValueChange={(v) => setEcrForm((p) => ({ ...p, changeType: v as ChangeType }))}>
                      <SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
                        <SelectValue placeholder="선택" />
                      </SelectTrigger>
                      <SelectContent>
                        {CHANGE_TYPES.map((t) => (
                          <SelectItem key={t} value={t}>{t}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">긴급도</Label>
                    <Select value={ecrForm.urgency || "보통"} onValueChange={(v) => setEcrForm((p) => ({ ...p, urgency: v as "보통" | "긴급" }))}>
                      <SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="보통">보통</SelectItem>
                        <SelectItem value="긴급">긴급</SelectItem>
                      </SelectContent>
                    </Select>
                  </div>
                </div>

                <div>
                  <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">대상 품목/설비 <span className="text-destructive">*</span></Label>
                  <Input
                    value={ecrForm.target || ""}
                    onChange={(e) => setEcrForm((p) => ({ ...p, target: e.target.value }))}
                    placeholder="품목코드 / 설비명"
                    className="h-8 text-xs sm:h-10 sm:text-sm"
                  />
                </div>

                <div>
                  <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">대상 도면번호</Label>
                  <Input
                    value={ecrForm.drawingNo || ""}
                    onChange={(e) => setEcrForm((p) => ({ ...p, drawingNo: e.target.value }))}
                    placeholder="DWG-XXX-XXX"
                    className="h-8 text-xs sm:h-10 sm:text-sm"
                  />
                </div>

                <div className="grid grid-cols-2 gap-3">
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">요청부서</Label>
                    <Select value={ecrForm.reqDept || ""} onValueChange={(v) => setEcrForm((p) => ({ ...p, reqDept: v }))}>
                      <SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
                        <SelectValue placeholder="선택" />
                      </SelectTrigger>
                      <SelectContent>
                        {DEPARTMENTS.map((d) => (
                          <SelectItem key={d} value={d}>{d}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">요청자</Label>
                    <Input
                      value={ecrForm.requester || ""}
                      onChange={(e) => setEcrForm((p) => ({ ...p, requester: e.target.value }))}
                      placeholder="요청자명"
                      className="h-8 text-xs sm:h-10 sm:text-sm"
                    />
                  </div>
                </div>
              </div>

              {/* 우측: 변경 내용 */}
              <div className="flex-1 min-w-0 flex flex-col gap-4">
                <div className="space-y-3 bg-muted/30 p-4 rounded-lg border border-border/50 flex-1">
                  <h3 className="text-sm font-semibold pb-2 border-b">변경 내용</h3>

                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">변경 사유 <span className="text-destructive">*</span></Label>
                    <Textarea
                      value={ecrForm.reason || ""}
                      onChange={(e) => setEcrForm((p) => ({ ...p, reason: e.target.value }))}
                      placeholder="변경이 필요한 구체적인 사유를 기술해 주세요"
                      className="min-h-[80px] resize-y text-xs sm:text-sm"
                    />
                  </div>

                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">변경 요구 내용 <span className="text-destructive">*</span></Label>
                    <Textarea
                      value={ecrForm.content || ""}
                      onChange={(e) => setEcrForm((p) => ({ ...p, content: e.target.value }))}
                      placeholder="어떻게 변경해야 하는지 구체적으로 기술해 주세요"
                      className="min-h-[80px] resize-y text-xs sm:text-sm"
                    />
                  </div>

                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">영향 범위 (해당 항목 체크)</Label>
                    <div className="grid grid-cols-3 gap-2 mt-2">
                      {IMPACT_OPTIONS.map((opt) => (
                        <label
                          key={opt.key}
                          className="flex items-center gap-2 px-3 py-2 bg-background border rounded-md text-xs cursor-pointer hover:bg-muted/50 transition-colors"
                        >
                          <Checkbox
                            checked={!!ecrImpactChecks[opt.key]}
                            onCheckedChange={(c) =>
                              setEcrImpactChecks((prev) => ({ ...prev, [opt.key]: !!c }))
                            }
                          />
                          {opt.label}
                        </label>
                      ))}
                    </div>
                  </div>
                </div>

                <div className="space-y-2 bg-muted/30 p-4 rounded-lg border border-border/50">
                  <h3 className="text-sm font-semibold pb-2 border-b flex items-center gap-2">
                    <Paperclip className="w-3.5 h-3.5" /> 첨부파일
                  </h3>
                  <div className="border-2 border-dashed border-border rounded-md p-4 text-center text-xs text-muted-foreground cursor-pointer hover:border-primary/50 hover:bg-muted/30 transition-colors">
                    <Upload className="w-5 h-5 mx-auto mb-1.5 text-muted-foreground" />
                    클릭하여 파일 첨부 (불량 사진, 참고 도면 등)
                  </div>
                </div>
              </div>
        </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setIsEcrModalOpen(false)}>취소</Button>
            <Button onClick={handleSaveEcr}>
              <Save className="w-4 h-4 mr-1.5" /> 저장
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* ECN 발행 모달 */}
      <Dialog open={isEcnModalOpen} onOpenChange={setIsEcnModalOpen}>
        <DialogContent className="max-w-5xl w-[95vw] max-h-[90vh] flex flex-col overflow-hidden">
          <DialogHeader>
            <DialogTitle>ECN 발행 (설계변경통지)</DialogTitle>
            <DialogDescription>ECR 기반으로 설계변경통지를 발행해요.</DialogDescription>
          </DialogHeader>
          <div className="flex-1 overflow-y-auto">
        <div className="flex flex-col md:flex-row gap-5 p-6">
              {/* 좌측 */}
              <div className="md:w-[380px] shrink-0 space-y-3 bg-muted/30 p-4 rounded-lg border border-border/50">
                <h3 className="text-sm font-semibold pb-2 border-b">ECN 기본 정보</h3>

                <div>
                  <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">ECN번호</Label>
                  <Input value={ecnForm.id || ""} readOnly className="h-8 text-xs sm:h-10 sm:text-sm bg-muted cursor-not-allowed" />
                </div>

                <div>
                  <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">관련 ECR번호</Label>
                  <Input value={ecnForm.ecrNo || ""} readOnly className="h-8 text-xs sm:h-10 sm:text-sm bg-muted cursor-not-allowed" />
                </div>

                <div className="grid grid-cols-2 gap-3">
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">발행일자</Label>
                    <Input
                      type="date"
                      value={ecnForm.date || ""}
                      onChange={(e) => setEcnForm((p) => ({ ...p, date: e.target.value }))}
                      className="h-8 text-xs sm:h-10 sm:text-sm"
                    />
                  </div>
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">적용일자 <span className="text-destructive">*</span></Label>
                    <Input
                      type="date"
                      value={ecnForm.applyDate || ""}
                      onChange={(e) => setEcnForm((p) => ({ ...p, applyDate: e.target.value }))}
                      className="h-8 text-xs sm:h-10 sm:text-sm"
                    />
                  </div>
                </div>

                <div>
                  <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">대상 품목/설비</Label>
                  <Input value={ecnForm.target || ""} readOnly className="h-8 text-xs sm:h-10 sm:text-sm bg-muted cursor-not-allowed" />
                </div>

                <div>
                  <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">도면번호 (변경 후)</Label>
                  <Input
                    value={ecnForm.drawingAfter || ""}
                    onChange={(e) => setEcnForm((p) => ({ ...p, drawingAfter: e.target.value }))}
                    placeholder="변경된 도면번호 (Rev 포함)"
                    className="h-8 text-xs sm:h-10 sm:text-sm"
                  />
                </div>

                <div>
                  <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">설계 담당</Label>
                  <Select value={ecnForm.designer || ""} onValueChange={(v) => setEcnForm((p) => ({ ...p, designer: v }))}>
                    <SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
                      <SelectValue placeholder="선택" />
                    </SelectTrigger>
                    <SelectContent>
                      {DESIGNERS.map((d) => (
                        <SelectItem key={d} value={d}>{d}</SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </div>
              </div>

              {/* 우측 */}
              <div className="flex-1 min-w-0 flex flex-col gap-4">
                <div className="space-y-3 bg-muted/30 p-4 rounded-lg border border-border/50">
                  <h3 className="text-sm font-semibold pb-2 border-b">변경 전/후 비교</h3>
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">변경 전 (AS-IS)</Label>
                    <Textarea
                      value={ecnForm.before || ""}
                      onChange={(e) => setEcnForm((p) => ({ ...p, before: e.target.value }))}
                      placeholder="변경 전 상태/사양/치수 등"
                      className="min-h-[80px] resize-y text-xs sm:text-sm"
                    />
                  </div>
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">변경 후 (TO-BE) <span className="text-destructive">*</span></Label>
                    <Textarea
                      value={ecnForm.after || ""}
                      onChange={(e) => setEcnForm((p) => ({ ...p, after: e.target.value }))}
                      placeholder="변경 후 상태/사양/치수 등"
                      className="min-h-[80px] resize-y text-xs sm:text-sm"
                    />
                  </div>
                </div>

                <div className="space-y-3 bg-muted/30 p-4 rounded-lg border border-border/50">
                  <h3 className="text-sm font-semibold pb-2 border-b">통보 대상 부서</h3>
                  <div className="grid grid-cols-3 gap-2">
                    {NOTIFY_DEPTS.map((dept) => (
                      <label
                        key={dept.key}
                        className="flex items-center gap-2 px-3 py-2 bg-background border rounded-md text-xs cursor-pointer hover:bg-muted/50 transition-colors"
                      >
                        <Checkbox
                          checked={!!ecnNotifyChecks[dept.key]}
                          onCheckedChange={(c) =>
                            setEcnNotifyChecks((prev) => ({ ...prev, [dept.key]: !!c }))
                          }
                        />
                        {dept.label}
                      </label>
                    ))}
                  </div>
                </div>

                <div className="space-y-3 bg-muted/30 p-4 rounded-lg border border-border/50">
                  <h3 className="text-sm font-semibold pb-2 border-b">변경 사유 및 비고</h3>
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">변경 사유 요약</Label>
                    <Textarea
                      value={ecnForm.reason || ""}
                      readOnly
                      className="min-h-[60px] resize-y text-xs sm:text-sm bg-muted cursor-not-allowed"
                    />
                  </div>
                  <div>
                    <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">비고</Label>
                    <Textarea
                      value={ecnForm.remark || ""}
                      onChange={(e) => setEcnForm((p) => ({ ...p, remark: e.target.value }))}
                      placeholder="추가 참고사항"
                      className="min-h-[60px] resize-y text-xs sm:text-sm"
                    />
                  </div>
                </div>
              </div>
        </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setIsEcnModalOpen(false)}>취소</Button>
            <Button onClick={handleSaveEcn}>
              <FileText className="w-4 h-4 mr-1.5" /> ECN 발행
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 기각 모달 */}
      <Dialog open={isRejectModalOpen} onOpenChange={setIsRejectModalOpen}>
        <DialogContent className="max-w-[95vw] sm:max-w-[500px]">
          <DialogHeader>
            <DialogTitle className="text-base sm:text-lg flex items-center gap-2">
              <XCircle className="w-5 h-5 text-destructive" />
              ECR 기각
            </DialogTitle>
            <DialogDescription className="text-xs sm:text-sm">
              {rejectTargetId}을 기각 처리해요.
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-3 sm:space-y-4">
            <div>
              <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">기각 사유 <span className="text-destructive">*</span></Label>
              <Textarea
                value={rejectReason}
                onChange={(e) => setRejectReason(e.target.value)}
                placeholder="기각 사유를 상세히 입력해 주세요"
                className="min-h-[100px] resize-y text-xs sm:text-sm"
              />
            </div>
          </div>

          <DialogFooter className="gap-2 sm:gap-0">
            <Button variant="outline" onClick={() => setIsRejectModalOpen(false)} className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm">
              취소
            </Button>
            <Button variant="destructive" onClick={handleRejectSubmit} className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm">
              <XCircle className="w-4 h-4 mr-2" /> 기각 처리
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <TableSettingsModal
        open={tsEcr.open}
        onOpenChange={tsEcr.setOpen}
        tableName={tsEcr.tableName}
        settingsId={tsEcr.settingsId}
        defaultVisibleKeys={tsEcr.defaultVisibleKeys}
        onSave={tsEcr.applySettings}
      />
      <TableSettingsModal
        open={tsEcn.open}
        onOpenChange={tsEcn.setOpen}
        tableName={tsEcn.tableName}
        settingsId={tsEcn.settingsId}
        defaultVisibleKeys={tsEcn.defaultVisibleKeys}
        onSave={tsEcn.applySettings}
      />
    </div>
  );
}
