"use client";

import React from "react";
import { ArrowRight, Link2, Unlink2, Plus, Trash2, Pencil, X, Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Checkbox } from "@/components/ui/checkbox";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  PopComponentDefinitionV5,
  PopDataConnection,
} from "../types/pop-layout";
import {
  PopComponentRegistry,
  type ComponentConnectionMeta,
} from "@/lib/registry/PopComponentRegistry";
import { getTableColumns } from "@/lib/api/tableManagement";

// ========================================
// Props
// ========================================

interface ConnectionEditorProps {
  component: PopComponentDefinitionV5;
  allComponents: PopComponentDefinitionV5[];
  connections: PopDataConnection[];
  onAddConnection?: (conn: Omit<PopDataConnection, "id">) => void;
  onUpdateConnection?: (connectionId: string, conn: Omit<PopDataConnection, "id">) => void;
  onRemoveConnection?: (connectionId: string) => void;
}

// ========================================
// ConnectionEditor
// ========================================

export default function ConnectionEditor({
  component,
  allComponents,
  connections,
  onAddConnection,
  onUpdateConnection,
  onRemoveConnection,
}: ConnectionEditorProps) {
  const registeredComp = PopComponentRegistry.getComponent(component.type);
  const meta = registeredComp?.connectionMeta;

  const outgoing = connections.filter(
    (c) => c.sourceComponent === component.id
  );
  const incoming = connections.filter(
    (c) => c.targetComponent === component.id
  );

  const hasSendable = meta?.sendable && meta.sendable.length > 0;
  const hasReceivable = meta?.receivable && meta.receivable.length > 0;

  if (!hasSendable && !hasReceivable) {
    return (
      <div className="space-y-4">
        <div className="rounded-lg bg-gray-50 p-4 text-center">
          <Link2 className="mx-auto mb-2 h-8 w-8 text-muted-foreground" />
          <p className="text-sm font-medium text-gray-700">연결 없음</p>
          <p className="mt-1 text-xs text-muted-foreground">
            이 컴포넌트는 다른 컴포넌트와 연결할 수 없습니다
          </p>
        </div>
      </div>
    );
  }

  return (
    <div className="space-y-6">
      {hasSendable && (
        <SendSection
          component={component}
          meta={meta!}
          allComponents={allComponents}
          outgoing={outgoing}
          onAddConnection={onAddConnection}
          onUpdateConnection={onUpdateConnection}
          onRemoveConnection={onRemoveConnection}
        />
      )}

      {hasReceivable && (
        <ReceiveSection
          component={component}
          meta={meta!}
          allComponents={allComponents}
          incoming={incoming}
        />
      )}
    </div>
  );
}

// ========================================
// 대상 컴포넌트에서 정보 추출
// ========================================

/** 화면에 표시 중인 컬럼만 추출 */
function extractDisplayColumns(comp: PopComponentDefinitionV5 | undefined): string[] {
  if (!comp?.config) return [];
  const cfg = comp.config as Record<string, unknown>;
  const cols: string[] = [];

  if (Array.isArray(cfg.listColumns)) {
    (cfg.listColumns as Array<{ columnName?: string }>).forEach((c) => {
      if (c.columnName && !cols.includes(c.columnName)) cols.push(c.columnName);
    });
  }

  if (Array.isArray(cfg.selectedColumns)) {
    (cfg.selectedColumns as string[]).forEach((c) => {
      if (!cols.includes(c)) cols.push(c);
    });
  }

  return cols;
}

/** 대상 컴포넌트의 데이터소스 테이블명 추출 */
function extractTableName(comp: PopComponentDefinitionV5 | undefined): string {
  if (!comp?.config) return "";
  const cfg = comp.config as Record<string, unknown>;
  const ds = cfg.dataSource as { tableName?: string } | undefined;
  return ds?.tableName || "";
}

// ========================================
// 보내기 섹션
// ========================================

