"use client";

import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Printer, FileDown, FileText } from "lucide-react";
import { useReportDesigner } from "@/contexts/ReportDesignerContext";
import { useState, useRef, useEffect } from "react";
import { useToast } from "@/hooks/use-toast";
import { getFullImageUrl } from "@/lib/api/client";
import JsBarcode from "jsbarcode";
import QRCode from "qrcode";

// mm -> px 변환 상수
const MM_TO_PX = 4;

interface ReportPreviewModalProps {
  isOpen: boolean;
  onClose: () => void;
}

// 미리보기용 워터마크 레이어 컴포넌트
interface PreviewWatermarkLayerProps {
  watermark: {
    enabled: boolean;
    type: "text" | "image";
    text?: string;
    fontSize?: number;
    fontColor?: string;
    imageUrl?: string;
    opacity: number;
    style: "diagonal" | "center" | "tile";
    rotation?: number;
  };
  pageWidth: number;
  pageHeight: number;
}

function PreviewWatermarkLayer({ watermark, pageWidth, pageHeight }: PreviewWatermarkLayerProps) {
  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;

  // 대각선 스타일
  if (watermark.style === "diagonal") {
    return (
      <div style={baseStyle}>
        <div
          className="absolute flex items-center justify-center"
          style={{
            top: "50%",
            left: "50%",
            transform: `translate(-50%, -50%) rotate(${rotation}deg)`,
            opacity: watermark.opacity,
            whiteSpace: "nowrap",
          }}
        >
          {watermark.type === "text" ? (
            <span
              style={{
                fontSize: `${watermark.fontSize || 48}px`,
                color: watermark.fontColor || "#cccccc",
                fontWeight: "bold",
                userSelect: "none",
              }}
            >
              {watermark.text || "WATERMARK"}
            </span>
          ) : (
            watermark.imageUrl && (
              <img
                src={
                  watermark.imageUrl.startsWith("data:")
                    ? watermark.imageUrl
                    : getFullImageUrl(watermark.imageUrl)
                }
                alt="watermark"
                style={{
                  maxWidth: "50%",
                  maxHeight: "50%",
                  objectFit: "contain",
                }}
              />
            )
          )}
        </div>
      </div>
    );
  }

  // 중앙 스타일
  if (watermark.style === "center") {
    return (
      <div style={baseStyle}>
        <div
          className="absolute flex items-center justify-center"
          style={{
            top: "50%",
            left: "50%",
            transform: "translate(-50%, -50%)",
            opacity: watermark.opacity,
          }}
        >
          {watermark.type === "text" ? (
            <span
              style={{
                fontSize: `${watermark.fontSize || 48}px`,
                color: watermark.fontColor || "#cccccc",
                fontWeight: "bold",
                userSelect: "none",
              }}
            >
              {watermark.text || "WATERMARK"}
            </span>
          ) : (
            watermark.imageUrl && (
              <img
                src={
                  watermark.imageUrl.startsWith("data:")
                    ? watermark.imageUrl
                    : getFullImageUrl(watermark.imageUrl)
                }
                alt="watermark"
                style={{
                  maxWidth: "50%",
                  maxHeight: "50%",
                  objectFit: "contain",
                }}
              />
            )
          )}
        </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((_, index) => (
            <div
              key={index}
              style={{
                width: `${tileSize}px`,
                height: `${tileSize}px`,
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
              }}
            >
              {watermark.type === "text" ? (
                <span
                  style={{
                    fontSize: `${watermark.fontSize || 24}px`,
                    color: watermark.fontColor || "#cccccc",
                    fontWeight: "bold",
                    userSelect: "none",
                    whiteSpace: "nowrap",
                  }}
                >
                  {watermark.text || "WATERMARK"}
                </span>
              ) : (
                watermark.imageUrl && (
                  <img
                    src={
                      watermark.imageUrl.startsWith("data:")
                        ? watermark.imageUrl
                        : getFullImageUrl(watermark.imageUrl)
                    }
                    alt="watermark"
                    style={{
                      width: `${tileSize * 0.6}px`,
                      height: `${tileSize * 0.6}px`,
                      objectFit: "contain",
                    }}
                  />
                )
              )}
            </div>
          ))}
        </div>
      </div>
    );
  }

  return null;
}

// 바코드/QR코드 미리보기 컴포넌트
function BarcodePreview({
  component,
  getQueryResult,
}: {
  component: any;
  getQueryResult: (queryId: string) => { fields: string[]; rows: Record<string, unknown>[] } | null;
}) {
  const svgRef = useRef<SVGSVGElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const [error, setError] = useState<string | null>(null);

  const barcodeType = component.barcodeType || "CODE128";
  const isQR = barcodeType === "QR";

  // 바코드 값 결정
  const getBarcodeValue = (): string => {
    // QR코드 다중 필드 모드
    if (
      isQR &&
      component.qrUseMultiField &&
      component.qrDataFields &&
      component.qrDataFields.length > 0 &&
      component.query_id
    ) {
      const queryResult = getQueryResult(component.query_id);
      if (queryResult && queryResult.rows && queryResult.rows.length > 0) {
        if (component.qrIncludeAllRows) {
          const allRowsData: Record<string, string>[] = [];
          queryResult.rows.forEach((row) => {
            const rowData: Record<string, string> = {};
            component.qrDataFields.forEach((field: { fieldName: string; label: string }) => {
              if (field.fieldName && field.label) {
                const val = row[field.fieldName];
                rowData[field.label] = val !== null && val !== undefined ? String(val) : "";
              }
            });
            allRowsData.push(rowData);
          });
          return JSON.stringify(allRowsData);
        }
        const row = queryResult.rows[0];
        const jsonData: Record<string, string> = {};
        component.qrDataFields.forEach((field: { fieldName: string; label: string }) => {
          if (field.fieldName && field.label) {
            const val = row[field.fieldName];
            jsonData[field.label] = val !== null && val !== undefined ? String(val) : "";
          }
        });
        return JSON.stringify(jsonData);
      }
    }

    // 단일 필드 바인딩
    if (component.barcodeFieldName && component.query_id) {
      const queryResult = getQueryResult(component.query_id);
      if (queryResult && queryResult.rows && queryResult.rows.length > 0) {
        if (isQR && component.qrIncludeAllRows) {
          const allValues = queryResult.rows
            .map((row) => {
              const val = row[component.barcodeFieldName];
              return val !== null && val !== undefined ? String(val) : "";
            })
            .filter((v) => v !== "");
          return JSON.stringify(allValues);
        }
        const row = queryResult.rows[0];
        const val = row[component.barcodeFieldName];
        if (val !== null && val !== undefined) {
          return String(val);
        }
      }
      return `{${component.barcodeFieldName}}`;
    }
    return component.barcodeValue || "SAMPLE123";
  };

  const barcodeValue = getBarcodeValue();

  useEffect(() => {
    setError(null);

    if (isQR) {
      // QR코드 렌더링
      if (canvasRef.current && barcodeValue) {
        const bgColor = component.barcodeBackground === "transparent" ? "#ffffff" : (component.barcodeBackground || "#ffffff");
        QRCode.toCanvas(
          canvasRef.current,
          barcodeValue,
          {
            width: Math.min(component.width, component.height) - 20,
            margin: 2,
            color: {
              dark: component.barcodeColor || "#000000",
              light: bgColor,
            },
            errorCorrectionLevel: component.qrErrorCorrectionLevel || "M",
          },
          (err) => {
            if (err) setError(err.message || "QR코드 생성 실패");
          }
        );
      }
    } else {
      // 1D 바코드 렌더링
      if (svgRef.current && barcodeValue) {
        try {
          const bgColor = component.barcodeBackground === "transparent" ? "" : (component.barcodeBackground || "#ffffff");
          JsBarcode(svgRef.current, barcodeValue.trim(), {
            format: barcodeType.toLowerCase(),
            width: 2,
            height: Math.max(30, component.height - 40),
            displayValue: component.showBarcodeText !== false,
            lineColor: component.barcodeColor || "#000000",
            background: bgColor,
            margin: component.barcodeMargin ?? 10,
            fontSize: 12,
            textMargin: 2,
          });
        } catch (err: any) {
          setError(err?.message || "바코드 생성 실패");
        }
      }
    }
  }, [barcodeValue, barcodeType, isQR, component]);

  if (error) {
    return (
      <div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", color: "#ef4444", fontSize: "12px" }}>
        {error}
      </div>
    );
  }

  return (
    <div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", backgroundColor: component.barcodeBackground || "transparent" }}>
      {isQR ? (
        <canvas ref={canvasRef} style={{ maxWidth: "100%", maxHeight: "100%" }} />
      ) : (
        <svg ref={svgRef} style={{ maxWidth: "100%", maxHeight: "100%" }} />
      )}
    </div>
  );
}

