"use client";

import React, { useState, useCallback, useMemo, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Checkbox } from "@/components/ui/checkbox";
import { ScanLine } from "lucide-react";
import { PopComponentRegistry } from "@/lib/registry/PopComponentRegistry";
import { usePopEvent } from "@/hooks/pop/usePopEvent";
import { BarcodeScanModal } from "@/components/common/BarcodeScanModal";
import type {
  PopDataConnection,
  PopComponentDefinition,
} from "@/components/pop/designer/types/pop-layout";

// ========================================
// 타입 정의
// ========================================

export interface ScanFieldMapping {
  sourceKey: string;
  outputIndex: number;
  label: string;
  targetComponentId: string;
  targetFieldName: string;
  enabled: boolean;
}

export interface PopScannerConfig {
  barcodeFormat: "all" | "1d" | "2d";
  autoSubmit: boolean;
  showLastScan: boolean;
  buttonLabel: string;
  buttonVariant: "default" | "outline" | "secondary";
  parseMode: "none" | "auto" | "json";
  fieldMappings: ScanFieldMapping[];
}

// 연결된 컴포넌트의 필드 정보
interface ConnectedFieldInfo {
  componentId: string;
  componentName: string;
  componentType: string;
  fieldName: string;
  fieldLabel: string;
}

const DEFAULT_SCANNER_CONFIG: PopScannerConfig = {
  barcodeFormat: "all",
  autoSubmit: true,
  showLastScan: false,
  buttonLabel: "스캔",
  buttonVariant: "default",
  parseMode: "none",
  fieldMappings: [],
};

// ========================================
// 파싱 유틸리티
// ========================================

function tryParseJson(raw: string): Record<string, string> | null {
  try {
    const parsed = JSON.parse(raw);
    if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
      const result: Record<string, string> = {};
      for (const [k, v] of Object.entries(parsed)) {
        result[k] = String(v);
      }
      return result;
    }
  } catch {
    // JSON이 아닌 경우
  }
  return null;
}

function parseScanResult(
  raw: string,
  mode: PopScannerConfig["parseMode"]
): Record<string, string> | null {
  if (mode === "none") return null;
  return tryParseJson(raw);
}

// ========================================
// 연결된 컴포넌트 필드 추출
// ========================================

function getConnectedFields(
  componentId?: string,
  connections?: PopDataConnection[],
  allComponents?: PopComponentDefinition[],
): ConnectedFieldInfo[] {
  if (!componentId || !connections || !allComponents) return [];

  const targetIds = connections
    .filter((c) => c.sourceComponent === componentId)
    .map((c) => c.targetComponent);

  const uniqueTargetIds = [...new Set(targetIds)];
  const fields: ConnectedFieldInfo[] = [];

  for (const tid of uniqueTargetIds) {
    const comp = allComponents.find((c) => c.id === tid);
    if (!comp?.config) continue;
    const compCfg = comp.config as Record<string, unknown>;
    const compType = comp.type || "";
    const compName = (comp as Record<string, unknown>).label as string || comp.type || tid;

    // pop-search: filterColumns (복수) 또는 modalConfig.valueField 또는 fieldName (단일)
    const filterCols = compCfg.filterColumns as string[] | undefined;
    const modalCfg = compCfg.modalConfig as { valueField?: string; displayField?: string } | undefined;

    if (Array.isArray(filterCols) && filterCols.length > 0) {
      for (const col of filterCols) {
        fields.push({
          componentId: tid,
          componentName: compName,
          componentType: compType,
          fieldName: col,
          fieldLabel: col,
        });
      }
    } else if (modalCfg?.valueField) {
      fields.push({
        componentId: tid,
        componentName: compName,
        componentType: compType,
        fieldName: modalCfg.valueField,
        fieldLabel: (compCfg.placeholder as string) || modalCfg.valueField,
      });
    } else if (compCfg.fieldName && typeof compCfg.fieldName === "string") {
      fields.push({
        componentId: tid,
        componentName: compName,
        componentType: compType,
        fieldName: compCfg.fieldName,
        fieldLabel: (compCfg.placeholder as string) || compCfg.fieldName as string,
      });
    }

    // pop-field: sections 내 fields
    const sections = compCfg.sections as Array<{
      fields?: Array<{ id: string; fieldName?: string; labelText?: string }>;
    }> | undefined;
    if (Array.isArray(sections)) {
      for (const section of sections) {
        for (const f of section.fields ?? []) {
          if (f.fieldName) {
            fields.push({
              componentId: tid,
              componentName: compName,
              componentType: compType,
              fieldName: f.fieldName,
              fieldLabel: f.labelText || f.fieldName,
            });
          }
        }
      }
    }
  }

  return fields;
}