interface SendSectionProps {
  component: PopComponentDefinitionV5;
  meta: ComponentConnectionMeta;
  allComponents: PopComponentDefinitionV5[];
  outgoing: PopDataConnection[];
  onAddConnection?: (conn: Omit<PopDataConnection, "id">) => void;
  onUpdateConnection?: (connectionId: string, conn: Omit<PopDataConnection, "id">) => void;
  onRemoveConnection?: (connectionId: string) => void;
}

function SendSection({
  component,
  meta,
  allComponents,
  outgoing,
  onAddConnection,
  onUpdateConnection,
  onRemoveConnection,
}: SendSectionProps) {
  const [editingId, setEditingId] = React.useState<string | null>(null);

  return (
    <div className="space-y-3">
      <Label className="flex items-center gap-1 text-xs font-medium">
        <ArrowRight className="h-3 w-3 text-blue-500" />
        이때 (보내기)
      </Label>

      {/* 기존 연결 목록 */}
      {outgoing.map((conn) => (
        <div key={conn.id}>
          {editingId === conn.id ? (
            <ConnectionForm
              component={component}
              meta={meta}
              allComponents={allComponents}
              initial={conn}
              onSubmit={(data) => {
                onUpdateConnection?.(conn.id, data);
                setEditingId(null);
              }}
              onCancel={() => setEditingId(null)}
              submitLabel="수정"
            />
          ) : (
            <div className="flex items-center gap-1 rounded border bg-blue-50/50 px-3 py-2">
              <span className="flex-1 truncate text-xs">
                {conn.label || `${conn.sourceOutput} -> ${conn.targetInput}`}
              </span>
              <button
                onClick={() => setEditingId(conn.id)}
                className="shrink-0 p-0.5 text-muted-foreground hover:text-primary"
              >
                <Pencil className="h-3 w-3" />
              </button>
              {onRemoveConnection && (
                <button
                  onClick={() => onRemoveConnection(conn.id)}
                  className="shrink-0 p-0.5 text-muted-foreground hover:text-destructive"
                >
                  <Trash2 className="h-3 w-3" />
                </button>
              )}
            </div>
          )}
        </div>
      ))}

      {/* 새 연결 추가 */}
      <ConnectionForm
        component={component}
        meta={meta}
        allComponents={allComponents}
        onSubmit={(data) => onAddConnection?.(data)}
        submitLabel="연결 추가"
      />
    </div>
  );
}

// ========================================
// 연결 폼 (추가/수정 공용)
// ========================================

interface ConnectionFormProps {
  component: PopComponentDefinitionV5;
  meta: ComponentConnectionMeta;
  allComponents: PopComponentDefinitionV5[];
  initial?: PopDataConnection;
  onSubmit: (data: Omit<PopDataConnection, "id">) => void;
  onCancel?: () => void;
  submitLabel: string;
}