export function ReportPreviewModal({ isOpen, onClose }: ReportPreviewModalProps) {
  const { layout_config: layoutConfig, getQueryResult, report_detail: reportDetail } = useReportDesigner();
  const [isExporting, setIsExporting] = useState(false);
  const { toast } = useToast();

  // 컴포넌트의 실제 표시 값 가져오기
  const getComponentValue = (component: any): string => {
    if (component.query_id && component.fieldName) {
      const queryResult = getQueryResult(component.query_id);
      if (queryResult && queryResult.rows.length > 0) {
        const value = queryResult.rows[0][component.fieldName];
        if (value !== null && value !== undefined) {
          return String(value);
        }
      }
      return `{${component.fieldName}}`;
    }
    return component.defaultValue || "텍스트";
  };

  // 바코드/QR코드를 base64 이미지로 변환
  const generateBarcodeImage = async (component: any): Promise<string | null> => {
    const barcodeType = component.barcodeType || "CODE128";
    const isQR = barcodeType === "QR";

    // 바코드 값 결정
    const getBarcodeValue = (): string => {
      if (
        isQR &&
        component.qrUseMultiField &&
        component.qrDataFields &&
        component.qrDataFields.length > 0 &&
        component.query_id
      ) {
        const queryResult = getQueryResult(component.query_id);
        if (queryResult && queryResult.rows && queryResult.rows.length > 0) {
          if (component.qrIncludeAllRows) {
            const allRowsData: Record<string, string>[] = [];
            queryResult.rows.forEach((row) => {
              const rowData: Record<string, string> = {};
              component.qrDataFields.forEach((field: { fieldName: string; label: string }) => {
                if (field.fieldName && field.label) {
                  const val = row[field.fieldName];
                  rowData[field.label] = val !== null && val !== undefined ? String(val) : "";
                }
              });
              allRowsData.push(rowData);
            });
            return JSON.stringify(allRowsData);
          }
          const row = queryResult.rows[0];
          const jsonData: Record<string, string> = {};
          component.qrDataFields.forEach((field: { fieldName: string; label: string }) => {
            if (field.fieldName && field.label) {
              const val = row[field.fieldName];
              jsonData[field.label] = val !== null && val !== undefined ? String(val) : "";
            }
          });
          return JSON.stringify(jsonData);
        }
      }

      if (component.barcodeFieldName && component.query_id) {
        const queryResult = getQueryResult(component.query_id);
        if (queryResult && queryResult.rows && queryResult.rows.length > 0) {
          if (isQR && component.qrIncludeAllRows) {
            const allValues = queryResult.rows
              .map((row) => {
                const val = row[component.barcodeFieldName];
                return val !== null && val !== undefined ? String(val) : "";
              })
              .filter((v) => v !== "");
            return JSON.stringify(allValues);
          }
          const row = queryResult.rows[0];
          const val = row[component.barcodeFieldName];
          if (val !== null && val !== undefined) {
            return String(val);
          }
        }
      }
      return component.barcodeValue || "SAMPLE123";
    };

    const barcodeValue = getBarcodeValue();

    try {
      if (isQR) {
        // QR코드를 canvas에 렌더링 후 base64로 변환
        const canvas = document.createElement("canvas");
        const bgColor = component.barcodeBackground === "transparent" ? "#ffffff" : (component.barcodeBackground || "#ffffff");
        await QRCode.toCanvas(canvas, barcodeValue, {
          width: Math.min(component.width, component.height) - 10,
          margin: 2,
          color: {
            dark: component.barcodeColor || "#000000",
            light: bgColor,
          },
          errorCorrectionLevel: component.qrErrorCorrectionLevel || "M",
        });
        return canvas.toDataURL("image/png");
      } else {
        // 1D 바코드를 SVG로 렌더링 후 base64로 변환
        const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
        const bgColor = component.barcodeBackground === "transparent" ? "" : (component.barcodeBackground || "#ffffff");
        JsBarcode(svg, barcodeValue.trim(), {
          format: barcodeType.toLowerCase(),
          width: 2,
          height: Math.max(30, component.height - 40),
          displayValue: component.showBarcodeText !== false,
          lineColor: component.barcodeColor || "#000000",
          background: bgColor,
          margin: component.barcodeMargin ?? 10,
          fontSize: 12,
          textMargin: 2,
        });
        const svgData = new XMLSerializer().serializeToString(svg);
        const svgBase64 = btoa(unescape(encodeURIComponent(svgData)));
        return `data:image/svg+xml;base64,${svgBase64}`;
      }
    } catch (error) {
      console.error("바코드 생성 오류:", error);
      return null;
    }
  };

  const handlePrint = async () => {
    // 바코드 이미지 미리 생성
    const pagesWithBarcodes = await Promise.all(
      layoutConfig.pages.map(async (page) => {
        const componentsWithBarcodes = await Promise.all(
          (Array.isArray(page.components) ? page.components : []).map(async (component) => {
            if (component.type === "barcode") {
              const barcodeImage = await generateBarcodeImage(component);
              return { ...component, barcodeImageBase64: barcodeImage };
            }
            return component;
          })
        );
        return { ...page, components: componentsWithBarcodes };
      })
    );

    // HTML 생성하여 인쇄
    const printHtml = generatePrintHTML(pagesWithBarcodes);

    const printWindow = window.open("", "_blank");
    if (!printWindow) return;

    printWindow.document.write(printHtml);
    printWindow.document.close();
    // print()는 HTML 내 스크립트에서 이미지 로드 완료 후 자동 호출됨
  };

  // 워터마크 HTML 생성 헬퍼 함수
  const generateWatermarkHTML = (watermark: any, pageWidth: number, pageHeight: number): string => {
    if (!watermark?.enabled) return "";

    const opacity = watermark.opacity ?? 0.3;
    const rotation = watermark.rotation ?? -45;

    // 공통 래퍼 스타일
    const wrapperStyle = `position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; overflow: hidden; z-index: 0;`;

    // 텍스트 컨텐츠 생성
    const textContent = watermark.type === "text"
      ? `<span style="font-size: ${watermark.fontSize || 48}px; color: ${watermark.fontColor || "#cccccc"}; font-weight: bold; white-space: nowrap;">${watermark.text || "WATERMARK"}</span>`
      : watermark.imageUrl
        ? `<img src="${watermark.imageUrl.startsWith("data:") ? watermark.imageUrl : getFullImageUrl(watermark.imageUrl)}" style="max-width: 50%; max-height: 50%; object-fit: contain;" />`
        : "";

    if (watermark.style === "diagonal") {
      return `
        <div style="${wrapperStyle}">
          <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(${rotation}deg); opacity: ${opacity};">
            ${textContent}
          </div>
        </div>`;
    }

    if (watermark.style === "center") {
      return `
        <div style="${wrapperStyle}">
          <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); opacity: ${opacity};">
            ${textContent}
          </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;
      const tileItems = Array.from({ length: rows * cols })
        .map(() => `<div style="width: ${tileSize}px; height: ${tileSize}px; display: flex; align-items: center; justify-content: center;">${textContent}</div>`)
        .join("");

      return `
        <div style="${wrapperStyle}">
          <div style="position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; display: flex; flex-wrap: wrap; align-content: flex-start; transform: rotate(${rotation}deg); opacity: ${opacity};">
            ${tileItems}
          </div>
        </div>`;
    }

    return "";
  };

  // 페이지별 컴포넌트 HTML 생성
  const generatePageHTML = (
    pageComponents: any[],
    pageWidth: number,
    pageHeight: number,
    backgroundColor: string,
    pageIndex: number = 0,
    totalPages: number = 1,
    watermark?: any,
  ): string => {
    const componentsHTML = pageComponents
      .map((component) => {
        const queryResult = component.query_id ? getQueryResult(component.query_id) : null;
        let content = "";

        // Text/Label 컴포넌트
        if (component.type === "text" || component.type === "label") {
          const displayValue = getComponentValue(component);
          content = `<div style="font-size: ${component.font_size || 13}px; color: ${component.font_color || "#000000"}; font-weight: ${component.font_weight || "normal"}; text-align: ${component.text_align || "left"}; white-space: pre-wrap;">${displayValue}</div>`;
        }

        // Image 컴포넌트
        else if (component.type === "image" && component.image_url) {
          const imageUrl = component.image_url.startsWith("data:")
            ? component.image_url
            : getFullImageUrl(component.image_url);
          content = `<img src="${imageUrl}" style="width: 100%; height: 100%; object-fit: ${component.object_fit || "contain"};" />`;
        }

        // Divider 컴포넌트
        else if (component.type === "divider") {
          const width = component.orientation === "horizontal" ? "100%" : `${component.line_width || 1}px`;
          const height = component.orientation === "vertical" ? "100%" : `${component.line_width || 1}px`;
          content = `<div style="width: ${width}; height: ${height}; background-color: ${component.line_color || "#000000"};"></div>`;
        }

        // Signature 컴포넌트
        else if (component.type === "signature") {
          const labelPosition = component.label_position || "left";
          const showLabel = component.show_label !== false;
          const labelText = component.label_text || "서명:";
          const imageUrl = component.image_url
            ? component.image_url.startsWith("data:")
              ? component.image_url
              : getFullImageUrl(component.image_url)
            : "";

          if (labelPosition === "left" || labelPosition === "right") {
            content = `
              <div style="display: flex; align-items: center; flex-direction: ${labelPosition === "right" ? "row-reverse" : "row"}; gap: 8px; height: 100%;">
                ${showLabel ? `<div style="font-size: 12px; white-space: nowrap;">${labelText}</div>` : ""}
                <div style="flex: 1; position: relative;">
                  ${imageUrl ? `<img src="${imageUrl}" style="width: 100%; height: 100%; object-fit: ${component.object_fit || "contain"};" />` : ""}
                </div>
              </div>`;
          } else {
            content = `
              <div style="display: flex; flex-direction: column; align-items: center; height: 100%;">
                ${showLabel && labelPosition === "top" ? `<div style="font-size: 12px;">${labelText}</div>` : ""}
                <div style="flex: 1; width: 100%; position: relative;">
                  ${imageUrl ? `<img src="${imageUrl}" style="width: 100%; height: 100%; object-fit: ${component.object_fit || "contain"};" />` : ""}
                </div>
                ${showLabel && labelPosition === "bottom" ? `<div style="font-size: 12px;">${labelText}</div>` : ""}
              </div>`;
          }
        }

        // Stamp 컴포넌트
        else if (component.type === "stamp") {
          const showLabel = component.show_label !== false;
          const labelText = component.label_text || "(인)";
          const personName = component.person_name || "";
          const imageUrl = component.image_url
            ? component.image_url.startsWith("data:")
              ? component.image_url
              : getFullImageUrl(component.image_url)
            : "";

          content = `
            <div style="display: flex; align-items: center; gap: 8px; width: 100%; height: 100%;">
              ${personName ? `<div style="font-size: 12px; white-space: nowrap;">${personName}</div>` : ""}
              <div style="position: relative; flex: 1; height: 100%;">
                ${imageUrl ? `<img src="${imageUrl}" style="width: 100%; height: 100%; object-fit: ${component.object_fit || "contain"}; border-radius: 50%;" />` : ""}
                ${showLabel ? `<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 12px; font-weight: bold; color: #dc2626;">${labelText}</div>` : ""}
              </div>
            </div>`;
        }

        // PageNumber 컴포넌트
        else if (component.type === "pageNumber") {
          const format = component.page_number_format || "number";
          let pageNumberText = "";
          switch (format) {
            case "number":
              pageNumberText = `${pageIndex + 1}`;
              break;
            case "numberTotal":
              pageNumberText = `${pageIndex + 1} / ${totalPages}`;
              break;
            case "koreanNumber":
              pageNumberText = `${pageIndex + 1} 페이지`;
              break;
            default:
              pageNumberText = `${pageIndex + 1}`;
          }
          content = `<div style="display: flex; align-items: center; justify-content: center; height: 100%; font-size: ${component.font_size}px; color: ${component.font_color}; font-weight: ${component.font_weight}; text-align: ${component.text_align};">${pageNumberText}</div>`;
        }

        // Card 컴포넌트
        else if (component.type === "card") {
          const cardTitle = component.card_title || "정보 카드";
          const cardItems = component.card_items || [];
          const labelWidth = component.label_width || 80;
          const showCardTitle = component.show_card_title !== false;
          const titleFontSize = component.title_font_size || 14;
          const labelFontSize = component.label_font_size || 13;
          const valueFontSize = component.value_font_size || 13;
          const titleColor = component.title_color || "#1e40af";
          const labelColor = component.label_color || "#374151";
          const valueColor = component.value_color || "#000000";
          const borderColor = component.border_color || "#e5e7eb";

          // 쿼리 바인딩된 값 가져오기
          const getCardValue = (item: { label: string; value: string; fieldName?: string }) => {
            if (item.fieldName && queryResult && queryResult.rows && queryResult.rows.length > 0) {
              const row = queryResult.rows[0];
              return row[item.fieldName] !== undefined ? String(row[item.fieldName]) : item.value;
            }
            return item.value;
          };

          const itemsHtml = cardItems
            .map(
              (item: { label: string; value: string; fieldName?: string }) => `
              <div style="display: flex; padding: 2px 0;">
                <span style="width: ${labelWidth}px; flex-shrink: 0; font-size: ${labelFontSize}px; color: ${labelColor}; font-weight: 500;">${item.label}</span>
                <span style="flex: 1; font-size: ${valueFontSize}px; color: ${valueColor};">${getCardValue(item)}</span>
              </div>
            `
            )
            .join("");

          content = `
            <div style="display: flex; flex-direction: column; height: 100%; overflow: hidden;">
              ${
                showCardTitle
                  ? `
                <div style="flex-shrink: 0; padding: 4px 8px; font-size: ${titleFontSize}px; font-weight: 600; color: ${titleColor};">
                  ${cardTitle}
                </div>
                <div style="flex-shrink: 0; margin: 0 4px; border-bottom: 1px solid ${borderColor};"></div>
              `
                  : ""
              }
              <div style="flex: 1; padding: 4px 8px; overflow: auto;">
                ${itemsHtml}
              </div>
            </div>`;
        }

        // 계산 컴포넌트
        else if (component.type === "calculation") {
          const calcItems = component.calc_items || [];
          const resultLabel = component.result_label || "합계";
          const calcLabelWidth = component.label_width || 120;
          const calcLabelFontSize = component.label_font_size || 13;
          const calcValueFontSize = component.value_font_size || 13;
          const calcResultFontSize = component.result_font_size || 16;
          const calcLabelColor = component.label_color || "#374151";
          const calcValueColor = component.value_color || "#000000";
          const calcResultColor = component.result_color || "#2563eb";
          const numberFormat = component.number_format || "currency";
          const currencySuffix = component.currency_suffix || "원";
          const borderColor = component.border_color || "#374151";

          // 숫자 포맷팅 함수
          const formatNumber = (num: number): string => {
            if (numberFormat === "none") return String(num);
            if (numberFormat === "comma") return num.toLocaleString();
            if (numberFormat === "currency") return num.toLocaleString() + currencySuffix;
            return String(num);
          };

          // 쿼리 바인딩된 값 가져오기
          const getCalcItemValue = (item: { label: string; value: number | string; operator: string; fieldName?: string }): number => {
            if (item.fieldName && queryResult && queryResult.rows && queryResult.rows.length > 0) {
              const row = queryResult.rows[0];
              const val = row[item.fieldName];
              return typeof val === "number" ? val : parseFloat(String(val)) || 0;
            }
            return typeof item.value === "number" ? item.value : parseFloat(String(item.value)) || 0;
          };

          // 계산 결과 (첫 번째 항목은 기준값, 두 번째부터 연산자 적용)
          let calcResult = 0;
          if (calcItems.length > 0) {
            // 첫 번째 항목은 기준값
            calcResult = getCalcItemValue(calcItems[0] as { label: string; value: number | string; operator: string; fieldName?: string });
            
            // 두 번째 항목부터 연산자 적용
            for (let i = 1; i < calcItems.length; i++) {
              const item = calcItems[i];
              const val = getCalcItemValue(item as { label: string; value: number | string; operator: string; fieldName?: string });
              switch ((item as { operator: string }).operator) {
                case "+":
                  calcResult += val;
                  break;
                case "-":
                  calcResult -= val;
                  break;
                case "x":
                  calcResult *= val;
                  break;
                case "÷":
                  calcResult = val !== 0 ? calcResult / val : calcResult;
                  break;
              }
            }
          }

          const itemsHtml = calcItems
            .map((item: { label: string; value: number | string; operator: string; fieldName?: string }) => {
              const itemValue = getCalcItemValue(item);
              return `
                <div style="display: flex; justify-content: space-between; padding: 4px 8px;">
                  <span style="width: ${calcLabelWidth}px; font-size: ${calcLabelFontSize}px; color: ${calcLabelColor};">${item.label}</span>
                  <span style="font-size: ${calcValueFontSize}px; color: ${calcValueColor}; text-align: right;">${formatNumber(itemValue)}</span>
                </div>
              `;
            })
            .join("");

          content = `
            <div style="display: flex; flex-direction: column; height: 100%;">
              <div style="flex: 1;">
                ${itemsHtml}
              </div>
              <div style="border-top: 1px solid ${borderColor}; margin: 4px 8px;"></div>
              <div style="display: flex; justify-content: space-between; padding: 4px 8px;">
                <span style="width: ${calcLabelWidth}px; font-size: ${calcResultFontSize}px; font-weight: 600; color: ${calcLabelColor};">${resultLabel}</span>
                <span style="font-size: ${calcResultFontSize}px; font-weight: 700; color: ${calcResultColor}; text-align: right;">${formatNumber(calcResult)}</span>
              </div>
            </div>`;
        }

        // 바코드/QR코드 컴포넌트 (인쇄용 - base64 이미지 사용)
        else if (component.type === "barcode") {
          // 바코드 이미지는 미리 생성된 base64 사용 (handlePrint에서 생성)
          const barcodeImage = (component as any).barcodeImageBase64;
          if (barcodeImage) {
            content = `<img src="${barcodeImage}" style="max-width: 100%; max-height: 100%; object-fit: contain;" />`;
          } else {
            content = `<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #666; font-size: 12px;">바코드</div>`;
          }
        }

        // 체크박스 컴포넌트 (인쇄용)
        else if (component.type === "checkbox") {
          const checkboxSize = component.checkbox_size || 18;
          const checkboxColor = component.checkbox_color || "#2563eb";
          const checkboxBorderColor = component.checkbox_border_color || "#6b7280";
          const checkboxLabel = component.checkbox_label || "";
          const checkboxLabelPosition = component.checkbox_label_position || "right";

          // 체크 상태 결정
          let isChecked = component.checkbox_checked === true;
          if (component.checkbox_field_name && queryResult && queryResult.rows && queryResult.rows.length > 0) {
            const val = queryResult.rows[0][component.checkbox_field_name];
            isChecked = val === true || val === "Y" || val === "1" || val === 1 || val === "true";
          }

          const checkboxHTML = `
            <div style="width: ${checkboxSize}px; height: ${checkboxSize}px; border: 2px solid ${isChecked ? checkboxColor : checkboxBorderColor}; border-radius: 2px; background-color: ${isChecked ? checkboxColor : "transparent"}; display: flex; align-items: center; justify-content: center;">
              ${isChecked ? `<svg viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" style="width: ${checkboxSize * 0.7}px; height: ${checkboxSize * 0.7}px;"><polyline points="20 6 9 17 4 12" /></svg>` : ""}
            </div>
          `;

          content = `
            <div style="display: flex; align-items: center; gap: 8px; height: 100%; flex-direction: ${checkboxLabelPosition === "left" ? "row-reverse" : "row"}; ${checkboxLabelPosition === "left" ? "justify-content: flex-end;" : ""}">
              ${checkboxHTML}
              ${checkboxLabel ? `<span style="font-size: 12px;">${checkboxLabel}</span>` : ""}
            </div>
          `;
        }

        // Table 컴포넌트
        else if (component.type === "table" && queryResult && queryResult.rows.length > 0) {
          const columns =
            component.table_columns && component.table_columns.length > 0
              ? component.table_columns
              : queryResult.fields.map((field) => ({
                  field,
                  header: field,
                  align: "left" as const,
                  width: undefined,
                }));

          const tableRows = queryResult.rows
            .map(
              (row) => `
              <tr>
                ${columns.map((col: { field: string; align?: string }) => `<td style="border: ${component.show_border !== false ? "1px solid #d1d5db" : "none"}; padding: 6px 8px; text-align: ${col.align || "left"}; height: ${component.row_height || "auto"}px;">${String(row[col.field] ?? "")}</td>`).join("")}
              </tr>
            `,
            )
            .join("");

          content = `
            <table style="width: 100%; border-collapse: ${component.show_border !== false ? "collapse" : "separate"}; font-size: 12px;">
              <thead style="display: table-header-group; break-inside: avoid; break-after: avoid;">
                <tr style="background-color: ${component.header_background_color || "#f3f4f6"}; color: ${component.header_text_color || "#111827"};">
                  ${columns.map((col: { header: string; align?: string; width?: number }) => `<th style="border: ${component.show_border !== false ? "1px solid #d1d5db" : "none"}; padding: 6px 8px; text-align: ${col.align || "left"}; width: ${col.width ? `${col.width}px` : "auto"}; font-weight: 600;">${col.header}</th>`).join("")}
                </tr>
              </thead>
              <tbody>
                ${tableRows}
              </tbody>
            </table>`;
        }

        // 컴포넌트 값은 px로 저장됨 (캔버스는 pageWidth * MM_TO_PX px)
        // 인쇄용 mm 단위로 변환: px / MM_TO_PX = mm
        const xMm = component.x / MM_TO_PX;
        const yMm = component.y / MM_TO_PX;
        const widthMm = component.width / MM_TO_PX;
        const heightMm = component.height / MM_TO_PX;
        
        return `
          <div style="position: absolute; left: ${xMm}mm; top: ${yMm}mm; width: ${widthMm}mm; height: ${heightMm}mm; background-color: ${component.background_color || "transparent"}; border: ${component.border_width ? `${component.border_width}px solid ${component.border_color}` : "none"}; box-sizing: border-box; overflow: hidden;">
            ${content}
          </div>`;
      })
      .join("");

    const watermarkHTML = generateWatermarkHTML(watermark, pageWidth, pageHeight);

    return `
      <div class="print-page" style="position: relative; width: ${pageWidth}mm; min-height: ${pageHeight}mm; background-color: ${backgroundColor};">
        ${watermarkHTML}
        ${componentsHTML}
      </div>`;
  };

  // 모든 페이지 HTML 생성 (인쇄/PDF용)
  const generatePrintHTML = (pagesWithBarcodes?: any[]): string => {
    const pages = pagesWithBarcodes || layoutConfig.pages;
    const sortedPages = pages.sort((a, b) => a.page_order - b.page_order);
    const totalPages = sortedPages.length;

    const pagesHTML = sortedPages
      .map((page, pageIndex) =>
        generatePageHTML(
          Array.isArray(page.components) ? page.components : [],
          page.width,
          page.height,
          page.background_color,
          pageIndex,
          totalPages,
          layoutConfig.watermark, // 전체 페이지 공유 워터마크
        ),
      )
      .join('<div style="page-break-after: always;"></div>');

    return `
      <html>
        <head>
          <meta charset="UTF-8">
          <title>리포트 인쇄</title>
          <style>
            * { box-sizing: border-box; margin: 0; padding: 0; }
            @page {
              size: A4;
              margin: 0;
            }
            @media print {
              html, body { width: 210mm; height: 297mm; }
              .print-page { page-break-after: always; page-break-inside: avoid; }
              .print-page:last-child { page-break-after: auto; }
            }
            body {
              font-family: 'Malgun Gothic', 'Apple SD Gothic Neo', sans-serif;
              -webkit-print-color-adjust: exact;
              print-color-adjust: exact;
            }
          </style>
        </head>
        <body>
          ${pagesHTML}
          <script>
            window.onload = function() {
              // 이미지 로드 대기 후 인쇄
              const images = document.getElementsByTagName('img');
              if (images.length === 0) {
                setTimeout(() => window.print(), 100);
              } else {
                let loadedCount = 0;
                Array.from(images).forEach(img => {
                  if (img.complete) {
                    loadedCount++;
                  } else {
                    img.onload = () => {
                      loadedCount++;
                      if (loadedCount === images.length) {
                        setTimeout(() => window.print(), 100);
                      }
                    };
                  }
                });
                if (loadedCount === images.length) {
                  setTimeout(() => window.print(), 100);
                }
              }
            }
          </script>
        </body>
      </html>`;
  };

  // PDF 다운로드 (브라우저 인쇄 기능 이용)
  const handleDownloadPDF = async () => {
    // 바코드 이미지 미리 생성
    const pagesWithBarcodes = await Promise.all(
      layoutConfig.pages.map(async (page) => {
        const componentsWithBarcodes = await Promise.all(
          (Array.isArray(page.components) ? page.components : []).map(async (component) => {
            if (component.type === "barcode") {
              const barcodeImage = await generateBarcodeImage(component);
              return { ...component, barcodeImageBase64: barcodeImage };
            }
            return component;
          })
        );
        return { ...page, components: componentsWithBarcodes };
      })
    );

    const printHtml = generatePrintHTML(pagesWithBarcodes);

    const printWindow = window.open("", "_blank");
    if (!printWindow) return;

    printWindow.document.write(printHtml);
    printWindow.document.close();

    toast({
      title: "안내",
      description: "인쇄 대화상자에서 'PDF로 저장'을 선택하세요.",
    });
  };

  // 이미지 URL을 Base64로 변환
  const imageUrlToBase64 = async (url: string): Promise<string> => {
    try {
      // 이미 Base64인 경우 그대로 반환
      if (url.startsWith("data:")) {
        return url;
      }

      // 서버 이미지 URL을 fetch하여 Base64로 변환
      const fullUrl = getFullImageUrl(url);
      const response = await fetch(fullUrl);
      const blob = await response.blob();

      return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onloadend = () => resolve(reader.result as string);
        reader.onerror = reject;
        reader.readAsDataURL(blob);
      });
    } catch (error) {
      console.error("이미지 변환 실패:", error);
      return "";
    }
  };

  // WORD 다운로드 (백엔드 API 사용 - 컴포넌트 데이터 전송)
  const handleDownloadWord = async () => {
    setIsExporting(true);
    try {
      toast({
        title: "처리 중",
        description: "WORD 파일을 생성하고 있습니다...",
      });

      // 이미지 및 바코드를 Base64로 변환하여 컴포넌트 데이터에 포함
      const pagesWithBase64 = await Promise.all(
        layoutConfig.pages.map(async (page) => {
          const componentsWithBase64 = await Promise.all(
            (Array.isArray(page.components) ? page.components : []).map(async (component) => {
              // 이미지가 있는 컴포넌트는 Base64로 변환
              if (component.image_url) {
                try {
                  const base64 = await imageUrlToBase64(component.image_url);
                  return { ...component, imageBase64: base64 };
                } catch {
                  return component;
                }
              }
              // 바코드/QR코드 컴포넌트는 이미지로 변환
              if (component.type === "barcode") {
                try {
                  const barcodeImage = await generateBarcodeImage(component);
                  return { ...component, barcodeImageBase64: barcodeImage };
                } catch {
              return component;
                }
              }
              return component;
            })
                );
          return { ...page, components: componentsWithBase64 };
        })
                );

      // 쿼리 결과 수집
      const queryResults: Record<string, { fields: string[]; rows: Record<string, unknown>[] }> = {};
      for (const page of layoutConfig.pages) {
        const pageComponents = Array.isArray(page.components) ? page.components : [];
        for (const component of pageComponents) {
          if (component.query_id) {
            const result = getQueryResult(component.query_id);
            if (result) {
              queryResults[component.query_id] = result;
            }
          }
        }
      }

      const fileName = reportDetail?.report?.report_name_kor || "리포트";

      // 백엔드 API 호출 (컴포넌트 데이터 전송)
      const { apiClient } = await import("@/lib/api/client");
      const response = await apiClient.post(
        "/admin/reports/export-word",
        {
          layoutConfig: { ...layoutConfig, pages: pagesWithBase64 },
          queryResults,
          fileName,
        },
        { responseType: "blob" },
      );

      // Blob 다운로드
      const blob = new Blob([response.data], {
        type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      });
      const _rpd = new Date();
      const timestamp = `${_rpd.getFullYear()}-${String(_rpd.getMonth() + 1).padStart(2, "0")}-${String(_rpd.getDate()).padStart(2, "0")}`;
      const url = window.URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = url;
      link.download = `${fileName}_${timestamp}.docx`;
      link.click();
      window.URL.revokeObjectURL(url);

      toast({
        title: "성공",
        description: "WORD 파일이 다운로드되었습니다.",
      });
    } catch (error) {
      console.error("WORD 변환 오류:", error);
      const errorMessage = error instanceof Error ? error.message : "WORD 생성에 실패했습니다.";
      toast({
        title: "오류",
        description: errorMessage,
        variant: "destructive",
      });
    } finally {
      setIsExporting(false);
    }
  };

  return (
    <Dialog open={isOpen} onOpenChange={onClose}>
      <DialogContent className="max-w-4xl">
        <DialogHeader>
          <DialogTitle>미리보기</DialogTitle>
          <DialogDescription>
            현재 레이아웃의 미리보기입니다. 인쇄하거나 파일로 다운로드할 수 있습니다.
          </DialogDescription>
        </DialogHeader>

        {/* 미리보기 영역 - 모든 페이지 표시 */}
        <div className="max-h-[500px] overflow-auto rounded border bg-muted p-4">
          <div className="space-y-4">
            {layoutConfig.pages
              .sort((a, b) => a.page_order - b.page_order)
              .map((page) => (
                <div key={page.page_id} className="relative">
                  {/* 페이지 컨텐츠 */}
                  <div
                    className="relative mx-auto overflow-hidden shadow-lg"
                    style={{
                      width: `${page.width * 4}px`,
                      minHeight: `${page.height * 4}px`,
                      backgroundColor: page.background_color,
                    }}
                  >
                    {/* 워터마크 렌더링 (전체 페이지 공유) */}
                    {layoutConfig.watermark?.enabled && (
                      <PreviewWatermarkLayer
                        watermark={layoutConfig.watermark}
                        pageWidth={page.width}
                        pageHeight={page.height}
                      />
                    )}
                    {(Array.isArray(page.components) ? page.components : []).map((component) => {
                      const displayValue = getComponentValue(component);
                      const queryResult = component.query_id ? getQueryResult(component.query_id) : null;

                      return (
                        <div
                          key={component.id}
                          className="absolute"
                          style={{
                            left: `${component.x}px`,
                            top: `${component.y}px`,
                            width: `${component.width}px`,
                            height: `${component.height}px`,
                            backgroundColor: component.background_color,
                            border: component.border_width
                              ? `${component.border_width}px solid ${component.border_color}`
                              : "none",
                            padding: "8px",
                          }}
                        >
                          {component.type === "text" && (
                            <div
                              style={{
                                fontSize: `${component.font_size}px`,
                                color: component.font_color,
                                fontWeight: component.font_weight,
                                textAlign: component.text_align as "left" | "center" | "right",
                                whiteSpace: "pre-wrap",
                              }}
                            >
                              {displayValue}
                            </div>
                          )}

                          {component.type === "label" && (
                            <div
                              style={{
                                fontSize: `${component.font_size}px`,
                                color: component.font_color,
                                fontWeight: component.font_weight,
                                textAlign: component.text_align as "left" | "center" | "right",
                                whiteSpace: "pre-wrap",
                              }}
                            >
                              {displayValue}
                            </div>
                          )}

                          {component.type === "table" && queryResult && queryResult.rows.length > 0 ? (
                            (() => {
                              // tableColumns가 없으면 자동 생성
                              const columns =
                                component.table_columns && component.table_columns.length > 0
                                  ? component.table_columns
                                  : queryResult.fields.map((field) => ({
                                      field,
                                      header: field,
                                      align: "left" as const,
                                      width: undefined,
                                    }));

                              return (
                                <table
                                  style={{
                                    width: "100%",
                                    borderCollapse: component.show_border !== false ? "collapse" : "separate",
                                    fontSize: "12px",
                                  }}
                                >
                                  <thead>
                                    <tr
                                      style={{
                                        backgroundColor: component.header_background_color || "#f3f4f6",
                                        color: component.header_text_color || "#111827",
                                      }}
                                    >
                                      {columns.map((col) => (
                                        <th
                                          key={col.field}
                                          style={{
                                            border: component.show_border !== false ? "1px solid #d1d5db" : "none",
                                            padding: "6px 8px",
                                            textAlign: col.align || "left",
                                            width: col.width ? `${col.width}px` : "auto",
                                            fontWeight: "600",
                                          }}
                                        >
                                          {col.header}
                                        </th>
                                      ))}
                                    </tr>
                                  </thead>
                                  <tbody>
                                    {queryResult.rows.map((row, idx) => (
                                      <tr key={idx}>
                                        {columns.map((col) => (
                                          <td
                                            key={col.field}
                                            style={{
                                              border: component.show_border !== false ? "1px solid #d1d5db" : "none",
                                              padding: "6px 8px",
                                              textAlign: col.align || "left",
                                              height: component.row_height ? `${component.row_height}px` : "auto",
                                            }}
                                          >
                                            {String(row[col.field] ?? "")}
                                          </td>
                                        ))}
                                      </tr>
                                    ))}
                                  </tbody>
                                </table>
                              );
                            })()
                          ) : component.type === "table" ? (
                            <div className="text-xs text-muted-foreground/70">쿼리를 실행해주세요</div>
                          ) : null}

                          {component.type === "image" && component.image_url && (
                            <img
                              src={getFullImageUrl(component.image_url)}
                              alt="이미지"
                              style={{
                                width: "100%",
                                height: "100%",
                                objectFit: component.object_fit || "contain",
                              }}
                            />
                          )}

                          {component.type === "divider" && (
                            <div
                              style={{
                                width:
                                  component.orientation === "horizontal" ? "100%" : `${component.line_width || 1}px`,
                                height: component.orientation === "vertical" ? "100%" : `${component.line_width || 1}px`,
                                backgroundColor: component.line_color || "#000000",
                                ...(component.line_style === "dashed" && {
                                  backgroundImage: `repeating-linear-gradient(
                            ${component.orientation === "horizontal" ? "90deg" : "0deg"},
                            ${component.line_color || "#000000"} 0px,
                            ${component.line_color || "#000000"} 10px,
                            transparent 10px,
                            transparent 20px
                          )`,
                                  backgroundColor: "transparent",
                                }),
                                ...(component.line_style === "dotted" && {
                                  backgroundImage: `repeating-linear-gradient(
                            ${component.orientation === "horizontal" ? "90deg" : "0deg"},
                            ${component.line_color || "#000000"} 0px,
                            ${component.line_color || "#000000"} 3px,
                            transparent 3px,
                            transparent 10px
                          )`,
                                  backgroundColor: "transparent",
                                }),
                                ...(component.line_style === "double" && {
                                  boxShadow:
                                    component.orientation === "horizontal"
                                      ? `0 ${(component.line_width || 1) * 2}px 0 0 ${component.line_color || "#000000"}`
                                      : `${(component.line_width || 1) * 2}px 0 0 0 ${component.line_color || "#000000"}`,
                                }),
                              }}
                            />
                          )}

                          {component.type === "signature" && (
                            <div
                              style={{
                                display: "flex",
                                gap: "8px",
                                flexDirection:
                                  component.label_position === "top" || component.label_position === "bottom"
                                    ? "column"
                                    : "row",
                                ...(component.label_position === "right" || component.label_position === "bottom"
                                  ? {
                                      flexDirection:
                                        component.label_position === "right" ? "row-reverse" : "column-reverse",
                                    }
                                  : {}),
                              }}
                            >
                              {component.show_label !== false && (
                                <div
                                  style={{
                                    display: "flex",
                                    alignItems: "center",
                                    justifyContent: "center",
                                    fontSize: "12px",
                                    fontWeight: "500",
                                    minWidth:
                                      component.label_position === "left" || component.label_position === "right"
                                        ? "40px"
                                        : "auto",
                                  }}
                                >
                                  {component.label_text || "서명:"}
                                </div>
                              )}
                              <div style={{ flex: 1, position: "relative" }}>
                                {component.image_url && (
                                  <img
                                    src={getFullImageUrl(component.image_url)}
                                    alt="서명"
                                    style={{
                                      width: "100%",
                                      height: "100%",
                                      objectFit: component.object_fit || "contain",
                                    }}
                                  />
                                )}
                              </div>
                            </div>
                          )}

                          {component.type === "stamp" && (
                            <div
                              style={{
                                display: "flex",
                                gap: "8px",
                                width: "100%",
                                height: "100%",
                              }}
                            >
                              {component.person_name && (
                                <div
                                  style={{
                                    display: "flex",
                                    alignItems: "center",
                                    fontSize: "12px",
                                    fontWeight: "500",
                                  }}
                                >
                                  {component.person_name}
                                </div>
                              )}
                              <div
                                style={{
                                  position: "relative",
                                  flex: 1,
                                }}
                              >
                                {component.image_url && (
                                  <img
                                    src={getFullImageUrl(component.image_url)}
                                    alt="도장"
                                    style={{
                                      width: "100%",
                                      height: "100%",
                                      objectFit: component.object_fit || "contain",
                                    }}
                                  />
                                )}
                                {component.show_label !== false && (
                                  <div
                                    style={{
                                      position: "absolute",
                                      top: "0",
                                      left: "0",
                                      width: "100%",
                                      height: "100%",
                                      display: "flex",
                                      alignItems: "center",
                                      justifyContent: "center",
                                      fontSize: "12px",
                                      fontWeight: "500",
                                      pointerEvents: "none",
                                    }}
                                  >
                                    {component.label_text || "(인)"}
                                  </div>
                                )}
                              </div>
                            </div>
                          )}

                          {component.type === "pageNumber" && (() => {
                            const format = component.page_number_format || "number";
                            const pageIndex = layoutConfig.pages
                              .sort((a, b) => a.page_order - b.page_order)
                              .findIndex((p) => p.page_id === page.page_id);
                            const totalPages = layoutConfig.pages.length;
                            let pageNumberText = "";
                            switch (format) {
                              case "number":
                                pageNumberText = `${pageIndex + 1}`;
                                break;
                              case "numberTotal":
                                pageNumberText = `${pageIndex + 1} / ${totalPages}`;
                                break;
                              case "koreanNumber":
                                pageNumberText = `${pageIndex + 1} 페이지`;
                                break;
                              default:
                                pageNumberText = `${pageIndex + 1}`;
                            }
                            return (
                              <div
                                style={{
                                  display: "flex",
                                  alignItems: "center",
                                  justifyContent: "center",
                                  width: "100%",
                                  height: "100%",
                                  fontSize: `${component.font_size}px`,
                                  color: component.font_color,
                                  fontWeight: component.font_weight,
                                }}
                              >
                                {pageNumberText}
                              </div>
                            );
                          })()}

                          {/* Card 컴포넌트 */}
                          {component.type === "card" && (() => {
                            const cardTitle = component.card_title || "정보 카드";
                            const cardItems = component.card_items || [];
                            const labelWidth = component.label_width || 80;
                            const showCardTitle = component.show_card_title !== false;
                            const titleFontSize = component.title_font_size || 14;
                            const labelFontSize = component.label_font_size || 13;
                            const valueFontSize = component.value_font_size || 13;
                            const titleColor = component.title_color || "#1e40af";
                            const labelColor = component.label_color || "#374151";
                            const valueColor = component.value_color || "#000000";
                            const borderColor = component.border_color || "#e5e7eb";

                            // 쿼리 바인딩된 값 가져오기
                            const getCardValue = (item: { label: string; value: string; fieldName?: string }) => {
                              if (item.fieldName && component.query_id) {
                                const qResult = getQueryResult(component.query_id);
                                if (qResult && qResult.rows && qResult.rows.length > 0) {
                                  const row = qResult.rows[0];
                                  return row[item.fieldName] !== undefined ? String(row[item.fieldName]) : item.value;
                                }
                              }
                              return item.value;
                            };

                            return (
                              <div
                                style={{
                                  display: "flex",
                                  flexDirection: "column",
                                  height: "100%",
                                  overflow: "hidden",
                                }}
                              >
                                {showCardTitle && (
                                  <>
                                    <div
                                      style={{
                                        flexShrink: 0,
                                        padding: "4px 8px",
                                        fontSize: `${titleFontSize}px`,
                                        fontWeight: 600,
                                        color: titleColor,
                                      }}
                                    >
                                      {cardTitle}
                                    </div>
                                    <div
                                      style={{
                                        flexShrink: 0,
                                        margin: "0 4px",
                                        borderBottom: `1px solid ${borderColor}`,
                                      }}
                                    />
                                  </>
                                )}
                                <div style={{ flex: 1, padding: "4px 8px", overflow: "auto" }}>
                                  {cardItems.map((item: { label: string; value: string; fieldName?: string }, idx: number) => (
                                    <div key={idx} style={{ display: "flex", padding: "2px 0" }}>
                                      <span
                                        style={{
                                          width: `${labelWidth}px`,
                                          flexShrink: 0,
                                          fontSize: `${labelFontSize}px`,
                                          color: labelColor,
                                          fontWeight: 500,
                                        }}
                                      >
                                        {item.label}
                                      </span>
                                      <span
                                        style={{
                                          flex: 1,
                                          fontSize: `${valueFontSize}px`,
                                          color: valueColor,
                                        }}
                                      >
                                        {getCardValue(item)}
                                      </span>
                                    </div>
                                  ))}
                                </div>
                              </div>
                            );
                          })()}

                          {/* 계산 컴포넌트 */}
                          {component.type === "calculation" && (() => {
                            const calcItems = component.calc_items || [];
                            const resultLabel = component.result_label || "합계";
                            const calcLabelWidth = component.label_width || 120;
                            const calcLabelFontSize = component.label_font_size || 13;
                            const calcValueFontSize = component.value_font_size || 13;
                            const calcResultFontSize = component.result_font_size || 16;
                            const calcLabelColor = component.label_color || "#374151";
                            const calcValueColor = component.value_color || "#000000";
                            const calcResultColor = component.result_color || "#2563eb";
                            const numberFormat = component.number_format || "currency";
                            const currencySuffix = component.currency_suffix || "원";
                            const borderColor = component.border_color || "#374151";

                            // 숫자 포맷팅 함수
                            const formatNumber = (num: number): string => {
                              if (numberFormat === "none") return String(num);
                              if (numberFormat === "comma") return num.toLocaleString();
                              if (numberFormat === "currency") return num.toLocaleString() + currencySuffix;
                              return String(num);
                            };

                            // 쿼리 바인딩된 값 가져오기
                            const getCalcItemValue = (item: { label: string; value: number | string; operator: string; fieldName?: string }): number => {
                              if (item.fieldName && component.query_id) {
                                const qResult = getQueryResult(component.query_id);
                                if (qResult && qResult.rows && qResult.rows.length > 0) {
                                  const row = qResult.rows[0];
                                  const val = row[item.fieldName];
                                  return typeof val === "number" ? val : parseFloat(String(val)) || 0;
                                }
                              }
                              return typeof item.value === "number" ? item.value : parseFloat(String(item.value)) || 0;
                            };

                            // 계산 결과 (첫 번째 항목은 기준값, 두 번째부터 연산자 적용)
                            let calcResult = 0;
                            if (calcItems.length > 0) {
                              // 첫 번째 항목은 기준값
                              calcResult = getCalcItemValue(calcItems[0] as { label: string; value: number | string; operator: string; fieldName?: string });
                              
                              // 두 번째 항목부터 연산자 적용
                              for (let i = 1; i < calcItems.length; i++) {
                                const item = calcItems[i];
                                const val = getCalcItemValue(item as { label: string; value: number | string; operator: string; fieldName?: string });
                                switch ((item as { operator: string }).operator) {
                                  case "+":
                                    calcResult += val;
                                    break;
                                  case "-":
                                    calcResult -= val;
                                    break;
                                  case "x":
                                    calcResult *= val;
                                    break;
                                  case "÷":
                                    calcResult = val !== 0 ? calcResult / val : calcResult;
                                    break;
                                }
                              }
                            }

                            return (
                              <div
                                style={{
                                  display: "flex",
                                  flexDirection: "column",
                                  height: "100%",
                                }}
                              >
                                <div style={{ flex: 1 }}>
                                  {calcItems.map((item: { label: string; value: number | string; operator: string; fieldName?: string }, idx: number) => {
                                    const itemValue = getCalcItemValue(item);
                                    return (
                                      <div key={idx} style={{ display: "flex", justifyContent: "space-between", padding: "4px 8px" }}>
                                        <span
                                          style={{
                                            width: `${calcLabelWidth}px`,
                                            fontSize: `${calcLabelFontSize}px`,
                                            color: calcLabelColor,
                                          }}
                                        >
                                          {item.label}
                                        </span>
                                        <span
                                          style={{
                                            fontSize: `${calcValueFontSize}px`,
                                            color: calcValueColor,
                                            textAlign: "right",
                                          }}
                                        >
                                          {formatNumber(itemValue)}
                                        </span>
                                      </div>
                                    );
                                  })}
                                </div>
                                <div style={{ borderTop: `1px solid ${borderColor}`, margin: "4px 8px" }} />
                                <div style={{ display: "flex", justifyContent: "space-between", padding: "4px 8px" }}>
                                  <span
                                    style={{
                                      width: `${calcLabelWidth}px`,
                                      fontSize: `${calcResultFontSize}px`,
                                      fontWeight: 600,
                                      color: calcLabelColor,
                                    }}
                                  >
                                    {resultLabel}
                                  </span>
                                  <span
                                    style={{
                                      fontSize: `${calcResultFontSize}px`,
                                      fontWeight: 700,
                                      color: calcResultColor,
                                      textAlign: "right",
                                    }}
                                  >
                                    {formatNumber(calcResult)}
                                  </span>
                                </div>
                              </div>
                            );
                          })()}

                          {/* 바코드/QR코드 컴포넌트 */}
                          {component.type === "barcode" && (
                            <BarcodePreview component={component} getQueryResult={getQueryResult} />
                          )}

                          {/* 체크박스 컴포넌트 */}
                          {component.type === "checkbox" && (() => {
                            const checkboxSize = component.checkbox_size || 18;
                            const checkboxColor = component.checkbox_color || "#2563eb";
                            const checkboxBorderColor = component.checkbox_border_color || "#6b7280";
                            const checkboxLabel = component.checkbox_label || "";
                            const checkboxLabelPosition = component.checkbox_label_position || "right";

                            // 체크 상태 결정
                            let isChecked = component.checkbox_checked === true;
                            if (component.checkbox_field_name && component.query_id) {
                              const qResult = getQueryResult(component.query_id);
                              if (qResult && qResult.rows && qResult.rows.length > 0) {
                                const val = qResult.rows[0][component.checkbox_field_name];
                                isChecked = val === true || val === "Y" || val === "1" || val === 1 || val === "true";
                              }
                            }

                            return (
                              <div
                                style={{
                                  display: "flex",
                                  alignItems: "center",
                                  gap: "8px",
                                  height: "100%",
                                  flexDirection: checkboxLabelPosition === "left" ? "row-reverse" : "row",
                                  justifyContent: checkboxLabelPosition === "left" ? "flex-end" : "flex-start",
                                }}
                              >
                                <div
                                  style={{
                                    width: `${checkboxSize}px`,
                                    height: `${checkboxSize}px`,
                                    borderRadius: "2px",
                                    border: `2px solid ${isChecked ? checkboxColor : checkboxBorderColor}`,
                                    backgroundColor: isChecked ? checkboxColor : "transparent",
                                    display: "flex",
                                    alignItems: "center",
                                    justifyContent: "center",
                                  }}
                                >
                                  {isChecked && (
                                    <svg
                                      viewBox="0 0 24 24"
                                      fill="none"
                                      stroke="white"
                                      strokeWidth="3"
                                      strokeLinecap="round"
                                      strokeLinejoin="round"
                                      style={{
                                        width: `${checkboxSize * 0.7}px`,
                                        height: `${checkboxSize * 0.7}px`,
                                      }}
                                    >
                                      <polyline points="20 6 9 17 4 12" />
                                    </svg>
                                  )}
                                </div>
                                {checkboxLabel && (
                                  <span style={{ fontSize: "12px" }}>{checkboxLabel}</span>
                                )}
                              </div>
                            );
                          })()}
                        </div>
                      );
                    })}
                  </div>
                </div>
              ))}
          </div>
        </div>

        <DialogFooter>
          <Button variant="outline" onClick={onClose} disabled={isExporting}>
            닫기
          </Button>
          <Button variant="outline" onClick={handlePrint} disabled={isExporting} className="gap-2">
            <Printer className="h-4 w-4" />
            인쇄
          </Button>
          <Button onClick={handleDownloadPDF} className="gap-2">
            <FileDown className="h-4 w-4" />
            PDF
          </Button>
          <Button onClick={handleDownloadWord} disabled={isExporting} variant="secondary" className="gap-2">
            <FileText className="h-4 w-4" />
            {isExporting ? "생성 중..." : "WORD"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