// ========================================
// 메인 컴포넌트
// ========================================

interface PopScannerComponentProps {
  config?: PopScannerConfig;
  label?: string;
  isDesignMode?: boolean;
  screenId?: string;
  componentId?: string;
}

function PopScannerComponent({
  config,
  isDesignMode,
  screenId,
  componentId,
}: PopScannerComponentProps) {
  const cfg = { ...DEFAULT_SCANNER_CONFIG, ...(config || {}) };
  const { publish } = usePopEvent(screenId || "");
  const [lastScan, setLastScan] = useState("");
  const [modalOpen, setModalOpen] = useState(false);

  const handleScanSuccess = useCallback(
    (barcode: string) => {
      setLastScan(barcode);
      setModalOpen(false);

      if (!componentId) return;

      if (cfg.parseMode === "none") {
        publish(`__comp_output__${componentId}__scan_value`, barcode);
        return;
      }

      const parsed = parseScanResult(barcode, cfg.parseMode);

      if (!parsed) {
        publish(`__comp_output__${componentId}__scan_value`, barcode);
        return;
      }

      if (cfg.parseMode === "auto") {
        publish("scan_auto_fill", parsed);
        publish(`__comp_output__${componentId}__scan_value`, barcode);
        return;
      }

      if (cfg.fieldMappings.length === 0) {
        publish(`__comp_output__${componentId}__scan_value`, barcode);
        return;
      }

      for (const mapping of cfg.fieldMappings) {
        if (!mapping.enabled) continue;
        const value = parsed[mapping.sourceKey];
        if (value === undefined) continue;

        publish(
          `__comp_output__${componentId}__scan_field_${mapping.outputIndex}`,
          value
        );

        if (mapping.targetComponentId && mapping.targetFieldName) {
          publish(
            `__comp_input__${mapping.targetComponentId}__set_value`,
            { fieldName: mapping.targetFieldName, value }
          );
        }
      }
    },
    [componentId, publish, cfg.parseMode, cfg.fieldMappings],
  );

  const handleClick = useCallback(() => {
    if (isDesignMode) return;
    setModalOpen(true);
  }, [isDesignMode]);

  return (
    <div className="flex h-full w-full items-center justify-center">
      <Button
        variant={cfg.buttonVariant}
        size="icon"
        onClick={handleClick}
        className="h-full w-full rounded-md transition-transform active:scale-95"
      >
        <ScanLine className="h-7! w-7!" />
        <span className="sr-only">{cfg.buttonLabel}</span>
      </Button>

      {cfg.showLastScan && lastScan && (
        <div className="absolute inset-x-0 bottom-0 truncate bg-background/80 px-1 text-center text-[8px] text-muted-foreground backdrop-blur-sm">
          {lastScan}
        </div>
      )}

      {!isDesignMode && (
        <BarcodeScanModal
          open={modalOpen}
          onOpenChange={setModalOpen}
          barcodeFormat={cfg.barcodeFormat}
          autoSubmit={cfg.autoSubmit}
          onScanSuccess={handleScanSuccess}
        />
      )}
    </div>
  );
}

// ========================================
// 설정 패널
// ========================================

const FORMAT_LABELS: Record<string, string> = {
  all: "모든 형식",
  "1d": "1D 바코드",
  "2d": "2D 바코드 (QR)",
};

const VARIANT_LABELS: Record<string, string> = {
  default: "기본 (Primary)",
  outline: "외곽선 (Outline)",
  secondary: "보조 (Secondary)",
};

const PARSE_MODE_LABELS: Record<string, string> = {
  none: "없음 (단일 값)",
  auto: "자동 (검색 필드명과 매칭)",
  json: "JSON (수동 매핑)",
};