function ConnectionForm({
  component,
  meta,
  allComponents,
  initial,
  onSubmit,
  onCancel,
  submitLabel,
}: ConnectionFormProps) {
  const [selectedOutput, setSelectedOutput] = React.useState(
    initial?.sourceOutput || meta.sendable[0]?.key || ""
  );
  const [selectedTargetId, setSelectedTargetId] = React.useState(
    initial?.targetComponent || ""
  );
  const [selectedTargetInput, setSelectedTargetInput] = React.useState(
    initial?.targetInput || ""
  );
  const [filterColumns, setFilterColumns] = React.useState<string[]>(
    initial?.filterConfig?.targetColumns ||
    (initial?.filterConfig?.targetColumn ? [initial.filterConfig.targetColumn] : [])
  );
  const [filterMode, setFilterMode] = React.useState<
    "equals" | "contains" | "starts_with" | "range"
  >(initial?.filterConfig?.filterMode || "contains");

  const targetCandidates = allComponents.filter((c) => {
    if (c.id === component.id) return false;
    const reg = PopComponentRegistry.getComponent(c.type);
    return reg?.connectionMeta?.receivable && reg.connectionMeta.receivable.length > 0;
  });

  const targetComp = selectedTargetId
    ? allComponents.find((c) => c.id === selectedTargetId)
    : null;

  const targetMeta = targetComp
    ? PopComponentRegistry.getComponent(targetComp.type)?.connectionMeta
    : null;

  // 보내는 값 + 받는 컴포넌트가 결정되면 받는 방식 자동 매칭
  React.useEffect(() => {
    if (!selectedOutput || !targetMeta?.receivable?.length) return;
    // 이미 선택된 값이 있으면 건드리지 않음
    if (selectedTargetInput) return;

    const receivables = targetMeta.receivable;
    // 1) 같은 key가 있으면 자동 매칭
    const exactMatch = receivables.find((r) => r.key === selectedOutput);
    if (exactMatch) {
      setSelectedTargetInput(exactMatch.key);
      return;
    }
    // 2) receivable이 1개뿐이면 자동 선택
    if (receivables.length === 1) {
      setSelectedTargetInput(receivables[0].key);
    }
  }, [selectedOutput, targetMeta, selectedTargetInput]);

  // 화면에 표시 중인 컬럼
  const displayColumns = React.useMemo(
    () => extractDisplayColumns(targetComp || undefined),
    [targetComp]
  );

  // DB 테이블 전체 컬럼 (비동기 조회)
  const tableName = React.useMemo(
    () => extractTableName(targetComp || undefined),
    [targetComp]
  );
  const [allDbColumns, setAllDbColumns] = React.useState<string[]>([]);
  const [dbColumnsLoading, setDbColumnsLoading] = React.useState(false);

  React.useEffect(() => {
    if (!tableName) {
      setAllDbColumns([]);
      return;
    }
    let cancelled = false;
    setDbColumnsLoading(true);
    getTableColumns(tableName).then((res) => {
      if (cancelled) return;
      if (res.success && res.data?.columns) {
        setAllDbColumns(res.data.columns.map((c) => c.columnName));
      } else {
        setAllDbColumns([]);
      }
      setDbColumnsLoading(false);
    });
    return () => { cancelled = true; };
  }, [tableName]);

  // 표시 컬럼과 데이터 전용 컬럼 분리
  const displaySet = React.useMemo(() => new Set(displayColumns), [displayColumns]);
  const dataOnlyColumns = React.useMemo(
    () => allDbColumns.filter((c) => !displaySet.has(c)),
    [allDbColumns, displaySet]
  );
  const hasAnyColumns = displayColumns.length > 0 || dataOnlyColumns.length > 0;

  const toggleColumn = (col: string) => {
    setFilterColumns((prev) =>
      prev.includes(col) ? prev.filter((c) => c !== col) : [...prev, col]
    );
  };

  const handleSubmit = () => {
    if (!selectedOutput || !selectedTargetId || !selectedTargetInput) return;

    const isEvent = isEventTypeConnection(meta, selectedOutput, targetMeta, selectedTargetInput);

    onSubmit({
      sourceComponent: component.id,
      sourceField: "",
      sourceOutput: selectedOutput,
      targetComponent: selectedTargetId,
      targetField: "",
      targetInput: selectedTargetInput,
      filterConfig:
        !isEvent && filterColumns.length > 0
          ? {
              targetColumn: filterColumns[0],
              targetColumns: filterColumns,
              filterMode,
            }
          : undefined,
      label: buildConnectionLabel(
        component,
        selectedOutput,
        allComponents.find((c) => c.id === selectedTargetId),
        selectedTargetInput,
        filterColumns
      ),
    });

    if (!initial) {
      setSelectedTargetId("");
      setSelectedTargetInput("");
      setFilterColumns([]);
    }
  };

  return (
    <div className="space-y-2 rounded border border-dashed p-3">
      {onCancel && (
        <div className="flex items-center justify-between">
          <p className="text-[10px] font-medium text-muted-foreground">연결 수정</p>
          <button onClick={onCancel} className="text-muted-foreground hover:text-foreground">
            <X className="h-3 w-3" />
          </button>
        </div>
      )}
      {!onCancel && (
        <p className="text-[10px] font-medium text-muted-foreground">새 연결 추가</p>
      )}

      {/* 보내는 값 */}
      <div className="space-y-1">
        <span className="text-[10px] text-muted-foreground">보내는 값</span>
        <Select value={selectedOutput} onValueChange={setSelectedOutput}>
          <SelectTrigger className="h-7 text-xs">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {meta.sendable.map((s) => (
              <SelectItem key={s.key} value={s.key} className="text-xs">
                {s.label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>

      {/* 받는 컴포넌트 */}
      <div className="space-y-1">
        <span className="text-[10px] text-muted-foreground">받는 컴포넌트</span>
        <Select
          value={selectedTargetId}
          onValueChange={(v) => {
            setSelectedTargetId(v);
            setSelectedTargetInput("");
            setFilterColumns([]);
          }}
        >
          <SelectTrigger className="h-7 text-xs">
            <SelectValue placeholder="컴포넌트 선택" />
          </SelectTrigger>
          <SelectContent>
            {targetCandidates.map((c) => (
              <SelectItem key={c.id} value={c.id} className="text-xs">
                {c.label || c.id}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>

      {/* 받는 방식 */}
      {targetMeta && (
        <div className="space-y-1">
          <span className="text-[10px] text-muted-foreground">받는 방식</span>
          <Select value={selectedTargetInput} onValueChange={setSelectedTargetInput}>
            <SelectTrigger className="h-7 text-xs">
              <SelectValue placeholder="선택" />
            </SelectTrigger>
            <SelectContent>
              {targetMeta.receivable.map((r) => (
                <SelectItem key={r.key} value={r.key} className="text-xs">
                  {r.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      )}

      {/* 필터 설정: event 타입 연결이면 숨김 */}
      {selectedTargetInput && !isEventTypeConnection(meta, selectedOutput, targetMeta, selectedTargetInput) && (
        <div className="space-y-2 rounded bg-gray-50 p-2">
          <p className="text-[10px] font-medium text-muted-foreground">필터할 컬럼</p>

          {dbColumnsLoading ? (
            <div className="flex items-center gap-2 py-2">
              <Loader2 className="h-3 w-3 animate-spin text-muted-foreground" />
              <span className="text-[10px] text-muted-foreground">컬럼 조회 중...</span>
            </div>
          ) : hasAnyColumns ? (
            <div className="space-y-2">
              {/* 표시 컬럼 그룹 */}
              {displayColumns.length > 0 && (
                <div className="space-y-1">
                  <p className="text-[9px] font-medium text-green-600">화면 표시 컬럼</p>
                  {displayColumns.map((col) => (
                    <div key={col} className="flex items-center gap-2">
                      <Checkbox
                        id={`col-${col}-${initial?.id || "new"}`}
                        checked={filterColumns.includes(col)}
                        onCheckedChange={() => toggleColumn(col)}
                      />
                      <label
                        htmlFor={`col-${col}-${initial?.id || "new"}`}
                        className="cursor-pointer text-xs"
                      >
                        {col}
                      </label>
                    </div>
                  ))}
                </div>
              )}

              {/* 데이터 전용 컬럼 그룹 */}
              {dataOnlyColumns.length > 0 && (
                <div className="space-y-1">
                  {displayColumns.length > 0 && (
                    <div className="my-1 h-px bg-gray-200" />
                  )}
                  <p className="text-[9px] font-medium text-amber-600">데이터 전용 컬럼</p>
                  {dataOnlyColumns.map((col) => (
                    <div key={col} className="flex items-center gap-2">
                      <Checkbox
                        id={`col-${col}-${initial?.id || "new"}`}
                        checked={filterColumns.includes(col)}
                        onCheckedChange={() => toggleColumn(col)}
                      />
                      <label
                        htmlFor={`col-${col}-${initial?.id || "new"}`}
                        className="cursor-pointer text-xs text-muted-foreground"
                      >
                        {col}
                      </label>
                    </div>
                  ))}
                </div>
              )}
            </div>
          ) : (
            <Input
              value={filterColumns[0] || ""}
              onChange={(e) => setFilterColumns(e.target.value ? [e.target.value] : [])}
              placeholder="컬럼명 입력"
              className="h-7 text-xs"
            />
          )}

          {filterColumns.length > 0 && (
            <p className="text-[10px] text-blue-600">
              {filterColumns.length}개 컬럼 중 하나라도 일치하면 표시
            </p>
          )}

          {/* 필터 방식 */}
          <div className="space-y-1">
            <p className="text-[10px] text-muted-foreground">필터 방식</p>
            <Select value={filterMode} onValueChange={(v: any) => setFilterMode(v)}>
              <SelectTrigger className="h-7 text-xs">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="contains" className="text-xs">포함</SelectItem>
                <SelectItem value="equals" className="text-xs">일치</SelectItem>
                <SelectItem value="starts_with" className="text-xs">시작</SelectItem>
                <SelectItem value="range" className="text-xs">범위</SelectItem>
              </SelectContent>
            </Select>
          </div>
        </div>
      )}

      {/* 제출 버튼 */}
      <Button
        size="sm"
        variant="outline"
        className="h-7 w-full text-xs"
        disabled={!selectedOutput || !selectedTargetId || !selectedTargetInput}
        onClick={handleSubmit}
      >
        {!initial && <Plus className="mr-1 h-3 w-3" />}
        {submitLabel}
      </Button>
    </div>
  );
}

// ========================================
// 받기 섹션 (읽기 전용)
// ========================================

interface ReceiveSectionProps {
  component: PopComponentDefinitionV5;
  meta: ComponentConnectionMeta;
  allComponents: PopComponentDefinitionV5[];
  incoming: PopDataConnection[];
}

function ReceiveSection({
  component,
  meta,
  allComponents,
  incoming,
}: ReceiveSectionProps) {
  return (
    <div className="space-y-3">
      <Label className="flex items-center gap-1 text-xs font-medium">
        <Unlink2 className="h-3 w-3 text-green-500" />
        이렇게 (받기)
      </Label>

      <div className="space-y-1">
        {meta.receivable.map((r) => (
          <div
            key={r.key}
            className="rounded bg-green-50/50 px-3 py-2 text-xs text-gray-600"
          >
            <span className="font-medium">{r.label}</span>
            {r.description && (
              <p className="mt-0.5 text-[10px] text-muted-foreground">
                {r.description}
              </p>
            )}
          </div>
        ))}
      </div>

      {incoming.length > 0 ? (
        <div className="space-y-2">
          <p className="text-[10px] text-muted-foreground">연결된 소스</p>
          {incoming.map((conn) => {
            const sourceComp = allComponents.find(
              (c) => c.id === conn.sourceComponent
            );
            return (
              <div
                key={conn.id}
                className="flex items-center gap-2 rounded border bg-gray-50 px-3 py-2 text-xs"
              >
                <ArrowRight className="h-3 w-3 text-muted-foreground" />
                <span className="truncate">
                  {sourceComp?.label || conn.sourceComponent}
                </span>
              </div>
            );
          })}
        </div>
      ) : (
        <p className="text-xs text-muted-foreground">
          아직 연결된 소스가 없습니다. 보내는 컴포넌트에서 연결을 설정하세요.
        </p>
      )}
    </div>
  );
}

// ========================================
// 유틸
// ========================================

function isEventTypeConnection(
  sourceMeta: ComponentConnectionMeta | undefined,
  outputKey: string,
  targetMeta: ComponentConnectionMeta | null | undefined,
  inputKey: string,
): boolean {
  const sourceItem = sourceMeta?.sendable?.find((s) => s.key === outputKey);
  const targetItem = targetMeta?.receivable?.find((r) => r.key === inputKey);
  return sourceItem?.type === "event" || targetItem?.type === "event";
}

function buildConnectionLabel(
  source: PopComponentDefinitionV5,
  _outputKey: string,
  target: PopComponentDefinitionV5 | undefined,
  _inputKey: string,
  columns?: string[]
): string {
  const srcLabel = source.label || source.id;
  const tgtLabel = target?.label || target?.id || "?";
  const colInfo = columns && columns.length > 0
    ? ` [${columns.join(", ")}]`
    : "";
  return `${srcLabel} -> ${tgtLabel}${colInfo}`;
}
