"use client";

import { useEffect, useMemo, useState, useCallback, useRef } from "react";
import { Check, Download, X, RefreshCcw, Truck, AlertCircle, Package } from "lucide-react";
import Swal from "sweetalert2";
import { captureAndShare } from "@/lib/capture-share";

interface Order {
  OBJID: string; ORDER_NO: string; ORDER_DATE: string;
  COMPANY_NAME: string; EMAIL: string; STATUS: string;
  TOTAL_TAXFREE: number; TOTAL_TAXABLE: number;
  TOTAL_SUPPLY: number; TOTAL_VAT: number; TOTAL_AMOUNT: number;
}
interface DetailOrder extends Order {
  CEO_NAME?: string; BIZ_NO?: string; PHONE?: string; ADDRESS?: string;
  MEMO?: string; APPROVE_DATE?: string;
}
interface DetailLine {
  OBJID: string;
  SEQ: number; ITEM_NAME: string; UNIT: string; UNIT_PRICE: number; QTY: number;
  IS_TAX_FREE: string; SUPPLY_AMOUNT: number; VAT_AMOUNT: number; TOTAL_AMOUNT: number;
  STOCK_QTY: number;
  KIND: "ITEM" | "DELIVERY" | "CHARTER";
  EXTRA_LABEL?: string;
  REMARK?: string;
}
interface Supplier {
  NAME: string; CEO: string; BIZ_NO: string;
  BANK_ACCOUNT: string; PHONE: string; EMAIL: string; ADDRESS: string;
}

const fmt = (n: number | string | undefined | null) =>
  Number(n || 0).toLocaleString("ko-KR");

const STATUS_LABEL: Record<string, string> = {
  REQUESTED: "출고요청",
  APPROVED: "출고완료",
  PAID: "입금완료",
  INVOICED: "계산서발행",
  CANCELLED: "취소",
};
const STATUS_COLOR: Record<string, string> = {
  REQUESTED: "bg-amber-100 text-amber-700 border-amber-200",
  APPROVED: "bg-blue-100 text-blue-700 border-blue-200",
  PAID: "bg-emerald-100 text-emerald-700 border-emerald-200",
  INVOICED: "bg-violet-100 text-violet-700 border-violet-200",
  CANCELLED: "bg-slate-100 text-slate-500 border-slate-200",
};

const todayStr = () => {
  const d = new Date();
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
};