interface PopScannerConfigPanelProps {
  config: PopScannerConfig;
  onUpdate: (config: PopScannerConfig) => void;
  allComponents?: PopComponentDefinition[];
  connections?: PopDataConnection[];
  componentId?: string;
}

function PopScannerConfigPanel({
  config,
  onUpdate,
  allComponents,
  connections,
  componentId,
}: PopScannerConfigPanelProps) {
  const cfg = { ...DEFAULT_SCANNER_CONFIG, ...config };

  const update = (partial: Partial<PopScannerConfig>) => {
    onUpdate({ ...cfg, ...partial });
  };

  const connectedFields = useMemo(
    () => getConnectedFields(componentId, connections, allComponents),
    [componentId, connections, allComponents],
  );

  const buildMappingsFromFields = useCallback(
    (fields: ConnectedFieldInfo[], existing: ScanFieldMapping[]): ScanFieldMapping[] => {
      return fields.map((f, i) => {
        const prev = existing.find(
          (m) => m.targetComponentId === f.componentId && m.targetFieldName === f.fieldName
        );
        return {
          sourceKey: prev?.sourceKey ?? f.fieldName,
          outputIndex: i,
          label: f.fieldLabel,
          targetComponentId: f.componentId,
          targetFieldName: f.fieldName,
          enabled: prev?.enabled ?? true,
        };
      });
    },
    [],
  );

  const toggleMapping = (fieldName: string, componentId: string) => {
    const updated = cfg.fieldMappings.map((m) =>
      m.targetFieldName === fieldName && m.targetComponentId === componentId
        ? { ...m, enabled: !m.enabled }
        : m
    );
    update({ fieldMappings: updated });
  };

  const updateMappingSourceKey = (fieldName: string, componentId: string, sourceKey: string) => {
    const updated = cfg.fieldMappings.map((m) =>
      m.targetFieldName === fieldName && m.targetComponentId === componentId
        ? { ...m, sourceKey }
        : m
    );
    update({ fieldMappings: updated });
  };

  useEffect(() => {
    if (cfg.parseMode !== "json" || connectedFields.length === 0) return;
    const synced = buildMappingsFromFields(connectedFields, cfg.fieldMappings);
    const isSame =
      synced.length === cfg.fieldMappings.length &&
      synced.every(
        (s, i) =>
          s.targetComponentId === cfg.fieldMappings[i]?.targetComponentId &&
          s.targetFieldName === cfg.fieldMappings[i]?.targetFieldName,
      );
    if (!isSame) {
      onUpdate({ ...cfg, fieldMappings: synced });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [connectedFields, cfg.parseMode]);

  return (
    <div className="space-y-4 pr-1 pb-16">
      <div className="space-y-1.5">
        <Label className="text-xs">바코드 형식</Label>
        <Select
          value={cfg.barcodeFormat}
          onValueChange={(v) => update({ barcodeFormat: v as PopScannerConfig["barcodeFormat"] })}
        >
          <SelectTrigger className="h-8 text-xs">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {Object.entries(FORMAT_LABELS).map(([key, label]) => (
              <SelectItem key={key} value={key} className="text-xs">
                {label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
        <p className="text-[10px] text-muted-foreground">인식할 바코드 종류를 선택합니다</p>
      </div>

      <div className="space-y-1.5">
        <Label className="text-xs">버튼 라벨</Label>
        <Input
          value={cfg.buttonLabel}
          onChange={(e) => update({ buttonLabel: e.target.value })}
          placeholder="스캔"
          className="h-8 text-xs"
        />
      </div>

      <div className="space-y-1.5">
        <Label className="text-xs">버튼 스타일</Label>
        <Select
          value={cfg.buttonVariant}
          onValueChange={(v) => update({ buttonVariant: v as PopScannerConfig["buttonVariant"] })}
        >
          <SelectTrigger className="h-8 text-xs">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {Object.entries(VARIANT_LABELS).map(([key, label]) => (
              <SelectItem key={key} value={key} className="text-xs">
                {label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>

      <div className="flex items-center justify-between">
        <div>
          <Label className="text-xs">인식 후 자동 확인</Label>
          <p className="text-[10px] text-muted-foreground">
            {cfg.autoSubmit
              ? "바코드 인식 즉시 값 전달 (확인 버튼 생략)"
              : "인식 후 확인 버튼을 눌러야 값 전달"}
          </p>
        </div>
        <Switch
          checked={cfg.autoSubmit}
          onCheckedChange={(v) => update({ autoSubmit: v })}
        />
      </div>

      <div className="flex items-center justify-between">
        <div>
          <Label className="text-xs">마지막 스캔값 표시</Label>
          <p className="text-[10px] text-muted-foreground">버튼 아래에 마지막 스캔값 표시</p>
        </div>
        <Switch
          checked={cfg.showLastScan}
          onCheckedChange={(v) => update({ showLastScan: v })}
        />
      </div>

      {/* 파싱 설정 섹션 */}
      <div className="border-t pt-4">
        <Label className="text-xs font-semibold">스캔 데이터 파싱</Label>
        <p className="mb-3 text-[10px] text-muted-foreground">
          바코드/QR에 여러 정보가 담긴 경우, 파싱하여 각각 다른 컴포넌트에 전달
        </p>

        <div className="space-y-1.5">
          <Label className="text-xs">파싱 모드</Label>
          <Select
            value={cfg.parseMode}
            onValueChange={(v) => {
              const mode = v as PopScannerConfig["parseMode"];
              update({
                parseMode: mode,
                fieldMappings: mode === "none" ? [] : cfg.fieldMappings,
              });
            }}
          >
            <SelectTrigger className="h-8 text-xs">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {Object.entries(PARSE_MODE_LABELS).map(([key, label]) => (
                <SelectItem key={key} value={key} className="text-xs">
                  {label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>

        {cfg.parseMode === "auto" && (
          <div className="mt-3 rounded-md bg-muted/50 p-3">
            <p className="text-[10px] font-medium">자동 매칭 방식</p>
            <p className="mt-1 text-[10px] text-muted-foreground">
              QR/바코드의 JSON 키가 연결된 컴포넌트의 필드명과 같으면 자동 입력됩니다.
            </p>
            {connectedFields.length > 0 && (
              <div className="mt-2 space-y-1">
                <p className="text-[10px] font-medium">연결된 필드 목록:</p>
                {connectedFields.map((f, i) => (
                  <div key={i} className="flex items-center gap-1 text-[10px] text-muted-foreground">
                    <span className="font-mono text-primary">{f.fieldName}</span>
                    <span>- {f.fieldLabel}</span>
                    <span className="text-muted-foreground/50">({f.componentName})</span>
                  </div>
                ))}
                <p className="mt-1 text-[10px] text-muted-foreground">
                  QR에 위 필드명이 JSON 키로 포함되면 자동 매칭됩니다.
                </p>
              </div>
            )}
            {connectedFields.length === 0 && (
              <p className="mt-2 text-[10px] text-muted-foreground">
                연결 탭에서 스캐너와 다른 컴포넌트를 먼저 연결하세요.
                연결 없이도 같은 화면의 모든 컴포넌트에 전역으로 전달됩니다.
              </p>
            )}
          </div>
        )}

        {cfg.parseMode === "json" && (
          <div className="mt-3 space-y-3">
            <p className="text-[10px] text-muted-foreground">
              연결된 컴포넌트의 필드를 선택하고, 매핑할 JSON 키를 지정합니다.
              필드명과 같은 JSON 키가 있으면 자동 매칭됩니다.
            </p>

            {connectedFields.length === 0 ? (
              <div className="rounded-md bg-muted/50 p-3">
                <p className="text-[10px] text-muted-foreground">
                  연결 탭에서 스캐너와 다른 컴포넌트를 먼저 연결해주세요.
                  연결된 컴포넌트의 필드 목록이 여기에 표시됩니다.
                </p>
              </div>
            ) : (
              <div className="space-y-2">
                <Label className="text-xs font-semibold">필드 매핑</Label>
                <div className="space-y-1.5">
                  {cfg.fieldMappings.map((mapping) => (
                    <div
                      key={`${mapping.targetComponentId}_${mapping.targetFieldName}`}
                      className="flex items-start gap-2 rounded-md border p-2"
                    >
                      <Checkbox
                        id={`map_${mapping.targetComponentId}_${mapping.targetFieldName}`}
                        checked={mapping.enabled}
                        onCheckedChange={() =>
                          toggleMapping(mapping.targetFieldName, mapping.targetComponentId)
                        }
                        className="mt-0.5"
                      />
                      <div className="flex-1 space-y-1">
                        <label
                          htmlFor={`map_${mapping.targetComponentId}_${mapping.targetFieldName}`}
                          className="flex cursor-pointer items-center gap-1 text-[11px]"
                        >
                          <span className="font-mono text-primary">
                            {mapping.targetFieldName}
                          </span>
                          <span className="text-muted-foreground">
                            ({mapping.label})
                          </span>
                        </label>
                        {mapping.enabled && (
                          <div className="flex items-center gap-1">
                            <span className="shrink-0 text-[10px] text-muted-foreground">
                              JSON 키:
                            </span>
                            <Input
                              value={mapping.sourceKey}
                              onChange={(e) =>
                                updateMappingSourceKey(
                                  mapping.targetFieldName,
                                  mapping.targetComponentId,
                                  e.target.value,
                                )
                              }
                              placeholder={mapping.targetFieldName}
                              className="h-6 text-[10px]"
                            />
                          </div>
                        )}
                      </div>
                    </div>
                  ))}
                </div>

                {cfg.fieldMappings.some((m) => m.enabled) && (
                  <div className="rounded-md bg-muted/50 p-2">
                    <p className="text-[10px] font-medium text-muted-foreground">활성 매핑:</p>
                    <ul className="mt-1 space-y-0.5">
                      {cfg.fieldMappings
                        .filter((m) => m.enabled)
                        .map((m, i) => (
                          <li key={i} className="text-[10px] text-muted-foreground">
                            <span className="font-mono">{m.sourceKey || "?"}</span>
                            {" -> "}
                            <span className="font-mono text-primary">{m.targetFieldName}</span>
                            {m.label && <span className="ml-1">({m.label})</span>}
                          </li>
                        ))}
                    </ul>
                  </div>
                )}
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

// ========================================
// 미리보기
// ========================================

function PopScannerPreview({ config }: { config?: PopScannerConfig }) {
  const cfg = config || DEFAULT_SCANNER_CONFIG;

  return (
    <div className="flex h-full w-full items-center justify-center overflow-hidden">
      <Button
        variant={cfg.buttonVariant}
        size="icon"
        className="pointer-events-none h-full w-full rounded-md"
        tabIndex={-1}
      >
        <ScanLine className="h-7! w-7!" />
      </Button>
    </div>
  );
}

// ========================================
// 동적 sendable 생성
// ========================================

function buildSendableMeta(config?: PopScannerConfig) {
  const base = [
    {
      key: "scan_value",
      label: "스캔 값 (원본)",
      type: "filter_value" as const,
      category: "filter" as const,
      description: "파싱 전 원본 스캔 결과 (단일 값 모드이거나 파싱 실패 시)",
    },
  ];

  if (config?.fieldMappings && config.fieldMappings.length > 0) {
    for (const mapping of config.fieldMappings) {
      base.push({
        key: `scan_field_${mapping.outputIndex}`,
        label: mapping.label || `스캔 필드 ${mapping.outputIndex}`,
        type: "filter_value" as const,
        category: "filter" as const,
        description: `파싱된 필드: JSON 키 "${mapping.sourceKey}"`,
      });
    }
  }

  return base;
}

// ========================================
// 레지스트리 등록
// ========================================

PopComponentRegistry.registerComponent({
  id: "pop-scanner",
  name: "스캐너",
  description: "바코드/QR 카메라 스캔",
  category: "input",
  icon: "ScanLine",
  component: PopScannerComponent,
  configPanel: PopScannerConfigPanel,
  preview: PopScannerPreview,
  defaultProps: DEFAULT_SCANNER_CONFIG,
  connectionMeta: {
    sendable: buildSendableMeta(),
    receivable: [],
  },
  getDynamicConnectionMeta: (config: Record<string, unknown>) => ({
    sendable: buildSendableMeta(config as unknown as PopScannerConfig),
    receivable: [],
  }),
  touchOptimized: true,
  supportedDevices: ["mobile", "tablet"],
});
