"use client";

// ============================================================
// 영업관리 > 견적관리 > 견적작성(장비)
// wace estimateTemplate2.jsp 1:1 이식 (template_type='2')
// 진입: 견적관리 그리드 행 선택 → "견적작성" → "장비 견적서"
// 구조: CNC Machine 특별 영역 + 7개 기본 카테고리 (group1 4개 + 단독 3개) + 비고 + 푸터
// ============================================================

import React, { useEffect, useMemo, useState } from "react";
import { useParams, useSearchParams, useRouter } from "next/navigation";
import { salesEstimateApi } from "@/lib/api/salesEstimate";
import { CustomerSelect, fetchCustomers } from "@/components/common/CustomerSelect";

// ─── 포맷 헬퍼 ────────────────────────────────────────────────
function addComma(num: number | string): string {
  if (num === "" || num == null) return "";
  const n = Number(String(num).replace(/,/g, ""));
  if (Number.isNaN(n)) return "";
  return n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}

// ─── 데이터 타입 ──────────────────────────────────────────────
// CNC Machine 특별 영역 (1개 row)
interface CncRow {
  description: string;
  specification: string;
  quantity: string;
  unit_price: string;  // 입력 시 콤마 포함
  amount: string;      // 자동 계산
  remark: string;
}

// 일반 카테고리 (N개, textarea 묶음 — 여러 줄)
interface CategoryRow {
  category: string;        // data-category 값 (예: 'structure', 'category_8')
  category_name: string;   // 화면 표시명
  category_no: number;
  group: string;           // 'group1' 또는 ''
  description: string;     // 여러 줄
  specification: string;
  quantity: string;
  quantity2: string;
  remark: string;
  subtotal: string;        // 개별 subtotal (group이 아닌 카테고리만)
}

// ─── wace 1:1 기본 데이터 (신규 작성 시 깔리는 7개 카테고리) ──
const DEFAULT_CATEGORIES: CategoryRow[] = [
  {
    category: "structure", category_name: "기구", category_no: 1, group: "group1",
    description: "X,Y,Z LINEAR\nLINEAR SCALE ENCODER\n주물 BODY\nX,Z AXIS COLUMN\nCOVER\nLM GUIDE\nLM GUIDE\nTABLE\nSUS 자바라 X, Y",
    specification: "\n\nMINERAL CASTING\nMINERAL CASTING\nSPCC 도장\nX,Y: SHS25 P급, C1 중예압\nZ: SRG25 P급, C0\n600 * 500\n벨로우즈 멀티 커버",
    quantity: "\n\n3\n1\n1\n1\n4\n2\n1\n4",
    quantity2: "", remark: "", subtotal: "",
  },
  {
    category: "spindle_module", category_name: "초음파 스핀들 모듈", category_no: 2, group: "group1",
    description: "초음파 스핀들 모듈\n제너레이터",
    specification: "AS030-080H2A2.0-U\n15~50kHz, 50W",
    quantity: "1\n1",
    quantity2: "", remark: "", subtotal: "",
  },
  {
    category: "electric", category_name: "전장", category_no: 3, group: "group1",
    description: "C-BOX\nINVERTER\nNC 제어기",
    specification: "Panel & Box, 공용 전기 자재, 냉각장치\nDELTA MS300\nSIEMENS CONTROL PANEL 828D",
    quantity: "1\n1\n1",
    quantity2: "", remark: "", subtotal: "",
  },
  {
    category: "utility", category_name: "UTILITY", category_no: 4, group: "group1",
    description: "공압 PANEL & HOSE\nCHILLER\n절삭유 공급장치\nOIL 자동급유장치\n절삭유 공급 필터",
    specification: "\n\t\t\t\nDSD-010S\n순환장치\nLUBRICATION\n1um 1ea, 10um 1ea",
    quantity: "1\n1\n1\n1\n1",
    quantity2: "", remark: "", subtotal: "",
  },
  {
    category: "option", category_name: "Option", category_no: 5, group: "",
    description: "OMP400\nNC4\nATC",
    specification: "OMP400(Renishaw)\nNV4Blue(Renishaw)\n-",
    quantity: "1\n1\n1",
    quantity2: "", remark: "", subtotal: "",
  },
  {
    category: "setup", category_name: "Set up", category_no: 6, group: "",
    description: "인건비 (기구+제어)\n인건비 (Training)\n기타(항공/숙박/교통/식비)",
    specification: "", quantity: "", quantity2: "", remark: "", subtotal: "",
  },
  {
    category: "packing", category_name: "포장/물류", category_no: 7, group: "",
    description: "포장비\n물류비",
    specification: "", quantity: "", quantity2: "", remark: "", subtotal: "",
  },
];