export default function AdminOrdersPage() {
  const [orders, setOrders] = useState<Order[]>([]);
  // URL 쿼리 우선: dateFrom/dateTo 키가 있으면 그 값 사용 (빈 문자열도 명시적 = 전체 기간).
  // 키가 없을 때만 기본값(오늘 ~ 오늘)
  const initial = (() => {
    if (typeof window === "undefined") return { status: "", dateFrom: todayStr(), dateTo: todayStr(), keyword: "" };
    const q = new URLSearchParams(window.location.search);
    return {
      status: q.get("status") ?? "",
      dateFrom: q.has("dateFrom") ? (q.get("dateFrom") ?? "") : todayStr(),
      dateTo: q.has("dateTo") ? (q.get("dateTo") ?? "") : todayStr(),
      keyword: q.get("keyword") ?? "",
    };
  })();
  const [status, setStatus] = useState(initial.status);
  const [dateFrom, setDateFrom] = useState(initial.dateFrom);
  const [dateTo, setDateTo] = useState(initial.dateTo);
  const [keyword, setKeyword] = useState(initial.keyword);
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [activeId, setActiveId] = useState<string>("");
  const [detail, setDetail] = useState<{ order: DetailOrder; items: DetailLine[]; supplier: Supplier } | null>(null);
  const [loading, setLoading] = useState(false);
  const [busy, setBusy] = useState(false);

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const res = await fetch("/api/m/orders/list", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          status: status || undefined,
          dateFrom: dateFrom || undefined,
          dateTo: dateTo || undefined,
          keyword: keyword || undefined,
        }),
      });
      const j = await res.json();
      const list: Order[] = j.RESULTLIST ?? [];
      setOrders(list);
      setSelected((prev) => new Set(Array.from(prev).filter((id) => list.some((o) => o.OBJID === id))));
      if (list.length && !list.some((o) => o.OBJID === activeId)) {
        setActiveId(list[0].OBJID);
      } else if (!list.length) {
        setActiveId("");
        setDetail(null);
      }
    } finally {
      setLoading(false);
    }
  }, [status, dateFrom, dateTo, keyword, activeId]);

  // 최초 로드만 자동, 검색 조건 변경은 [조회] 버튼으로
  // eslint-disable-next-line react-hooks/exhaustive-deps
  useEffect(() => { load(); }, []);

  const reloadDetail = useCallback(async () => {
    if (!activeId) { setDetail(null); return; }
    const res = await fetch("/api/m/orders/detail", {
      method: "POST", headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ objid: activeId }),
    });
    const j = await res.json();
    if (j.success) {
      setDetail({ order: j.order as DetailOrder, items: j.items as DetailLine[], supplier: j.supplier as Supplier });
    }
  }, [activeId]);

  // 활성 행 변경 시 상세 로드
  useEffect(() => {
    let cancelled = false;
    (async () => {
      if (!activeId) { setDetail(null); return; }
      const res = await fetch("/api/m/orders/detail", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ objid: activeId }),
      });
      const j = await res.json();
      if (!cancelled && j.success) {
        setDetail({ order: j.order as DetailOrder, items: j.items as DetailLine[], supplier: j.supplier as Supplier });
      }
    })();
    return () => { cancelled = true; };
  }, [activeId]);

  const requestedSelectedIds = useMemo(
    () => Array.from(selected).filter((id) => orders.find((o) => o.OBJID === id)?.STATUS === "REQUESTED"),
    [selected, orders]
  );

  const toggleOne = (o: Order) => {
    if (o.STATUS !== "REQUESTED") return;
    setSelected((prev) => {
      const next = new Set(prev);
      if (next.has(o.OBJID)) next.delete(o.OBJID); else next.add(o.OBJID);
      return next;
    });
  };
  const toggleAllRequested = () => {
    const reqIds = orders.filter((o) => o.STATUS === "REQUESTED").map((o) => o.OBJID);
    setSelected((prev) => {
      const allOn = reqIds.length > 0 && reqIds.every((id) => prev.has(id));
      const next = new Set(prev);
      if (allOn) reqIds.forEach((id) => next.delete(id));
      else reqIds.forEach((id) => next.add(id));
      return next;
    });
  };

  const bulkShip = async () => {
    const ids = requestedSelectedIds;
    if (ids.length === 0) {
      Swal.fire({ icon: "warning", title: "출고 처리할 발주를 선택하세요.", text: "체크박스로 출고요청 상태의 발주를 선택해주세요." });
      return;
    }
    const ok = await Swal.fire({
      icon: "question",
      title: `${ids.length}건 출고 처리하시겠습니까?`,
      html: `선택된 발주의 재고가 차감되고,<br>각 거래처 이메일로 거래명세표가 발송됩니다.`,
      showCancelButton: true,
      confirmButtonText: "출고",
      cancelButtonText: "취소",
      confirmButtonColor: "#0f766e",
    });
    if (!ok.isConfirmed) return;

    setBusy(true);
    let ok_cnt = 0;
    let fail_cnt = 0;
    let mailFail = 0;
    const errors: string[] = [];
    for (const objid of ids) {
      try {
        const res = await fetch("/api/m/orders/approve", {
          method: "POST", headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ objid }),
        });
        const j = await res.json();
        if (j.success) {
          ok_cnt++;
          if (!j.mailSent) mailFail++;
        } else {
          fail_cnt++;
          const o = orders.find((x) => x.OBJID === objid);
          errors.push(`${o?.ORDER_NO ?? objid}: ${j.message ?? "실패"}`);
        }
      } catch {
        fail_cnt++;
      }
    }
    setBusy(false);
    setSelected(new Set());
    await load();

    Swal.fire({
      icon: fail_cnt === 0 ? "success" : "warning",
      title: `출고 처리 완료 (성공 ${ok_cnt} / 실패 ${fail_cnt})`,
      html: [
        ok_cnt > 0 ? `· 거래명세표 메일 ${ok_cnt - mailFail}건 발송${mailFail > 0 ? ` <span style="color:#dc2626">(${mailFail}건 메일 실패)</span>` : ""}` : "",
        errors.length > 0 ? `<br><br><b>실패 내역:</b><br>${errors.join("<br>")}` : "",
      ].filter(Boolean).join(""),
    });
  };

  const cancelOne = async (o: Order) => {
    const ok = await Swal.fire({
      icon: "warning", title: "발주를 취소(반려)하시겠습니까?",
      text: o.ORDER_NO, showCancelButton: true, confirmButtonColor: "#dc2626",
    });
    if (!ok.isConfirmed) return;
    const res = await fetch("/api/m/orders/cancel", {
      method: "POST", headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ objid: o.OBJID }),
    });
    if ((await res.json()).success) load();
  };

  const allRequestedCount = orders.filter((o) => o.STATUS === "REQUESTED").length;
  const allRequestedChecked = allRequestedCount > 0 && allRequestedCount === requestedSelectedIds.length;

  return (
    <div className="space-y-3">
      {/* 헤더 */}
      <div className="flex items-end justify-between flex-wrap gap-2">
        <div>
          <h1 className="text-xl font-bold text-slate-900">출고 처리</h1>
          <p className="text-xs text-slate-500 mt-0.5">
            발주를 선택하면 거래명세표가 미리보기로 표시됩니다. 체크박스로 다중 선택 후 [출고]를 누르면 일괄 처리됩니다.
          </p>
        </div>
        <button
          onClick={bulkShip}
          disabled={busy || requestedSelectedIds.length === 0}
          className="h-9 px-4 rounded-lg bg-emerald-700 text-white text-sm font-bold hover:bg-emerald-800 disabled:opacity-40 disabled:cursor-not-allowed inline-flex items-center gap-1.5 shadow-sm"
        >
          <Truck size={14} /> 출고{requestedSelectedIds.length > 0 ? ` (${requestedSelectedIds.length})` : ""}
        </button>
      </div>

      {/* 검색바 — 모바일에선 한 줄에 핵심만, 데스크탑에선 여유 있게 */}
      <div className="bg-white border border-slate-200 rounded-xl p-2 sm:p-3">
        <div className="flex flex-wrap gap-1.5 sm:gap-2 items-center text-xs">
          <input type="date" value={dateFrom} onChange={(e) => setDateFrom(e.target.value)}
            className="h-8 sm:h-9 px-2 rounded border border-slate-200 text-xs sm:text-sm min-w-0 flex-1 sm:flex-none sm:w-[140px]" />
          <span className="text-slate-400 text-[10px] sm:text-xs">~</span>
          <input type="date" value={dateTo} onChange={(e) => setDateTo(e.target.value)}
            className="h-8 sm:h-9 px-2 rounded border border-slate-200 text-xs sm:text-sm min-w-0 flex-1 sm:flex-none sm:w-[140px]" />
          <select value={status} onChange={(e) => setStatus(e.target.value)}
            className="h-8 sm:h-9 px-2 rounded border border-slate-200 text-xs sm:text-sm bg-white sm:w-[140px]">
            <option value="">전체 상태</option>
            {Object.entries(STATUS_LABEL).map(([k, v]) => <option key={k} value={k}>{v}</option>)}
          </select>
          <input type="text" value={keyword} onChange={(e) => setKeyword(e.target.value)}
            onKeyDown={(e) => { if (e.key === "Enter") load(); }}
            placeholder="발주번호 / 업체"
            className="h-8 sm:h-9 px-2 rounded border border-slate-200 text-xs sm:text-sm flex-1 min-w-[120px]" />
          <button onClick={load} disabled={loading}
            className="h-8 sm:h-9 px-3 rounded bg-slate-800 text-white text-xs sm:text-sm font-bold hover:bg-slate-900 disabled:opacity-50">
            조회
          </button>
          {(dateFrom !== todayStr() || dateTo !== todayStr() || status || keyword) && (
            <button onClick={() => { setDateFrom(todayStr()); setDateTo(todayStr()); setStatus(""); setKeyword(""); }}
              className="h-8 sm:h-9 px-2 rounded border border-slate-200 bg-white text-slate-600 text-[11px]">
              초기화
            </button>
          )}
        </div>
      </div>

      {/* 2분할 레이아웃 — 모바일은 stack, lg 이상은 좌-우 분할 */}
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-3 lg:min-h-[calc(100vh-200px)]">
        {/* 좌측: 발주 리스트 */}
        <div className="bg-white border border-slate-200 rounded-xl overflow-hidden flex flex-col">
          <div className="px-3 py-2 bg-slate-50 border-b border-slate-200 text-xs font-semibold text-slate-600 flex items-center justify-between">
            <span>발주 리스트 ({orders.length}건)</span>
            <span className="text-slate-400 font-normal">선택 {selected.size}건 / 출고가능 {allRequestedCount}건</span>
          </div>
          <div className="flex-1 lg:overflow-auto max-h-[60vh] lg:max-h-none overflow-x-auto">
            <table className="w-full text-xs min-w-[520px]">
              <thead className="bg-slate-50 text-slate-600 sticky top-0 z-10">
                <tr>
                  <th className="w-8 px-2 py-2">
                    <input type="checkbox" checked={allRequestedChecked} onChange={toggleAllRequested}
                      disabled={allRequestedCount === 0}
                      className="accent-emerald-600 cursor-pointer disabled:opacity-30" />
                  </th>
                  <th className="text-left px-2 py-2">발주번호</th>
                  <th className="text-left px-2 py-2">발주일</th>
                  <th className="text-left px-2 py-2">업체</th>
                  <th className="text-right px-2 py-2">합계</th>
                  <th className="text-center px-2 py-2">상태</th>
                </tr>
              </thead>
              <tbody>
                {orders.length === 0 ? (
                  <tr><td colSpan={6} className="text-center py-12 text-slate-400">{loading ? "조회 중..." : "발주가 없습니다."}</td></tr>
                ) : orders.map((o) => {
                  const checked = selected.has(o.OBJID);
                  const active = o.OBJID === activeId;
                  return (
                    <tr
                      key={o.OBJID}
                      onClick={() => setActiveId(o.OBJID)}
                      className={`border-t border-slate-100 cursor-pointer ${active ? "bg-emerald-50/60" : "hover:bg-slate-50"}`}
                    >
                      <td className="px-2 py-2 text-center" onClick={(e) => e.stopPropagation()}>
                        <input
                          type="checkbox"
                          checked={checked}
                          onChange={() => toggleOne(o)}
                          disabled={o.STATUS !== "REQUESTED"}
                          className="accent-emerald-600 cursor-pointer disabled:opacity-30 disabled:cursor-not-allowed"
                          title={o.STATUS !== "REQUESTED" ? "출고요청 상태만 선택할 수 있습니다." : ""}
                        />
                      </td>
                      <td className="px-2 py-2 font-semibold text-slate-800">{o.ORDER_NO}</td>
                      <td className="px-2 py-2 text-slate-600">{o.ORDER_DATE}</td>
                      <td className="px-2 py-2 truncate max-w-[140px]" title={o.COMPANY_NAME}>{o.COMPANY_NAME}</td>
                      <td className="px-2 py-2 text-right tabular-nums font-semibold">₩{fmt(o.TOTAL_AMOUNT)}</td>
                      <td className="px-2 py-2 text-center">
                        <span className={`inline-block px-1.5 py-0.5 rounded text-[10px] font-semibold border ${STATUS_COLOR[o.STATUS] ?? "bg-slate-100 text-slate-500 border-slate-200"}`}>
                          {STATUS_LABEL[o.STATUS] ?? o.STATUS}
                        </span>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>

        {/* 우측: 거래명세표 미리보기 */}
        <div className="bg-white border border-slate-200 rounded-xl overflow-hidden flex flex-col">
          <div className="px-3 py-2 bg-slate-50 border-b border-slate-200 text-xs font-semibold text-slate-600">
            거래명세표 미리보기
          </div>
          <div className="flex-1 lg:overflow-auto p-4">
            {!detail ? (
              <div className="h-full flex flex-col items-center justify-center text-slate-400">
                <Package size={48} className="mb-3 opacity-50" />
                <div className="text-sm">왼쪽에서 발주를 선택하세요.</div>
              </div>
            ) : (
              <StatementPreview order={detail.order} items={detail.items} supplier={detail.supplier} onCancel={cancelOne} busy={busy} onReload={reloadDetail} onReloadList={load} />
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

function StatementPreview({
  order,
  items,
  supplier,
  onCancel,
  busy,
  onReload,
  onReloadList,
}: {
  order: DetailOrder;
  items: DetailLine[];
  supplier: Supplier;
  onCancel: (o: Order) => void;
  busy: boolean;
  onReload: () => void;
  onReloadList: () => void;
}) {
  const [shipping, setShipping] = useState(false);

  const shipNow = async () => {
    const lack = items.filter((it) => it.KIND === "ITEM" && Number(it.STOCK_QTY) < Number(it.QTY));
    if (lack.length > 0) {
      const ok = await Swal.fire({
        icon: "warning",
        title: "재고 부족 항목이 있습니다.",
        html: `<div class="text-left text-sm">${lack.map((it) => `· ${it.ITEM_NAME} (요청 ${fmt(it.QTY)} / 현재고 ${fmt(it.STOCK_QTY)})`).join("<br>")}</div><br>그래도 출고를 시도하시겠습니까?`,
        showCancelButton: true,
        confirmButtonText: "출고 시도",
        cancelButtonText: "취소",
        confirmButtonColor: "#0f766e",
      });
      if (!ok.isConfirmed) return;
    } else {
      const ok = await Swal.fire({
        icon: "question",
        title: "출고 처리하시겠습니까?",
        html: `발주 <b>${order.ORDER_NO}</b><br>거래처: ${order.COMPANY_NAME}<br>합계: ₩${fmt(order.TOTAL_AMOUNT)}<br><br>재고가 차감되고, 거래명세표가 메일로 발송됩니다.`,
        showCancelButton: true,
        confirmButtonText: "출고",
        cancelButtonText: "취소",
        confirmButtonColor: "#0f766e",
      });
      if (!ok.isConfirmed) return;
    }
    setShipping(true);
    try {
      const res = await fetch("/api/m/orders/approve", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ objid: order.OBJID }),
      });
      const j = await res.json();
      if (j.success) {
        await Swal.fire({
          icon: "success",
          title: "출고 완료",
          html: j.mailSent ? "거래명세표 메일이 발송되었습니다." : `<span class="text-rose-600">메일 발송에 실패했습니다.</span>`,
          timer: 1800,
          showConfirmButton: false,
        });
        onReloadList();
        onReload();
      } else {
        Swal.fire({ icon: "error", title: "출고 실패", text: j.message ?? "오류" });
      }
    } finally {
      setShipping(false);
    }
  };

  const statementRef = useRef<HTMLDivElement>(null);
  const lowStock = items.filter((it) => it.KIND === "ITEM" && Number(it.STOCK_QTY) < Number(it.QTY));
  // 입금완료(PAID)/취소(CANCELED) 전까지는 거래명세표 수정 가능 (관리자 화면이므로 항상 admin).
  // 사용자가 수량 변경 요청하면 담당자가 여기서 수정 → 재고/총액 자동 갱신 → 사용자 측 화면에도 그대로 반영됨.
  const editable = order.STATUS !== "PAID" && order.STATUS !== "CANCELED";

  // 거래명세표를 이미지로 캡처 → 공유 또는 다운로드
  const handleCapture = async () => {
    if (!statementRef.current) return;
    await captureAndShare({
      node: statementRef.current,
      filename: `${order.ORDER_NO}_거래명세표`,
      shareTitle: `${order.ORDER_NO} 거래명세표`,
      shareText: order.COMPANY_NAME,
      forceWidth: 1100, // 엑셀 가로 출력처럼 펼쳐서 캡처
    });
  };

  // 비고 저장
  const saveRemark = async (lineObjid: string, remark: string) => {
    const res = await fetch("/api/m/orders/items/remark", {
      method: "POST", headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ lineObjid, remark }),
    });
    const j = await res.json();
    if (j.success) onReload();
    else Swal.fire({ icon: "error", title: "비고 저장 실패", text: j.message });
  };

  const upsertExtra = async (line: { objid?: string; kind: "DELIVERY" | "CHARTER"; label: string; unitPrice: number; qty: number }) => {
    const res = await fetch("/api/m/orders/lines/save", {
      method: "POST", headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ orderObjid: order.OBJID, lines: [line] }),
    });
    const j = await res.json();
    if (j.success) onReload();
    else Swal.fire({ icon: "error", title: "저장 실패", text: j.message });
  };
  const deleteExtra = async (objid: string) => {
    const ok = await Swal.fire({ icon: "question", title: "라인을 삭제하시겠습니까?", showCancelButton: true });
    if (!ok.isConfirmed) return;
    const res = await fetch("/api/m/orders/lines/save", {
      method: "POST", headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ orderObjid: order.OBJID, lines: [{ objid, kind: "CHARTER", unitPrice: 0, qty: 1, delete: true }] }),
    });
    const j = await res.json();
    if (j.success) onReload();
    else Swal.fire({ icon: "error", title: "삭제 실패", text: j.message });
  };
  const addNewExtra = (kind: "DELIVERY" | "CHARTER") => {
    // 같은 종류 라인이 이미 있으면 새로 만들지 않고 수량 +1
    const existing = items.find((it) => it.KIND === kind);
    if (existing) {
      upsertExtra({
        objid: existing.OBJID,
        kind,
        label: existing.EXTRA_LABEL || existing.ITEM_NAME,
        unitPrice: Number(existing.UNIT_PRICE),
        qty: Number(existing.QTY) + 1,
      });
      return;
    }
    const defaults = kind === "DELIVERY"
      ? { unitPrice: 4000, qty: 1, label: "택배비" }
      : { unitPrice: 5000, qty: 1, label: "용차" };
    upsertExtra({ kind, ...defaults });
  };
  return (
    <div className="text-[12px] text-slate-800 space-y-3">
      {/* 공유/캡처/엑셀/출고 버튼 — 캡처 영역 밖에 배치 */}
      <div className="flex justify-end gap-2 print:hidden flex-wrap">
        <button
          type="button"
          onClick={handleCapture}
          className="inline-flex items-center gap-1 h-8 px-3 rounded-lg bg-amber-100 text-amber-800 text-xs font-bold hover:bg-amber-200"
          title="이미지로 캡처해 카톡 등에 공유"
        >
          📤 이미지 공유
        </button>
        <button
          type="button"
          onClick={() => window.print()}
          className="inline-flex items-center gap-1 h-8 px-3 rounded-lg bg-slate-100 text-slate-700 text-xs font-bold hover:bg-slate-200"
          title="인쇄"
        >
          🖨 인쇄
        </button>
        <a
          href={`/api/m/orders/statement/${order.OBJID}`}
          className="inline-flex items-center gap-1 h-8 px-3 rounded-lg bg-emerald-100 text-emerald-800 text-xs font-bold hover:bg-emerald-200"
          title="거래명세표 엑셀 다운로드"
        >
          <Download size={12} /> 엑셀 다운로드
        </a>
        {editable && (
          <button
            type="button"
            onClick={shipNow}
            disabled={shipping || busy}
            className="inline-flex items-center gap-1 h-8 px-3 rounded-lg bg-emerald-700 text-white text-xs font-bold hover:bg-emerald-800 disabled:opacity-50 disabled:cursor-not-allowed"
            title="이 발주를 바로 출고 처리"
          >
            <Truck size={12} /> {shipping ? "출고 중..." : "출고"}
          </button>
        )}
      </div>

      <div ref={statementRef} className="bg-white p-3">
      <div className="text-center">
        <h2 className="text-2xl font-bold tracking-[0.3em] text-slate-900">거 래 명 세 표</h2>
      </div>

      {/* 좌: 발주 정보 / 우: 공급자 정보 박스 — 항상 가로 배치 */}
      <div className="flex justify-between items-start gap-3 mt-3 text-[11px]">
        <div className="space-y-0.5">
          <div><b>발주번호</b> · {order.ORDER_NO}</div>
          <div><b>발주일자</b> · {order.ORDER_DATE}</div>
          <div><b>현재상태</b> · <span className="font-semibold">{STATUS_LABEL[order.STATUS] ?? order.STATUS}</span></div>
        </div>
        <table className="text-[11px] border border-slate-400 self-start" style={{borderCollapse:'collapse'}}>
          <tbody>
            <tr>
              <td rowSpan={3} className="border border-slate-400 bg-slate-700 text-white text-center font-bold px-2 py-1" style={{writingMode:'vertical-rl',textOrientation:'upright',width:'24px'}}>공급자</td>
              <td className="border border-slate-400 bg-slate-100 text-center font-semibold px-2 py-1 whitespace-nowrap" style={{width:'110px'}}>결제 계좌번호</td>
              <td className="border border-slate-400 px-3 py-1 font-bold text-slate-900 whitespace-nowrap">{supplier.BANK_ACCOUNT}</td>
            </tr>
            <tr>
              <td className="border border-slate-400 bg-slate-100 text-center font-semibold px-2 py-1">전화번호</td>
              <td className="border border-slate-400 px-3 py-1">{supplier.PHONE}</td>
            </tr>
            <tr>
              <td className="border border-slate-400 bg-slate-100 text-center font-semibold px-2 py-1">이메일</td>
              <td className="border border-slate-400 px-3 py-1 text-blue-700">{supplier.EMAIL}</td>
            </tr>
          </tbody>
        </table>
      </div>

      <div className="border border-slate-200 rounded p-2 bg-slate-50/60 mt-3">
        <div className="font-semibold text-slate-900">{order.COMPANY_NAME} <span className="text-slate-500 font-normal">귀하</span></div>
        <div className="text-[11px] text-slate-600 mt-0.5 leading-relaxed">
          {order.CEO_NAME && <>대표: {order.CEO_NAME} · </>}
          {order.BIZ_NO && <>사업자번호: {order.BIZ_NO} · </>}
          {order.PHONE && <>전화: {order.PHONE}</>}
          {order.ADDRESS && <div>주소: {order.ADDRESS}</div>}
        </div>
      </div>

      {lowStock.length > 0 && (
        <div className="border border-rose-200 bg-rose-50 rounded p-2 text-[11px] text-rose-700 flex items-start gap-2 js-no-export">
          <AlertCircle size={14} className="mt-0.5 flex-shrink-0" />
          <div>
            <b>재고 부족 {lowStock.length}건</b> — 출고 시 거부됩니다:
            <ul className="mt-1 ml-4 list-disc">
              {lowStock.map((it) => (
                <li key={it.SEQ}>{it.ITEM_NAME} (요청 {fmt(it.QTY)} / 현재고 {fmt(it.STOCK_QTY)})</li>
              ))}
            </ul>
          </div>
        </div>
      )}

      {editable && (
        <div className="flex flex-wrap items-center gap-2 js-no-export">
          <span className="text-[11px] text-slate-500">택배/용차 라인 추가:</span>
          <button
            type="button"
            onClick={() => addNewExtra("DELIVERY")}
            className="inline-flex items-center gap-1 h-7 px-2.5 rounded bg-orange-100 text-orange-800 text-[11px] font-bold hover:bg-orange-200"
          >
            + 택배 추가
          </button>
          <button
            type="button"
            onClick={() => addNewExtra("CHARTER")}
            className="inline-flex items-center gap-1 h-7 px-2.5 rounded bg-sky-100 text-sky-800 text-[11px] font-bold hover:bg-sky-200"
          >
            + 용차 추가
          </button>
        </div>
      )}

      <table className="w-full text-[11px] border border-slate-300 mt-3">
        <thead className="bg-slate-100">
          <tr>
            <th className="border border-slate-300 px-1.5 py-1.5 w-8">#</th>
            <th className="border border-slate-300 px-1.5 py-1.5 text-left">품명</th>
            <th className="border border-slate-300 px-1.5 py-1.5 w-12">구분</th>
            <th className="border border-slate-300 px-1.5 py-1.5 w-14 js-no-export">현재고</th>
            <th className="border border-slate-300 px-1.5 py-1.5 w-20">수량</th>
            <th className="border border-slate-300 px-1.5 py-1.5 w-20">단가</th>
            <th className="border border-slate-300 px-1.5 py-1.5">공급가</th>
            <th className="border border-slate-300 px-1.5 py-1.5">세액</th>
            <th className="border border-slate-300 px-1.5 py-1.5">합계</th>
            <th className="border border-slate-300 px-1.5 py-1.5 w-32">비고</th>
            {editable && <th className="border border-slate-300 px-1 py-1.5 w-8"></th>}
          </tr>
        </thead>
        <tbody className="tabular-nums">
          {items.map((it, idx) => {
            const displaySeq = idx + 1;
            const isExtra = it.KIND === "DELIVERY" || it.KIND === "CHARTER";
            const lack = !isExtra && Number(it.STOCK_QTY) < Number(it.QTY);
            const kindBadge = it.KIND === "DELIVERY" ? "택배" : it.KIND === "CHARTER" ? "용차" : null;
            const kindBg = it.KIND === "DELIVERY" ? "bg-orange-50" : it.KIND === "CHARTER" ? "bg-sky-50" : "";

            if (isExtra && editable) {
              return (
                <ExtraRow
                  key={`${it.OBJID}-${it.QTY}-${it.UNIT_PRICE}-${it.EXTRA_LABEL ?? ""}`}
                  line={it}
                  displaySeq={displaySeq}
                  editable={editable}
                  onSave={(updated) => upsertExtra({ objid: it.OBJID, kind: it.KIND as "DELIVERY" | "CHARTER", ...updated })}
                  onDelete={() => deleteExtra(it.OBJID)}
                  onSaveRemark={(r) => saveRemark(it.OBJID, r)}
                />
              );
            }

            return (
              <tr key={it.OBJID || it.SEQ} className={kindBg}>
                <td className="border border-slate-300 px-1.5 py-1 text-center">{displaySeq}</td>
                <td className="border border-slate-300 px-1.5 py-1">
                  {kindBadge && <span className={`mr-1 text-[9px] font-bold px-1 py-0.5 rounded ${it.KIND === "DELIVERY" ? "bg-orange-200 text-orange-800" : "bg-sky-200 text-sky-800"}`}>{kindBadge}</span>}
                  {it.ITEM_NAME}
                </td>
                <td className={`border border-slate-300 px-1.5 py-1 text-center ${it.IS_TAX_FREE === "Y" ? "text-violet-700" : "text-rose-700"}`}>
                  {it.IS_TAX_FREE === "Y" ? "면세" : "과세"}
                </td>
                <td className={`border border-slate-300 px-1.5 py-1 text-right js-no-export ${lack ? "text-rose-700 font-bold" : "text-slate-600"}`}>
                  {isExtra ? "-" : fmt(it.STOCK_QTY)}
                </td>
                <td className="border border-slate-300 px-1.5 py-1 text-right">{fmt(it.QTY)}</td>
                <td className="border border-slate-300 px-1.5 py-1 text-right">{fmt(it.UNIT_PRICE)}</td>
                <td className="border border-slate-300 px-1.5 py-1 text-right">{fmt(it.SUPPLY_AMOUNT)}</td>
                <td className="border border-slate-300 px-1.5 py-1 text-right">{it.IS_TAX_FREE === "Y" ? "-" : fmt(it.VAT_AMOUNT)}</td>
                <td className="border border-slate-300 px-1.5 py-1 text-right font-semibold">{fmt(it.TOTAL_AMOUNT)}</td>
                <td className="border border-slate-300 px-1 py-0.5">
                  {editable
                    ? <RemarkInput initial={it.REMARK || ""} onSave={(r) => saveRemark(it.OBJID, r)} />
                    : <span className="text-slate-600 text-[10px]">{it.REMARK || ""}</span>}
                </td>
                {editable && <td className="border border-slate-300 px-1 py-1"></td>}
              </tr>
            );
          })}
          {items.length === 0 && (
            <tr><td colSpan={editable ? 11 : 10} className="border border-slate-300 px-2 py-6 text-center text-slate-400">품목이 없습니다.</td></tr>
          )}
        </tbody>
      </table>

      <table className="ml-auto text-[12px] tabular-nums mt-3">
        <tbody>
          <tr><td className="px-3 py-1 text-violet-700">면세 합계</td><td className="px-3 py-1 text-right min-w-[120px]">₩ {fmt(order.TOTAL_TAXFREE)}</td></tr>
          <tr><td className="px-3 py-1 text-rose-700">과세 공급가</td><td className="px-3 py-1 text-right">₩ {fmt(order.TOTAL_TAXABLE)}</td></tr>
          <tr><td className="px-3 py-1">세액 합계</td><td className="px-3 py-1 text-right">₩ {fmt(order.TOTAL_VAT)}</td></tr>
          <tr className="border-t-2 border-slate-900 font-bold">
            <td className="px-3 py-1.5 whitespace-nowrap text-[11px]">총 합계 (VAT포함)</td>
            <td className="px-3 py-1.5 text-right text-emerald-700 whitespace-nowrap">₩ {fmt(order.TOTAL_AMOUNT)}</td>
          </tr>
        </tbody>
      </table>
      </div>{/* /statementRef capture area */}

      {order.STATUS === "REQUESTED" && (
        <div className="flex items-center justify-between gap-2 pt-3 border-t border-slate-200 flex-wrap">
          <span className="text-[11px] text-slate-400">
            ※ 다중 발주를 일괄 처리하려면 왼쪽 리스트에서 체크박스 선택 후 상단 [출고] 버튼을 사용하세요.
          </span>
          <button
            onClick={() => onCancel(order)}
            disabled={busy || shipping}
            className="px-3 h-9 rounded-lg border border-rose-200 text-rose-700 text-xs font-semibold hover:bg-rose-50 disabled:opacity-50 inline-flex items-center gap-1"
          >
            <X size={12} /> 반려
          </button>
        </div>
      )}
      {(order.STATUS === "APPROVED" || order.STATUS === "PAID") && (
        <div className="flex items-center justify-between pt-3 border-t border-slate-200 gap-2 flex-wrap">
          <div className="text-[11px] text-emerald-700 inline-flex items-center gap-1">
            <Check size={12} /> 출고 완료 {order.APPROVE_DATE && `— ${order.APPROVE_DATE}`}
          </div>
          <IssueEinvoiceButton order={order} />
        </div>
      )}
    </div>
  );
}

