"use client";

import { useRef, useState, useEffect } from "react";
import JsBarcode from "jsbarcode";
import QRCode from "qrcode";
import type { BarcodeRendererProps as BarcodeCanvasRendererProps } from "./types";

interface BarcodeProps {
  value: string;
  format: string;
  width: number;
  height: number;
  displayValue: boolean;
  lineColor: string;
  background: string;
  margin: number;
}

function Barcode1D({ value, format, width, height, displayValue, lineColor, background, margin }: BarcodeProps) {
  const svgRef = useRef<SVGSVGElement>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (!svgRef.current || !value) return;
    setError(null);

    try {
      let isValid = true;
      let errorMsg = "";
      const trimmedValue = value.trim();

      if (format === "EAN13" && !/^\d{12,13}$/.test(trimmedValue)) {
        isValid = false;
        errorMsg = "EAN-13: 12~13자리 숫자 필요";
      } else if (format === "EAN8" && !/^\d{7,8}$/.test(trimmedValue)) {
        isValid = false;
        errorMsg = "EAN-8: 7~8자리 숫자 필요";
      } else if (format === "UPC" && !/^\d{11,12}$/.test(trimmedValue)) {
        isValid = false;
        errorMsg = "UPC: 11~12자리 숫자 필요";
      }

      if (!isValid) {
        setError(errorMsg);
        return;
      }

      const barcodeFormat = format.toLowerCase();
      const bgColor = background === "transparent" ? "" : background;

      JsBarcode(svgRef.current, trimmedValue, {
        format: barcodeFormat,
        width: 2,
        height: Math.max(30, height - (displayValue ? 30 : 10)),
        displayValue,
        lineColor,
        background: bgColor,
        margin,
        fontSize: 12,
        textMargin: 2,
      });
    } catch (err: any) {
      setError(err?.message || "바코드 생성 실패");
    }
  }, [value, format, width, height, displayValue, lineColor, background, margin]);

  return (
    <div className="relative h-full w-full">
      <svg ref={svgRef} className={`max-h-full max-w-full ${error ? "hidden" : ""}`} />
      {error && (
        <div className="absolute inset-0 flex flex-col items-center justify-center text-xs text-red-500">
          <span>{error}</span>
          <span className="mt-1 text-gray-400">{value}</span>
        </div>
      )}
    </div>
  );
}

interface QRProps {
  value: string;
  size: number;
  fgColor: string;
  bgColor: string;
  level: "L" | "M" | "Q" | "H";
}

function QR({ value, size, fgColor, bgColor, level }: QRProps) {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (!canvasRef.current || !value) return;
    setError(null);
    const lightColor = bgColor === "transparent" ? "#ffffff" : bgColor;

    QRCode.toCanvas(
      canvasRef.current,
      value,
      {
        width: Math.max(50, size),
        margin: 2,
        color: { dark: fgColor, light: lightColor },
        errorCorrectionLevel: level,
      },
      (err) => {
        if (err) setError(err.message || "QR코드 생성 실패");
      },
    );
  }, [value, size, fgColor, bgColor, level]);

  return (
    <div className="relative h-full w-full">
      <canvas ref={canvasRef} className={`max-h-full max-w-full ${error ? "hidden" : ""}`} />
      {error && (
        <div className="absolute inset-0 flex flex-col items-center justify-center text-xs text-red-500">
          <span>{error}</span>
          <span className="mt-1 text-gray-400">{value}</span>
        </div>
      )}
    </div>
  );
}

export function BarcodeCanvasRenderer({ component, getQueryResult }: BarcodeCanvasRendererProps) {
  const barcodeType = component.barcodeType || "CODE128";
  const showBarcodeText = component.showBarcodeText !== false;
  const barcodeColor = component.barcodeColor || "#000000";
  const barcodeBackground = component.barcodeBackground || "transparent";
  const barcodeMargin = component.barcodeMargin ?? 10;
  const qrErrorLevel = component.qrErrorCorrectionLevel || "M";

  const getBarcodeValue = (): string => {
    if (
      barcodeType === "QR" &&
      component.qrUseMultiField &&
      component.qrDataFields &&
      component.qrDataFields.length > 0 &&
      component.queryId
    ) {
      const queryResult = getQueryResult(component.queryId);
      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) => {
              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) => {
          if (field.fieldName && field.label) {
            const val = row[field.fieldName];
            jsonData[field.label] = val !== null && val !== undefined ? String(val) : "";
          }
        });
        return JSON.stringify(jsonData);
      }
      const placeholderData: Record<string, string> = {};
      component.qrDataFields.forEach((field) => {
        if (field.label) placeholderData[field.label] = `{${field.fieldName || "field"}}`;
      });
      return component.qrIncludeAllRows
        ? JSON.stringify([placeholderData, { "...": "..." }])
        : JSON.stringify(placeholderData);
    }

    if (component.barcodeFieldName && component.queryId) {
      const queryResult = getQueryResult(component.queryId);
      if (queryResult && queryResult.rows && queryResult.rows.length > 0) {
        if (barcodeType === "QR" && 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);
      }
      if (barcodeType === "QR" && component.qrIncludeAllRows) {
        return JSON.stringify([`{${component.barcodeFieldName}}`, "..."]);
      }
      return `{${component.barcodeFieldName}}`;
    }
    return component.barcodeValue || "SAMPLE123";
  };

  const barcodeValue = getBarcodeValue();
  const isQR = barcodeType === "QR";

  return (
    <div
      className="flex h-full w-full items-center justify-center overflow-hidden"
      style={{ backgroundColor: barcodeBackground }}
    >
      {isQR ? (
        <QR
          value={barcodeValue}
          size={Math.min(component.width, component.height) - 10}
          fgColor={barcodeColor}
          bgColor={barcodeBackground}
          level={qrErrorLevel}
        />
      ) : (
        <Barcode1D
          value={barcodeValue}
          format={barcodeType}
          width={component.width}
          height={component.height}
          displayValue={showBarcodeText}
          lineColor={barcodeColor}
          background={barcodeBackground}
          margin={barcodeMargin}
        />
      )}
    </div>
  );
}
