"use client";

import React, { useEffect, useRef, useState } from "react";
import { FileDown, FileText, Loader2, Printer } from "lucide-react";
import { Button } from "@/components/ui/button";
import { ComponentConfig, GridCell, ReportPage, WatermarkConfig } from "@/types/report";
import { useReportRenderer, QueryResult } from "@/hooks/useReportRenderer";
import { getFullImageUrl } from "@/lib/api/client";
import {
  TextRenderer,
  TableRenderer,
  ImageRenderer,
  DividerRenderer,
  SignatureRenderer,
  StampRenderer,
  PageNumberRenderer,
  CardRenderer,
  CalculationRenderer,
  BarcodeCanvasRenderer,
  CheckboxRenderer,
} from "./designer/renderers";
import { MM_TO_PX } from "@/lib/report/constants";

interface ReportInlineViewerProps {
  reportId: string | null;
  contextParams?: Record<string, unknown>;
  className?: string;
  showToolbar?: boolean;
  /** 컴포넌트 클릭 콜백 — 편집 모드에서 사용 */
  onComponentClick?: (component: ComponentConfig) => void;
  /** cellType="input" 셀의 커스텀 값 오버라이드: { [componentId]: { [cellId]: value } } */
  cellOverrides?: Record<string, Record<string, string>>;
  /** input 셀 클릭 콜백 */
  onInputCellClick?: (component: ComponentConfig, cell: GridCell) => void;
}