function ExtraRow({ line, displaySeq, editable, onSave, onDelete, onSaveRemark }: {
  line: DetailLine;
  displaySeq: number;
  editable: boolean;
  onSave: (data: { label: string; unitPrice: number; qty: number }) => void;
  onDelete: () => void;
  onSaveRemark: (r: string) => void;
}) {
  const [label, setLabel] = useState(line.EXTRA_LABEL || line.ITEM_NAME);
  const [unitPrice, setUnitPrice] = useState(Number(line.UNIT_PRICE) || 0);
  const [qty, setQty] = useState(Number(line.QTY) || 1);

  // 외부에서 line 이 갱신되면(예: + 택배 추가 → 서버 재조회) 인풋도 동기화.
  // 같은 OBJID 라서 컴포넌트가 unmount 되지 않아 useState 초기값이 무시되는 문제 방지.
  useEffect(() => {
    setLabel(line.EXTRA_LABEL || line.ITEM_NAME);
    setUnitPrice(Number(line.UNIT_PRICE) || 0);
    setQty(Number(line.QTY) || 1);
  }, [line.OBJID, line.EXTRA_LABEL, line.ITEM_NAME, line.UNIT_PRICE, line.QTY]);
  const total = Math.round(unitPrice * qty);
  const supply = Math.round(total / 1.1);
  const vat = total - supply;
  const dirty = label !== (line.EXTRA_LABEL || line.ITEM_NAME)
             || unitPrice !== Number(line.UNIT_PRICE)
             || qty !== Number(line.QTY);
  const isDelivery = line.KIND === "DELIVERY";

  return (
    <tr className={isDelivery ? "bg-orange-50" : "bg-sky-50"}>
      <td className="border border-slate-300 px-1.5 py-1 text-center">{displaySeq}</td>
      <td className="border border-slate-300 px-1.5 py-1">
        <span className={`mr-1 text-[9px] font-bold px-1 py-0.5 rounded ${isDelivery ? "bg-orange-200 text-orange-800" : "bg-sky-200 text-sky-800"}`}>
          {isDelivery ? "택배" : "용차"}
        </span>
        <input
          value={label}
          onChange={(e) => setLabel(e.target.value)}
          className="h-6 px-1.5 border border-slate-200 rounded text-[11px] bg-white w-[calc(100%-50px)] inline"
        />
      </td>
      <td className="border border-slate-300 px-1.5 py-1 text-center text-rose-700">과세</td>
      <td className="border border-slate-300 px-1.5 py-1 text-right text-slate-400 js-no-export">-</td>
      <td className="border border-slate-300 px-1 py-1 text-right">
        <input type="number" min={1} value={qty}
          onChange={(e) => setQty(Number(e.target.value))}
          className="w-full h-6 px-1 border border-slate-200 rounded text-[11px] text-right tabular-nums bg-white" />
      </td>
      <td className="border border-slate-300 px-1 py-1 text-right">
        <input type="number" min={0} value={unitPrice}
          onChange={(e) => setUnitPrice(Number(e.target.value))}
          className="w-full h-6 px-1 border border-slate-200 rounded text-[11px] text-right tabular-nums bg-white" />
      </td>
      <td className="border border-slate-300 px-1.5 py-1 text-right tabular-nums">{Number(supply).toLocaleString("ko-KR")}</td>
      <td className="border border-slate-300 px-1.5 py-1 text-right tabular-nums">{Number(vat).toLocaleString("ko-KR")}</td>
      <td className="border border-slate-300 px-1.5 py-1 text-right tabular-nums font-semibold">{Number(total).toLocaleString("ko-KR")}</td>
      <td className="border border-slate-300 px-1 py-0.5">
        {editable
          ? <RemarkInput initial={line.REMARK || ""} onSave={onSaveRemark} />
          : <span className="text-slate-600 text-[10px]">{line.REMARK || ""}</span>}
      </td>
      <td className="border border-slate-300 px-1 py-1 text-center">
        <div className="inline-flex gap-0.5">
          {dirty && (
            <button
              type="button"
              onClick={() => onSave({ label, unitPrice, qty })}
              className="text-emerald-700 hover:text-emerald-900"
              title="저장"
            >
              <Check size={12} />
            </button>
          )}
          <button type="button" onClick={onDelete} className="text-rose-500 hover:text-rose-700" title="삭제">
            <X size={12} />
          </button>
        </div>
      </td>
    </tr>
  );
}