const DEFAULT_NOTES_HTML = `<strong>■ 최종 견적가는 부가세 별도입니다.</strong><br>■ 장비 납기 : 발주 시 협의<br>■ 운송 조건 : 국내 RPS 에서 진행<br>국외 FOB 기준으로 운송비 / 포장비는 선 당사 부담후 실비 정산<br>■ 결제 조건 : 계약금 : 30% / 중도금 : 60% / 잔금 : 10%<br>-. 계약금 : 발주 후 7일 이내<br>-. 중도금 : 출하 전<br>-. 잔 금 : 설치 완료 후<br>■ 장비사양 : 본견적은 당사 표준 사항<br>사양 협의시 금액 변동성이 있음.<br>■ Warrenty Period: 1년(소모성 parts 제외)<br>■ 주의 : RPS 동의없이 초음파 스핀들의 임의 탈거 또는 해체시 보증 할수 없음.<br><br><div style="display: flex; justify-content: space-between; align-items: center;"><span>* 견적유효기간: 4주</span><span>㈜ 알 피 에 스</span></div>`;

// ─── 페이지 ──────────────────────────────────────────────────
export default function EstimateTemplate2Page() {
  const params = useParams<{ contractObjid: string }>();
  const searchParams = useSearchParams();
  const router = useRouter();

  const contractObjidParam = params?.contractObjid ?? "";
  const templateObjidParam = searchParams?.get("templateObjid") ?? "";

  const [exchangeRate, setExchangeRate] = useState<number>(1);

  // 헤더
  const [executorDate, setExecutorDate] = useState<string>("");
  const executorDateRef = React.useRef<HTMLInputElement>(null);
  const [recipient, setRecipient] = useState<string>("");
  const [partName, setPartName] = useState<string>("");
  const [partObjid, setPartObjid] = useState<string>("");
  const [modelCode, setModelCode] = useState<string>("");

  // CNC Machine 특별 영역
  const [cnc, setCnc] = useState<CncRow>({
    description: "초음파 CNC Machine",
    specification: "Hole 가공",
    quantity: "1",
    unit_price: "",
    amount: "",
    remark: "",
  });

  // 일반 카테고리 배열
  const [categories, setCategories] = useState<CategoryRow[]>(DEFAULT_CATEGORIES);

  // group1 공유 subtotal
  const [group1Subtotal, setGroup1Subtotal] = useState<string>("");

  // 비고/유효기간
  const [notesContent, setNotesContent] = useState<string>(DEFAULT_NOTES_HTML);
  const notesRef = React.useRef<HTMLDivElement>(null);
  const [validityPeriod, setValidityPeriod] = useState<string>("");

  // 상태
  const [contractObjid, setContractObjid] = useState<string>(contractObjidParam);
  const [templateObjid, setTemplateObjid] = useState<string>(templateObjidParam);
  const [loading, setLoading] = useState<boolean>(true);
  const [apprStatus, setApprStatus] = useState<string>("작성중");
  const readOnly = apprStatus === "결재완료" || apprStatus === "결재중";

  // ─── 최종 견적가 계산 ────────────────────────────────────────
  // wace fn_calculateTotal: cnc.amount + group1Subtotal + 단독 subtotal들
  const { totalAmountNum, totalAmountKrwNum, cncAmountNum } = useMemo(() => {
    const cncAmt = parseFloat((cnc.unit_price || "0").replace(/,/g, "")) * parseFloat(cnc.quantity || "0");
    const cncAmtNum = Number.isFinite(cncAmt) ? cncAmt : 0;
    const g1 = parseFloat((group1Subtotal || "0").replace(/,/g, "")) || 0;
    const standalone = categories
      .filter(c => !c.group)
      .reduce((s, c) => s + (parseFloat((c.subtotal || "0").replace(/,/g, "")) || 0), 0);
    const total = cncAmtNum + g1 + standalone;
    return { totalAmountNum: total, totalAmountKrwNum: total * (exchangeRate || 1), cncAmountNum: cncAmtNum };
  }, [cnc.unit_price, cnc.quantity, group1Subtotal, categories, exchangeRate]);

  // CNC amount는 cnc.amount 표시용으로 동기화
  useEffect(() => {
    setCnc(prev => ({ ...prev, amount: cncAmountNum ? addComma(cncAmountNum) : "" }));
  }, [cncAmountNum]);

  // ─── 카테고리 핸들러 ─────────────────────────────────────────
  function updateCategory(idx: number, patch: Partial<CategoryRow>) {
    setCategories(prev => prev.map((c, i) => i === idx ? { ...c, ...patch } : c));
  }

  function addCategory() {
    const visibleCount = categories.length;
    const next = visibleCount + 1;
    setCategories(prev => [...prev, {
      category: `category_${next}`,
      category_name: `카테고리 ${next}`,
      category_no: next,
      group: "",
      description: "", specification: "", quantity: "", quantity2: "", remark: "", subtotal: "",
    }]);
  }

  function deleteCategory(idx: number) {
    if (!confirm("이 카테고리를 삭제하시겠습니까?")) return;
    setCategories(prev => {
      const next = prev.filter((_, i) => i !== idx);
      // 번호 재정렬 (cnc_machine 제외 — 여긴 일반 카테고리만)
      return next.map((c, i) => ({ ...c, category_no: i + 1 }));
    });
  }

  // ─── 데이터 로드 ────────────────────────────────────────────
  useEffect(() => {
    let cancel = false;

    (async () => {
      try {
        // 영업 정보
        let contractInfo: any = null;
        if (contractObjidParam) {
          try {
            contractInfo = await salesEstimateApi.detail(contractObjidParam);
          } catch (e) {
            console.warn("영업정보 로드 실패", e);
          }
        }
        // getById 응답: { ...contract_mgmt 헤더 필드들, items: [...] } (평면 구조)
        if (contractInfo && !cancel) {
          setExchangeRate(parseFloat(contractInfo.exchange_rate || "1") || 1);
          if (contractInfo.customer_objid) setRecipient(contractInfo.customer_objid);
        }
        // 신규: contract_item[0]의 part_name을 품명/Model로
        if (contractInfo?.items?.[0] && !cancel) {
          const it0 = contractInfo.items[0];
          const pName = it0.master_part_name ?? it0.part_name ?? "";
          if (pName) {
            setPartName(pName);
            setModelCode(pName);
            setPartObjid(it0.part_objid ?? "");
          }
          if (it0.quantity) setCnc(prev => ({ ...prev, quantity: String(it0.quantity) }));
        }

        // 기존 견적 차수 수정
        if (templateObjidParam) {
          const tpl = await salesEstimateApi.getTemplate(templateObjidParam);
          if (tpl && !cancel) {
            if (tpl.contract_objid) setContractObjid(tpl.contract_objid);
            setExchangeRate(parseFloat(tpl.exchange_rate || "1") || 1);
            setExecutorDate(tpl.executor_date ?? "");
            if (tpl.recipient) setRecipient(tpl.recipient);
            if (tpl.part_name) {
              setPartName(tpl.part_name);
              setModelCode(tpl.part_name);
            }
            if (tpl.part_objid) setPartObjid(tpl.part_objid);
            if (tpl.notes_content) {
              setNotesContent(tpl.notes_content);
              if (notesRef.current) notesRef.current.innerHTML = tpl.notes_content;
            }
            if (tpl.validity_period) setValidityPeriod(tpl.validity_period);
            if (tpl.group1_subtotal) setGroup1Subtotal(addComma(tpl.group1_subtotal));

            // categories_json 복원
            if (tpl.categories_json) {
              try {
                const arr = JSON.parse(tpl.categories_json) as any[];
                const cncSaved = arr.find(c => c.category === "cnc_machine");
                if (cncSaved?.items?.[0]) {
                  const it = cncSaved.items[0];
                  setCnc({
                    description: it.description ?? "초음파 CNC Machine",
                    specification: it.specification ?? "",
                    quantity: it.quantity ?? "1",
                    unit_price: it.unit_price ? addComma(it.unit_price) : "",
                    amount: it.amount ? addComma(it.amount) : "",
                    remark: it.remark ?? "",
                  });
                }
                const rest: CategoryRow[] = arr
                  .filter(c => c.category !== "cnc_machine")
                  .map((c: any, i: number) => ({
                    category: c.category ?? `category_${i + 1}`,
                    category_name: c.category_name ?? `카테고리 ${i + 1}`,
                    category_no: c.category_no ?? i + 1,
                    group: c.group ?? "",
                    description: c.description ?? "",
                    specification: c.specification ?? "",
                    quantity: c.quantity ?? "",
                    quantity2: c.quantity2 ?? "",
                    remark: c.remark ?? "",
                    subtotal: c.subtotal ? addComma(c.subtotal) : "",
                  }));
                if (rest.length > 0) setCategories(rest);
              } catch (e) {
                console.warn("categories_json 파싱 실패", e);
              }
            }
          }
        }
        // 수신처 CustomerSelect 옵션 미리 로드 — PDF 캡처 selectedLabel 누락 방지
        try { await fetchCustomers(); } catch {}
      } finally {
        if (!cancel) setLoading(false);
      }
    })();

    return () => { cancel = true; };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [contractObjidParam, templateObjidParam]);

  // ─── 저장 (wace fn_save 1:1) ─────────────────────────────────
  async function handleSave() {
    if (!contractObjid && !templateObjid) {
      alert("견적서를 저장할 수 없습니다. 영업정보가 없습니다.");
      return;
    }
    if (!confirm("견적서를 저장하시겠습니까?")) return;

    // categories 배열 구성: CNC Machine + 일반 카테고리
    const cncAmtStr = (cnc.unit_price || "")
      ? String(parseFloat(cnc.unit_price.replace(/,/g, "")) * parseFloat(cnc.quantity || "0") || 0)
      : "";
    const catsBody: any[] = [
      {
        category: "cnc_machine",
        category_name: "초음파 CNC Machine",
        category_no: 0,
        content: "",
        items: [{
          description: cnc.description || "",
          specification: cnc.specification || "",
          quantity: cnc.quantity || "",
          unit_price: (cnc.unit_price || "").replace(/,/g, ""),
          amount: cncAmtStr,
          remark: cnc.remark || "",
        }],
        subtotal: "",
      },
      ...categories.map((c, idx) => ({
        category: c.category,
        category_name: c.category_name,
        category_no: idx + 1,
        group: c.group || "",
        description: c.description || "",
        specification: c.specification || "",
        quantity: c.quantity || "",
        quantity2: c.quantity2 || "",
        remark: c.remark || "",
        subtotal: c.group ? "" : (c.subtotal || "").replace(/,/g, ""),
      })),
    ];

    try {
      const data = await salesEstimateApi.saveTemplate2({
        contract_objid: contractObjid,
        template_objid: templateObjid || undefined,
        executor_date: executorDate,
        recipient,
        part_name: partName,
        part_objid: partObjid,
        notes_content: (notesRef.current?.innerHTML) ?? notesContent,
        validity_period: validityPeriod,
        categories_json: JSON.stringify(catsBody),
        group1_subtotal: (group1Subtotal || "").replace(/,/g, ""),
        total_amount: String(totalAmountNum),
        total_amount_krw: String(totalAmountKrwNum),
      });
      if (data?.templateObjid) setTemplateObjid(data.templateObjid);
      alert("저장되었습니다.");
    } catch (e: any) {
      console.error("저장 오류", e);
      alert("저장에 실패했습니다.\n" + (e?.response?.data?.message ?? e?.message ?? ""));
    }
  }

  function handlePrint() {
    window.print();
  }

  function handleClose() {
    if (window.opener) window.close();
    else router.back();
  }

  // ─── 메일 다이얼로그용 PDF 생성 노출 (template1과 동일 패턴) ─────────────
  // wace estimateMailFormPopup.jsp가 hidden iframe으로 이 페이지를 열고
  // iframe.contentWindow.fn_generateAndUploadPdf(cb)를 호출.
  useEffect(() => {
    if (loading) return;
    if (typeof window === "undefined") return;
    const w = window as any;
    w.dataLoaded = true;
    w.fn_generateAndUploadPdf = async (callback: (pdfBase64: string) => void) => {
      try {
        const html2canvas = (await import("html2canvas-pro")).default;
        const { jsPDF } = await import("jspdf");

        const container = document.querySelector(".estimate-container") as HTMLElement | null;
        if (!container) throw new Error("견적서 컨테이너(.estimate-container)를 찾을 수 없습니다.");

        const canvas = await html2canvas(container, {
          scale: 2,
          useCORS: true,
          logging: false,
          backgroundColor: "#ffffff",
          onclone: (doc) => {
            const replaceWithText = (el: HTMLElement, text: string) => {
              const span = doc.createElement("span");
              span.textContent = text;
              const style = el.getAttribute("style") || "";
              span.setAttribute("style", style + ";display:inline-block;white-space:pre-wrap;");
              el.parentNode?.replaceChild(span, el);
            };
            doc.querySelectorAll<HTMLInputElement>('input[type="text"],input[type="date"]').forEach(el => replaceWithText(el, el.value || ""));
            doc.querySelectorAll<HTMLTextAreaElement>("textarea").forEach(el => replaceWithText(el, el.value || ""));
            doc.querySelectorAll<HTMLSelectElement>("select").forEach(el => {
              const opt = el.options[el.selectedIndex];
              replaceWithText(el as unknown as HTMLElement, opt?.text || "");
            });
            // SmartSelect/CustomerSelect → 선택된 라벨만 텍스트로 (placeholder는 무시)
            doc.querySelectorAll<HTMLElement>('[role="combobox"]').forEach((el) => {
              const idx = Array.from(doc.querySelectorAll('[role="combobox"]')).indexOf(el);
              const live = document.querySelectorAll<HTMLElement>('[role="combobox"]')[idx];
              const liveLabel = live?.querySelector(".truncate")?.textContent?.trim() ?? "";
              const text = /^거래처\s*선택$|^고객사\s*선택$|^선택$/i.test(liveLabel) ? "" : liveLabel;
              replaceWithText(el, text);
            });
            // contenteditable 영역도 보존 (template2의 비고)
            doc.querySelectorAll<HTMLElement>(".no-print, .btn-area, button").forEach(el => { el.style.display = "none"; });
          },
        });

        const imgData = canvas.toDataURL("image/jpeg", 0.85);
        const pdf = new jsPDF("p", "mm", "a4");
        const imgWidth = 210, pageHeight = 297;
        const imgHeight = canvas.height * imgWidth / canvas.width;
        let heightLeft = imgHeight;
        let position = 0;

        pdf.addImage(imgData, "JPEG", 0, position, imgWidth, imgHeight, undefined, "FAST");
        heightLeft -= pageHeight;
        while (heightLeft > 1) {
          position = heightLeft - imgHeight;
          pdf.addPage();
          pdf.addImage(imgData, "JPEG", 0, position, imgWidth, imgHeight, undefined, "FAST");
          heightLeft -= pageHeight;
        }

        callback(pdf.output("datauristring"));
      } catch (e) {
        console.error("fn_generateAndUploadPdf (template2) error", e);
        callback("");
      }
    };
    return () => {
      try {
        w.dataLoaded = false;
        delete w.fn_generateAndUploadPdf;
      } catch {}
    };
  }, [loading]);

  if (loading) return <div style={{ padding: 40 }}>견적서를 불러오는 중...</div>;

  // ─── 렌더링 (wace 마크업 1:1) ────────────────────────────────
  return (
    <div className="estimate2-page">
      <style jsx global>{`
        @media print {
          @page { size: A4; margin: 10mm; }
          body { margin: 0; padding: 0; }
          .no-print { display: none !important; }
          .btn-delete-category { display: none !important; }
        }
        .estimate2-page body, body { font-family: "Malgun Gothic","맑은 고딕",Arial,sans-serif; background-color: #f5f5f5; }
        /* 견적서는 인쇄용 양식 — 다크모드와 무관하게 항상 흰 배경/검정 텍스트 */
        .estimate2-page { color: #000; background-color: #f5f5f5; min-height: 100vh; }
        .estimate2-page .estimate-container, .estimate2-page .estimate-container * { color: #000; }
        .estimate2-page .estimate-container {
          width: 210mm; min-height: 297mm;
          background: white; margin: 0 auto;
          padding: 15mm; box-shadow: 0 0 10px rgba(0,0,0,.1);
          box-sizing: border-box; padding-bottom: 100px;
        }
        .estimate2-page .header-section {
          display: flex; justify-content: space-between;
          align-items: center; margin-bottom: 20px;
        }
        .estimate2-page .title-section { flex: 1; text-align: center; }
        .estimate2-page .title {
          font-size: 24pt; font-weight: bold; letter-spacing: 15px;
        }
        .estimate2-page .model-header {
          background: #f0f0f0; padding: 8px; text-align: center;
          font-size: 11pt; font-weight: bold; margin: 15px 0;
        }
        .estimate2-page .items-table {
          width: 100%; border-collapse: collapse;
          margin-bottom: 8px; font-size: 9pt;
        }
        .estimate2-page .items-table th, .estimate2-page .items-table td {
          border: 1px solid #000; padding: 4px 6px; vertical-align: top;
        }
        .estimate2-page .items-table th { background: #f0f0f0; text-align: center; font-weight: bold; }
        .estimate2-page .category-row td:first-child { text-align: center; font-weight: bold; }
        .estimate2-page .category-row td[contenteditable] {
          background: #fffef0; font-weight: bold; padding: 6px 10px;
        }
        .estimate2-page .subtotal-row td { background: #f5f5f5; font-weight: bold; }
        .estimate2-page input[type="text"], .estimate2-page input[type="date"],
        .estimate2-page textarea, .estimate2-page select {
          border: none; outline: none; background: transparent;
          width: 100%; font-family: inherit; font-size: inherit; box-sizing: border-box;
          color: #000;
        }
        .estimate2-page input[readonly], .estimate2-page textarea[readonly] { color: #000; }
        .estimate2-page textarea { resize: vertical; line-height: 1.6; white-space: pre-wrap; }
        .estimate2-page .estimate-btn-area {
          position: fixed; bottom: 0; left: 0; right: 0;
          text-align: right; padding: 12px 24px;
          background: #fff; border-top: 3px solid #007bff;
          box-shadow: 0 -2px 10px rgba(0,0,0,.1); z-index: 1000;
        }
        .estimate2-page .estimate-btn {
          display: inline-block; padding: 5px 15px; margin: 0 2px;
          font-size: 12px; cursor: pointer; border: 1px solid #60a5fa;
          background: #60a5fa; color: #fff; border-radius: 3px;
        }
        .estimate2-page .estimate-btn:hover { background: #1e3a8a; border-color: #1e3a8a; }
        .estimate2-page .estimate-btn[disabled] { background: #cbd5e1; border-color: #cbd5e1; cursor: not-allowed; }
        .estimate2-page .btn-delete-category {
          padding: 2px 8px; font-size: 10px; cursor: pointer;
          background: #dc3545; color: #fff; border: none; border-radius: 3px;
        }
        .estimate2-page .notes-section { margin-top: 15px; }
        .estimate2-page .notes-section [contenteditable] {
          width: 97%; min-height: 180px; border: 1px solid #ddd;
          padding: 10px; font-size: 9pt; line-height: 1.8; background: white;
        }
      `}</style>

      <div className="estimate-container">
        {/* 헤더 (로고 + 제목 + 회사정보) */}
        <div className="header-section">
          <div style={{ flex: "0 0 120px" }}>
            <div style={{ fontSize: "12pt", fontWeight: "bold", color: "#dc3545" }}>RPS</div>
          </div>
          <div className="title-section">
            <div className="title">견&nbsp;&nbsp;적&nbsp;&nbsp;서</div>
          </div>
          <div style={{ flex: "0 0 200px" }}></div>
        </div>

        {/* 기본 정보 (좌우 배치) */}
        <div style={{ display: "flex", justifyContent: "space-between", padding: "0 10px" }}>
          <div style={{ textAlign: "left", fontSize: "10pt", lineHeight: 2 }}>
            <div>
              <strong>시행일자 :</strong>{" "}
              {/* 표시는 YYYY-MM-DD (text), 클릭 시 숨겨진 type=date의 showPicker 트리거 */}
              <span style={{ position: "relative", display: "inline-block", width: 200 }}>
                <input
                  type="text"
                  value={executorDate}
                  readOnly
                  placeholder="YYYY-MM-DD"
                  onClick={() => { if (!readOnly) executorDateRef.current?.showPicker?.(); }}
                  style={{ width: "100%", borderBottom: "1px solid #999", padding: "2px 5px", cursor: readOnly ? "default" : "pointer" }}
                />
                <input
                  ref={executorDateRef}
                  type="date"
                  value={executorDate}
                  onChange={e => setExecutorDate(e.target.value)}
                  tabIndex={-1}
                  aria-hidden="true"
                  style={{ position: "absolute", left: 0, top: 0, width: 1, height: 1, opacity: 0, pointerEvents: "none" }}
                />
              </span>
            </div>
            <div>
              <strong>수 신 처 :</strong>{" "}
              <span style={{ display: "inline-block", width: 200 }}>
                <CustomerSelect
                  value={recipient}
                  onValueChange={setRecipient}
                  placeholder="고객사 선택"
                  disabled={readOnly}
                />
              </span>
            </div>
            <div>
              <strong>품　　명 :</strong>{" "}
              <input
                type="text"
                value={partName}
                onChange={e => setPartName(e.target.value)}
                readOnly={readOnly}
                style={{ width: 200, borderBottom: "1px solid #999", padding: "2px 5px" }}
              />
            </div>
          </div>
          <div style={{ textAlign: "right" }}>
            <div style={{ display: "inline-block", minWidth: 300 }}>
              <div style={{ fontWeight: "bold", fontSize: "11pt", marginBottom: 5 }}>RPS CO., LTD</div>
              <div style={{ fontSize: "9pt", lineHeight: 1.5 }}>대전광역시 유성구 국제과학로 10로 8</div>
              <div style={{ fontSize: "9pt", lineHeight: 1.5 }}>TEL: (042)602-3300, FAX: (042)672-3399</div>
            </div>
          </div>
        </div>

        {/* 설비 Model */}
        <div className="model-header">
          설비 Model :{" "}
          <input
            type="text"
            value={modelCode}
            onChange={e => setModelCode(e.target.value)}
            readOnly={readOnly}
            style={{ display: "inline-block", minWidth: 200, textAlign: "center", fontWeight: "bold" }}
          />
        </div>

        {/* CNC Machine 특별 영역 */}
        <table className="items-table" data-category="cnc_machine">
          <colgroup>
            <col style={{ width: "5%" }} />
            <col style={{ width: "26%" }} />
            <col style={{ width: "28.5%" }} />
            <col style={{ width: "6.5%" }} />
            <col style={{ width: "12%" }} />
            <col style={{ width: "12%" }} />
            <col style={{ width: "10%" }} />
          </colgroup>
          <thead>
            <tr>
              <th>NO</th>
              <th>DESCRIPTION</th>
              <th>SPECIFICATION</th>
              <th>Q'TY</th>
              <th>UNIT PRICE</th>
              <th>AMOUNT</th>
              <th>REMARK</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td rowSpan={2} style={{ textAlign: "center" }}>1</td>
              <td rowSpan={2}>
                <input
                  type="text" value={cnc.description}
                  onChange={e => setCnc(prev => ({ ...prev, description: e.target.value }))}
                  readOnly={readOnly}
                />
              </td>
              <td>
                <input
                  type="text" value={cnc.specification}
                  onChange={e => setCnc(prev => ({ ...prev, specification: e.target.value }))}
                  readOnly={readOnly}
                  style={{ textAlign: "center" }}
                />
              </td>
              <td>
                <input
                  type="text" value={cnc.quantity}
                  onChange={e => setCnc(prev => ({ ...prev, quantity: e.target.value.replace(/[^0-9]/g, "") }))}
                  readOnly={readOnly}
                  style={{ textAlign: "center" }}
                />
              </td>
              <td>
                <input
                  type="text" value={cnc.unit_price}
                  onChange={e => {
                    const cleaned = e.target.value.replace(/,/g, "").replace(/[^0-9.]/g, "");
                    setCnc(prev => ({ ...prev, unit_price: cleaned === "" ? "" : addComma(cleaned) }));
                  }}
                  readOnly={readOnly}
                  style={{ textAlign: "right" }}
                />
              </td>
              <td>
                <input type="text" value={cnc.amount} readOnly style={{ textAlign: "right" }} />
              </td>
              <td>
                <input
                  type="text" value={cnc.remark}
                  onChange={e => setCnc(prev => ({ ...prev, remark: e.target.value }))}
                  readOnly={readOnly}
                />
              </td>
            </tr>
            <tr className="subtotal-row">
              <td colSpan={2} style={{ textAlign: "center", fontSize: "8pt" }}>최종 견적가</td>
              <td colSpan={2}>
                <input
                  type="text"
                  value={totalAmountNum ? addComma(totalAmountNum) : ""}
                  readOnly
                  style={{ width: "70%", textAlign: "right", fontWeight: "bold" }}
                />
                <span style={{ fontWeight: "bold", marginLeft: 5 }}>{exchangeRate === 1 ? "₩" : ""}</span>
              </td>
              <td style={{ textAlign: "center", fontSize: "8pt" }}>VAT 별도</td>
            </tr>
          </tbody>
        </table>

        {/* 일반 카테고리 N개 */}
        {categories.map((c, idx) => {
          const isGroup1Last = c.group === "group1" &&
            (idx === categories.length - 1 || categories[idx + 1]?.group !== "group1");
          return (
            <React.Fragment key={`${c.category}_${idx}`}>
              <table className="items-table" data-category={c.category} data-group={c.group}>
                <colgroup>
                  <col style={{ width: "5%" }} />
                  <col style={{ width: "26%" }} />
                  <col style={{ width: "28.5%" }} />
                  <col style={{ width: "6.5%" }} />
                  <col style={{ width: "24%" }} />
                  <col style={{ width: "10%" }} />
                </colgroup>
                <tbody>
                  <tr className="category-row">
                    <td rowSpan={2} style={{ textAlign: "center" }}>{idx + 1}</td>
                    <td
                      colSpan={4}
                      contentEditable={!readOnly}
                      suppressContentEditableWarning
                      onBlur={e => updateCategory(idx, { category_name: e.currentTarget.textContent ?? "" })}
                    >{c.category_name}</td>
                    <td style={{ textAlign: "center" }}>
                      {!readOnly && (
                        <button type="button" className="btn-delete-category" onClick={() => deleteCategory(idx)}>삭제</button>
                      )}
                    </td>
                  </tr>
                  <tr className="detail-row">
                    <td>
                      <textarea
                        value={c.description}
                        onChange={e => updateCategory(idx, { description: e.target.value })}
                        readOnly={readOnly}
                        rows={5}
                      />
                    </td>
                    <td>
                      <textarea
                        value={c.specification}
                        onChange={e => updateCategory(idx, { specification: e.target.value })}
                        readOnly={readOnly}
                        rows={5}
                      />
                    </td>
                    <td>
                      <textarea
                        value={c.quantity}
                        onChange={e => updateCategory(idx, { quantity: e.target.value })}
                        readOnly={readOnly}
                        rows={5}
                        style={{ textAlign: "right" }}
                      />
                    </td>
                    <td>
                      <textarea
                        value={c.quantity2}
                        onChange={e => updateCategory(idx, { quantity2: e.target.value })}
                        readOnly={readOnly}
                        rows={5}
                      />
                    </td>
                    <td>
                      <textarea
                        value={c.remark}
                        onChange={e => updateCategory(idx, { remark: e.target.value })}
                        readOnly={readOnly}
                        rows={5}
                      />
                    </td>
                  </tr>
                  {/* 단독 카테고리는 개별 Subtotal */}
                  {!c.group && (
                    <tr className="subtotal-row">
                      <td colSpan={4}>Subtotal</td>
                      <td>
                        <input
                          type="text" value={c.subtotal}
                          onChange={e => {
                            const cleaned = e.target.value.replace(/,/g, "").replace(/[^0-9.]/g, "");
                            updateCategory(idx, { subtotal: cleaned === "" ? "" : addComma(cleaned) });
                          }}
                          readOnly={readOnly}
                          style={{ textAlign: "right" }}
                        />
                      </td>
                      <td></td>
                    </tr>
                  )}
                </tbody>
              </table>
              {/* group1 마지막 카테고리 뒤 공유 Subtotal */}
              {isGroup1Last && (
                <table className="items-table" id="group1_subtotal">
                  <colgroup>
                    <col style={{ width: "5%" }} />
                    <col style={{ width: "26%" }} />
                    <col style={{ width: "28.5%" }} />
                    <col style={{ width: "6.5%" }} />
                    <col style={{ width: "24%" }} />
                    <col style={{ width: "10%" }} />
                  </colgroup>
                  <tbody>
                    <tr className="subtotal-row">
                      <td colSpan={4}>Subtotal</td>
                      <td>
                        <input
                          type="text" value={group1Subtotal}
                          onChange={e => {
                            const cleaned = e.target.value.replace(/,/g, "").replace(/[^0-9.]/g, "");
                            setGroup1Subtotal(cleaned === "" ? "" : addComma(cleaned));
                          }}
                          readOnly={readOnly}
                          style={{ textAlign: "right" }}
                        />
                      </td>
                      <td></td>
                    </tr>
                  </tbody>
                </table>
              )}
            </React.Fragment>
          );
        })}

        {/* 비고 (contenteditable HTML) */}
        <div className="notes-section">
          <div
            ref={notesRef}
            contentEditable={!readOnly}
            suppressContentEditableWarning
            dangerouslySetInnerHTML={{ __html: notesContent }}
            onBlur={e => setNotesContent(e.currentTarget.innerHTML)}
          />
        </div>

        {/* 푸터 — 대외비 */}
        <div style={{ textAlign: "right", fontSize: "7pt", color: "#999", marginTop: 5 }}>
          * RPS 대외비 - 본자료는 RPS의 사전허가 없이 제3자에게 제공할 수 없음을 알려드립니다.
        </div>
      </div>

      {/* 버튼 영역 */}
      <div className="estimate-btn-area no-print">
        <button type="button" className="estimate-btn" onClick={addCategory} disabled={readOnly}>+ 카테고리 추가</button>
        <button type="button" className="estimate-btn" onClick={handlePrint}>인쇄</button>
        <button type="button" className="estimate-btn" onClick={handleSave} disabled={readOnly}>저장</button>
        <button type="button" className="estimate-btn" onClick={handleClose}>닫기</button>
      </div>
    </div>
  );
}