export function ReportInlineViewer({
  reportId,
  contextParams,
  className = "",
  showToolbar = true,
  onComponentClick,
  cellOverrides,
  onInputCellClick,
}: ReportInlineViewerProps) {
  const { detail, pages, watermark, getQueryResult, isLoading } = useReportRenderer(reportId, contextParams);

  const containerRef = useRef<HTMLDivElement>(null);
  const previewRef = useRef<HTMLDivElement>(null);
  const [scale, setScale] = useState(1);
  const [isExporting, setIsExporting] = useState(false);

  const editable = !!onComponentClick;

  useEffect(() => {
    if (!containerRef.current || pages.length === 0) return;
    const calculateScale = () => {
      const container = containerRef.current;
      if (!container) return;
      const pageWidthPx = pages[0].width * MM_TO_PX;
      const availableWidth = container.clientWidth - 48;
      setScale(Math.min(availableWidth / pageWidthPx, 1));
    };
    const observer = new ResizeObserver(calculateScale);
    observer.observe(containerRef.current);
    calculateScale();
    return () => observer.disconnect();
  }, [pages]);

  const handleDownloadPDF = async () => {
    if (!previewRef.current || pages.length === 0) return;
    setIsExporting(true);
    try {
      const [{ jsPDF }, html2canvas] = await Promise.all([
        import("jspdf"),
        import("html2canvas").then((m) => m.default),
      ]);
      const pageEls = previewRef.current.querySelectorAll<HTMLElement>("[data-list-preview-page]");
      if (pageEls.length === 0) return;
      const firstPage = pages[0];
      const doc = new jsPDF({
        orientation: firstPage.orientation === "landscape" ? "l" : "p",
        unit: "mm",
        format: [firstPage.width, firstPage.height],
      });
      for (let i = 0; i < pageEls.length; i++) {
        const canvas = await html2canvas(pageEls[i], { scale: 2, useCORS: true, allowTaint: true, backgroundColor: "#ffffff" });
        if (i > 0) {
          const p = pages[i] ?? firstPage;
          doc.addPage([p.width, p.height], p.orientation === "landscape" ? "l" : "p");
        }
        const p = pages[i] ?? firstPage;
        doc.addImage(canvas.toDataURL("image/jpeg", 0.92), "JPEG", 0, 0, p.width, p.height);
      }
      doc.save(`${detail?.report?.report_name_kor ?? "report"}.pdf`);
    } catch { /* 무시 */ } finally { setIsExporting(false); }
  };

  const handlePrint = () => {
    if (!previewRef.current || pages.length === 0) return;

    // 1) body의 기존 자식들 숨기기
    const bodyChildren = Array.from(document.body.children) as HTMLElement[];
    bodyChildren.forEach((el) => { el.setAttribute("data-print-hidden", "true"); });

    // 2) 프리뷰 내용을 body 직속에 복제 (스케일 제거, 원본 크기)
    const printDiv = document.createElement("div");
    printDiv.id = "report-print-root";

    // 각 페이지를 원본 크기로 복제
    const pageEls = previewRef.current.querySelectorAll<HTMLElement>("[data-list-preview-page]");
    pageEls.forEach((el) => {
      const clone = el.cloneNode(true) as HTMLElement;
      clone.style.boxShadow = "none";
      clone.style.position = "relative";
      clone.style.pageBreakAfter = "always";
      clone.style.margin = "0 auto";
      printDiv.appendChild(clone);
    });

    document.body.appendChild(printDiv);

    // 3) 스타일
    const style = document.createElement("style");
    style.id = "report-print-style";
    style.textContent = `
      @media print {
        @page { margin: 0; }
        * { print-color-adjust: exact !important; -webkit-print-color-adjust: exact !important; }
        [data-print-hidden] { display: none !important; }
        #report-print-root { display: block !important; }
        #report-print-root [data-list-preview-page] { page-break-after: always; }
        #report-print-root [data-list-preview-page]:last-child { page-break-after: auto; }
      }
      #report-print-root { display: none; }
    `;
    document.head.appendChild(style);

    // 4) 인쇄 후 정리
    const cleanup = () => {
      printDiv.remove();
      style.remove();
      bodyChildren.forEach((el) => { el.removeAttribute("data-print-hidden"); });
      window.removeEventListener("afterprint", cleanup);
    };
    window.addEventListener("afterprint", cleanup);

    setTimeout(() => window.print(), 100);
  };

  if (!reportId) {
    return (
      <div className={`flex h-full items-center justify-center ${className}`}>
        <div className="text-center text-gray-400">
          <FileText className="mx-auto mb-3 h-14 w-14 opacity-30" />
          <p className="text-sm">리포트 양식을 선택해주세요</p>
        </div>
      </div>
    );
  }

  return (
    <div className={`flex h-full flex-col ${className}`}>
      {showToolbar && pages.length > 0 && !isLoading && (
        <div className="flex shrink-0 items-center justify-end gap-2 border-b bg-white px-3 py-2">
          <Button variant="outline" size="sm" onClick={handlePrint} className="gap-1.5 text-xs">
            <Printer className="h-3.5 w-3.5" /> 인쇄
          </Button>
          <Button variant="outline" size="sm" onClick={handleDownloadPDF} disabled={isExporting} className="gap-1.5 text-xs">
            {isExporting ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <FileDown className="h-3.5 w-3.5" />} PDF
          </Button>
        </div>
      )}

      <div ref={containerRef} className="min-h-0 flex-1 overflow-auto bg-gray-100">
        {isLoading ? (
          <div className="flex h-full items-center justify-center"><Loader2 className="h-10 w-10 animate-spin text-gray-400" /></div>
        ) : pages.length === 0 ? (
          <div className="flex h-full flex-col items-center justify-center gap-3 text-gray-400">
            <FileText className="h-14 w-14 opacity-30" />
            <p className="text-sm">{detail ? "저장된 레이아웃이 없습니다." : "데이터를 불러오는 중..."}</p>
          </div>
        ) : (
          <div ref={previewRef} className="flex flex-col items-center p-6" style={{ gap: `${24 * scale}px` }}>
            {[...pages].sort((a, b) => a.page_order - b.page_order).map((page, pageIndex) => (
              <div key={page.page_id} style={{
                width: `${Math.ceil(page.width * MM_TO_PX * scale) + 1}px`,
                minHeight: `${Math.ceil(page.height * MM_TO_PX * scale) + 1}px`,
                flexShrink: 0,
              }}>
                <div style={{
                  transform: `scale(${scale})`, transformOrigin: "top left",
                  width: `${page.width * MM_TO_PX}px`, minHeight: `${page.height * MM_TO_PX}px`,
                }}>
                  <PagePreview
                    page={page} pageIndex={pageIndex} totalPages={pages.length}
                    pages={pages} watermark={watermark} getQueryResult={getQueryResult}
                    editable={editable} onComponentClick={onComponentClick}
                    cellOverrides={cellOverrides} onInputCellClick={onInputCellClick}
                  />
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

/* ── 내부 컴포넌트 ── */

function WatermarkLayer({ watermark, pageWidth, pageHeight }: { watermark: WatermarkConfig; pageWidth: number; pageHeight: number }) {
  const baseStyle: React.CSSProperties = { position: "absolute", top: 0, left: 0, width: "100%", height: "100%", pointerEvents: "none", overflow: "hidden", zIndex: 0 };
  const rotation = watermark.rotation ?? -45;
  const textOrImage = watermark.type === "text" ? (
    <span style={{ fontSize: `${watermark.fontSize || 48}px`, color: watermark.fontColor || "#cccccc", fontWeight: "bold", userSelect: "none", whiteSpace: "nowrap" }}>{watermark.text || "WATERMARK"}</span>
  ) : watermark.imageUrl ? (
    // eslint-disable-next-line @next/next/no-img-element
    <img src={watermark.imageUrl.startsWith("data:") ? watermark.imageUrl : getFullImageUrl(watermark.imageUrl)} alt="" style={{ maxWidth: "50%", maxHeight: "50%", objectFit: "contain" }} />
  ) : null;

  if (watermark.style === "diagonal") return <div style={baseStyle}><div style={{ position: "absolute", top: "50%", left: "50%", transform: `translate(-50%, -50%) rotate(${rotation}deg)`, opacity: watermark.opacity, display: "flex", alignItems: "center", justifyContent: "center" }}>{textOrImage}</div></div>;
  if (watermark.style === "center") return <div style={baseStyle}><div style={{ position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%)", opacity: watermark.opacity, display: "flex", alignItems: "center", justifyContent: "center" }}>{textOrImage}</div></div>;
  if (watermark.style === "tile") {
    const tileSize = watermark.type === "text" ? (watermark.fontSize || 48) * 4 : 150;
    const cols = Math.ceil((pageWidth * MM_TO_PX) / tileSize) + 2;
    const rows = Math.ceil((pageHeight * MM_TO_PX) / tileSize) + 2;
    return <div style={baseStyle}><div style={{ position: "absolute", top: "-50%", left: "-50%", width: "200%", height: "200%", display: "flex", flexWrap: "wrap", alignContent: "flex-start", transform: `rotate(${rotation}deg)`, opacity: watermark.opacity }}>
      {Array.from({ length: rows * cols }).map((_, i) => <div key={i} style={{ width: `${tileSize}px`, height: `${tileSize}px`, display: "flex", alignItems: "center", justifyContent: "center" }}>{textOrImage}</div>)}
    </div></div>;
  }
  return null;
}

function PagePreview({ page, pageIndex, totalPages, pages, watermark, getQueryResult, editable, onComponentClick, cellOverrides, onInputCellClick }: {
  page: ReportPage; pageIndex: number; totalPages: number; pages: ReportPage[];
  watermark?: WatermarkConfig; getQueryResult: (queryId: string) => QueryResult | null;
  editable?: boolean; onComponentClick?: (comp: ComponentConfig) => void;
  cellOverrides?: Record<string, Record<string, string>>;
  onInputCellClick?: (component: ComponentConfig, cell: GridCell) => void;
}) {
  const comps = page.components ?? [];
  const sortedByY = [...comps].sort((a, b) => a.y - b.y);
  const growableTypes = new Set(["table", "card", "calculation"]);

  // 실제 렌더링 높이를 측정하여 yOffset 계산
  const [measuredHeights, setMeasuredHeights] = useState<Record<string, number>>({});
  const compRefs = useRef<Record<string, HTMLDivElement | null>>({});

  useEffect(() => {
    // 렌더 후 growable 컴포넌트의 실제 scrollHeight 측정
    const newHeights: Record<string, number> = {};
    let changed = false;
    for (const c of sortedByY) {
      if (growableTypes.has(c.type)) {
        const el = compRefs.current[c.id];
        if (el) {
          const actual = el.scrollHeight;
          if (actual > c.height && actual !== measuredHeights[c.id]) {
            newHeights[c.id] = actual;
            changed = true;
          }
        }
      }
    }
    if (changed) setMeasuredHeights((prev) => ({ ...prev, ...newHeights }));
  });

  // yOffset 계산
  const offsets: Record<string, number> = {};
  let cumulativeShift = 0;
  for (const c of sortedByY) {
    offsets[c.id] = cumulativeShift;
    if (growableTypes.has(c.type)) {
      const measured = measuredHeights[c.id];
      if (measured && measured > c.height) {
        cumulativeShift += measured - c.height;
      }
    }
  }

  const totalPageHeight = page.height * MM_TO_PX + cumulativeShift;

  const setRef = (id: string) => (el: HTMLDivElement | null) => {
    compRefs.current[id] = el;
  };

  return (
    <div data-list-preview-page={page.page_id} className="relative shadow-md" style={{
      width: `${page.width * MM_TO_PX}px`, minHeight: `${totalPageHeight}px`,
      backgroundColor: page.background_color || "#ffffff", flexShrink: 0, overflow: "visible",
    }}>
      {watermark?.enabled && <WatermarkLayer watermark={watermark} pageWidth={page.width} pageHeight={page.height} />}
      {sortedByY.sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0)).map((comp) => (
        <ComponentRenderer key={comp.id} comp={comp} pageIndex={pageIndex} totalPages={totalPages}
          pages={pages} getQueryResult={getQueryResult} editable={editable} onComponentClick={onComponentClick}
          cellOverrides={cellOverrides} onInputCellClick={onInputCellClick}
          yOffset={offsets[comp.id] || 0}
          measureRef={growableTypes.has(comp.type) ? setRef(comp.id) : undefined} />
      ))}
    </div>
  );
}

function ComponentRenderer({ comp, pageIndex, totalPages, pages, getQueryResult, editable, onComponentClick, cellOverrides, onInputCellClick, yOffset = 0, measureRef }: {
  comp: ComponentConfig; pageIndex: number; totalPages: number; pages: ReportPage[];
  getQueryResult: (queryId: string) => QueryResult | null;
  editable?: boolean; onComponentClick?: (comp: ComponentConfig) => void;
  cellOverrides?: Record<string, Record<string, string>>;
  onInputCellClick?: (component: ComponentConfig, cell: GridCell) => void;
  yOffset?: number; measureRef?: (el: HTMLDivElement | null) => void;
}) {
  const [hovered, setHovered] = useState(false);
  const isDivider = comp.type === "divider";
  const isClickable = editable && !isDivider && comp.type !== "pageNumber";

  // 데이터 양에 따라 늘어나야 하는 컴포넌트
  const growable = comp.type === "table" || comp.type === "card" || comp.type === "calculation";

  const baseStyle: React.CSSProperties = {
    position: "absolute",
    left: `${comp.x}px`, top: `${comp.y + yOffset}px`,
    width: `${comp.width}px`,
    ...(growable ? { minHeight: `${comp.height}px` } : { height: `${comp.height}px` }),
    boxSizing: "border-box",
    overflow: growable ? "visible" : "hidden",
    zIndex: comp.zIndex ?? 0,
    backgroundColor: comp.backgroundColor || "transparent",
    ...(comp.borderWidth ? { borderWidth: `${comp.borderWidth}px`, borderColor: comp.borderColor || "#000", borderStyle: "solid" } : {}),
    ...(comp.borderRadius ? { borderRadius: `${comp.borderRadius}px` } : {}),
    padding: isDivider ? 0 : comp.padding != null ? typeof comp.padding === "number" ? `${comp.padding}px` : comp.padding : "8px",
    // 클릭 가능 시 호버 효과
    ...(isClickable ? { cursor: "pointer", transition: "outline 0.15s, box-shadow 0.15s" } : {}),
    ...(isClickable && hovered ? { outline: "2px solid #3b82f6", outlineOffset: "-1px", boxShadow: "0 0 0 4px rgba(59,130,246,0.15)" } : {}),
  };

  const STATUS_LABELS: Record<string, string> = { draft: "작성중", pending: "검토중", approved: "승인", rejected: "반려", converted: "수주전환" };

  const getComponentValue = (c: ComponentConfig): string => {
    if (c.queryId && c.fieldName) {
      const qr = getQueryResult(c.queryId);
      let val = "-";
      if (qr?.rows?.length) {
        const raw = qr.rows[0][c.fieldName];
        if (raw != null && raw !== "") {
          val = String(raw);
          if (c.fieldName === "status" && STATUS_LABELS[val]) val = STATUS_LABELS[val];
        }
      }
      // defaultValue가 있으면 라벨로 표시: "라벨\n값"
      if (c.defaultValue) return `${c.defaultValue}\n${val}`;
      return val;
    }
    return c.defaultValue || "";
  };

  const displayValue = getComponentValue(comp);
  const sortedPages = [...pages].sort((a, b) => a.page_order - b.page_order);
  const currentPageId = sortedPages[pageIndex]?.page_id ?? null;
  const layoutConfig = { pages: sortedPages.map((p) => ({ page_id: p.page_id, page_order: p.page_order })) };

  const handleClick = (e: React.MouseEvent) => {
    if (!isClickable) return;
    e.stopPropagation();
    onComponentClick?.(comp);
  };

  return (
    <div ref={measureRef} style={baseStyle} onClick={handleClick}
      onMouseEnter={() => isClickable && setHovered(true)}
      onMouseLeave={() => setHovered(false)}
    >
      {(comp.type === "text" || comp.type === "label") && <TextRenderer component={comp} displayValue={displayValue} getQueryResult={getQueryResult} />}
      {comp.type === "table" && <TableRenderer component={comp} getQueryResult={getQueryResult} cellOverrides={cellOverrides} onInputCellClick={onInputCellClick} />}
      {comp.type === "image" && <ImageRenderer component={comp} />}
      {comp.type === "divider" && <DividerRenderer component={comp} />}
      {comp.type === "signature" && <SignatureRenderer component={comp} />}
      {comp.type === "stamp" && <StampRenderer component={comp} />}
      {comp.type === "pageNumber" && <PageNumberRenderer component={comp} currentPageId={currentPageId} layoutConfig={layoutConfig} />}
      {comp.type === "card" && <CardRenderer component={comp} getQueryResult={getQueryResult} />}
      {comp.type === "calculation" && <CalculationRenderer component={comp} getQueryResult={getQueryResult} />}
      {comp.type === "barcode" && <BarcodeCanvasRenderer component={comp} getQueryResult={getQueryResult} />}
      {comp.type === "checkbox" && <CheckboxRenderer component={comp} getQueryResult={getQueryResult} />}
    </div>
  );
}