function IssueEinvoiceButton({ order }: { order: DetailOrder }) {
  const [busy, setBusy] = useState(false);
  const [issued, setIssued] = useState<{ ntsInvoiceNo?: string; provider?: string } | null>(null);

  const onIssue = async (kind: "TAX" | "TAXFREE") => {
    const ok = await Swal.fire({
      icon: "question",
      title: `${kind === "TAX" ? "세금계산서" : "계산서(면세)"} 발행`,
      html: `<div class="text-sm">발주 <b>${order.ORDER_NO}</b><br>합계 ₩${fmt(order.TOTAL_AMOUNT)}<br><br>전자세금계산서를 발행하시겠습니까?</div>`,
      showCancelButton: true,
      confirmButtonText: "발행",
      cancelButtonText: "취소",
      confirmButtonColor: "#0f766e",
    });
    if (!ok.isConfirmed) return;
    setBusy(true);
    try {
      const res = await fetch("/api/m/einvoices/issue", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ orderObjid: order.OBJID, invoiceKind: kind, invoiceType: "NORMAL" }),
      });
      const j = await res.json();
      if (j.success) {
        setIssued({ ntsInvoiceNo: j.ntsInvoiceNo, provider: j.provider });
        await Swal.fire({
          icon: "success",
          title: "발행 완료",
          html: `
            <div class="text-sm">
              <div>승인번호: <b>${j.ntsInvoiceNo ?? "-"}</b></div>
              <div>처리방식: <b>${j.provider}</b></div>
              ${j.message ? `<div class="text-xs text-slate-500 mt-2">${j.message}</div>` : ""}
            </div>`,
        });
      } else {
        Swal.fire({ icon: "error", title: "발행 실패", text: j.message ?? "오류" });
      }
    } finally { setBusy(false); }
  };

  if (issued) {
    return (
      <span className="text-[11px] text-emerald-700 inline-flex items-center gap-1.5">
        <Check size={11} /> 세금계산서 발행됨
        {issued.ntsInvoiceNo && <span className="font-mono text-slate-500">({issued.ntsInvoiceNo})</span>}
      </span>
    );
  }
  return (
    <div className="flex gap-1.5">
      <button
        type="button"
        disabled={busy}
        onClick={() => onIssue("TAX")}
        className="inline-flex items-center gap-1 h-8 px-2.5 rounded bg-rose-600 text-white text-[11px] font-bold hover:bg-rose-700 disabled:opacity-50"
        title="과세 전자세금계산서 발행"
      >
        세금계산서 발행
      </button>
      <button
        type="button"
        disabled={busy}
        onClick={() => onIssue("TAXFREE")}
        className="inline-flex items-center gap-1 h-8 px-2.5 rounded bg-violet-600 text-white text-[11px] font-bold hover:bg-violet-700 disabled:opacity-50"
        title="면세 계산서 발행"
      >
        계산서(면세)
      </button>
    </div>
  );
}

function RemarkInput({ initial, onSave }: { initial: string; onSave: (r: string) => void }) {
  const [val, setVal] = useState(initial);
  useEffect(() => { setVal(initial); }, [initial]);
  const dirty = val !== initial;
  return (
    <div className="flex items-center gap-1">
      <input
        value={val}
        onChange={(e) => setVal(e.target.value)}
        onBlur={() => { if (dirty) onSave(val); }}
        onKeyDown={(e) => { if (e.key === "Enter") { (e.target as HTMLInputElement).blur(); } }}
        placeholder="비고"
        className="w-full h-6 px-1.5 border border-slate-200 rounded text-[10px] bg-white"
      />
    </div>
  );
}
