"use client";

import { useState, useEffect, useCallback, useRef } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Badge } from "@/components/ui/badge";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Database,
  Plus,
  Trash2,
  Link2,
  Loader2,
  ChevronDown,
  ChevronUp,
  Table2,
} from "lucide-react";
import { reportApi } from "@/lib/api/reportApi";
import { useReportDesigner } from "@/contexts/ReportDesignerContext";
import type { ReportQuery } from "@/contexts/report-designer/types";
import type {
  ComponentConfig,
  VisualDataSource,
  VisualDetailSource,
  VisualColumn,
  JoinKeyPair,
} from "@/types/report";

interface SchemaTable {
  table_name: string;
  table_type: string;
}

interface SchemaColumn {
  column_name: string;
  data_type: string;
  is_nullable: string;
}

interface ForeignKey {
  constraint_name: string;
  columns: string[];
  foreign_table: string;
  foreign_columns: string[];
}

interface Props {
  component: ComponentConfig;
  embedded?: boolean;
}

const EMPTY_DATA_SOURCE: VisualDataSource = {
  master: { tableName: "", columns: [] },
  details: [],
};

function buildSqlForMaster(ds: VisualDataSource): string {
  if (!ds.master.tableName || ds.master.columns.length === 0) return "";
  const cols = ds.master.columns.map((c) => `"${c.name}"`).join(", ");
  return `SELECT ${cols} FROM "${ds.master.tableName}" WHERE 1=1`;
}

function buildSqlForDetail(ds: VisualDataSource, detail: VisualDetailSource): string {
  if (!detail.tableName || detail.columns.length === 0) return "";
  const cols = detail.columns.map((c) => `"${c.name}"`).join(", ");
  const conditions = detail.joinKeys
    .filter((jk) => jk.detailColumn)
    .map((jk, idx) => `"${jk.detailColumn}" = $${idx + 1}`)
    .join(" AND ");
  const where = conditions ? ` WHERE ${conditions}` : "";
  return `SELECT ${cols} FROM "${detail.tableName}"${where}`;
}

function buildQueriesFromDataSource(ds: VisualDataSource): ReportQuery[] {
  const queries: ReportQuery[] = [];

  const masterSql = buildSqlForMaster(ds);
  if (masterSql) {
    queries.push({
      id: `vds_master_${ds.master.tableName}`,
      name: `${ds.master.tableName} (마스터)`,
      type: "MASTER",
      sqlQuery: masterSql,
      parameters: [],
      visualDataSource: ds,
    });
  }

  for (const detail of ds.details) {
    const detailSql = buildSqlForDetail(ds, detail);
    if (detailSql) {
      const params = detail.joinKeys
        .filter((jk) => jk.detailColumn)
        .map((_, idx) => `$${idx + 1}`);
      queries.push({
        id: `vds_detail_${detail.id}`,
        name: `${detail.tableName} (디테일)`,
        type: "DETAIL",
        sqlQuery: detailSql,
        parameters: params,
        visualDataSource: ds,
      });
    }
  }

  return queries;
}

export function VisualDataSourceBuilder({ component, embedded = false }: Props) {
  const { updateComponent, queries, setQueries } = useReportDesigner();

  const ds: VisualDataSource = component.visualDataSource ?? EMPTY_DATA_SOURCE;
  const prevDsRef = useRef<string>("");

  // 데이터 소스 변경 시 queries 배열 자동 동기화
  useEffect(() => {
    const dsJson = JSON.stringify(ds);
    if (dsJson === prevDsRef.current) return;
    prevDsRef.current = dsJson;

    if (!ds.master.tableName) return;

    const vdsQueries = buildQueriesFromDataSource(ds);
    if (vdsQueries.length === 0) return;

    const nonVdsQueries = queries.filter((q) => !q.id.startsWith("vds_"));
    setQueries([...nonVdsQueries, ...vdsQueries]);
  }, [ds, queries, setQueries]);

  const [tables, setTables] = useState<SchemaTable[]>([]);
  const [tablesLoading, setTablesLoading] = useState(false);
  const [masterColumns, setMasterColumns] = useState<SchemaColumn[]>([]);
  const [masterColumnsLoading, setMasterColumnsLoading] = useState(false);
  const [detailColumnsMap, setDetailColumnsMap] = useState<Record<string, SchemaColumn[]>>({});
  const [detailColumnsLoading, setDetailColumnsLoading] = useState<Record<string, boolean>>({});
  const [detailFkMap, setDetailFkMap] = useState<Record<string, ForeignKey[]>>({});
  const [expandedDetails, setExpandedDetails] = useState<Record<string, boolean>>({});

  // 복원 시 디테일 테이블의 컬럼 목록 자동 로드
  useEffect(() => {
    for (const detail of ds.details) {
      if (detail.tableName && !detailColumnsMap[detail.id]) {
        setDetailColumnsLoading((prev) => ({ ...prev, [detail.id]: true }));
        reportApi
          .getSchemaTableColumns(detail.tableName)
          .then((res) => {
            if (res.success) {
              setDetailColumnsMap((prev) => ({ ...prev, [detail.id]: res.data }));
            }
          })
          .catch(() => {})
          .finally(() => {
            setDetailColumnsLoading((prev) => ({ ...prev, [detail.id]: false }));
          });
      }
    }
  }, [ds.details, detailColumnsMap]);

  const updateDS = useCallback(
    (patch: Partial<VisualDataSource>) => {
      updateComponent(component.id, {
        visualDataSource: { ...ds, ...patch },
      });
    },
    [component.id, ds, updateComponent],
  );

  // 테이블 목록 로드
  useEffect(() => {
    let cancelled = false;
    setTablesLoading(true);
    reportApi
      .getSchemaTableList()
      .then((res) => {
        if (!cancelled && res.success) setTables(res.data);
      })
      .catch(() => {})
      .finally(() => {
        if (!cancelled) setTablesLoading(false);
      });
    return () => { cancelled = true; };
  }, []);

  // 마스터 테이블 컬럼 로드
  useEffect(() => {
    if (!ds.master.tableName) {
      setMasterColumns([]);
      return;
    }
    let cancelled = false;
    setMasterColumnsLoading(true);
    reportApi
      .getSchemaTableColumns(ds.master.tableName)
      .then((res) => {
        if (!cancelled && res.success) setMasterColumns(res.data);
      })
      .catch(() => {})
      .finally(() => {
        if (!cancelled) setMasterColumnsLoading(false);
      });
    return () => { cancelled = true; };
  }, [ds.master.tableName]);

  const handleMasterTableChange = useCallback(
    (tableName: string) => {
      const newTableName = tableName === "none" ? "" : tableName;
      updateDS({
        master: { tableName: newTableName, columns: [] },
        details: [],
      });
      setDetailColumnsMap({});
      setDetailFkMap({});
    },
    [updateDS],
  );

  const toggleMasterColumn = useCallback(
    (colName: string, dataType: string) => {
      const existing = ds.master.columns.find((c) => c.name === colName);
      const newColumns = existing
        ? ds.master.columns.filter((c) => c.name !== colName)
        : [...ds.master.columns, { name: colName, label: colName, dataType, selected: true }];
      updateDS({ master: { ...ds.master, columns: newColumns } });
    },
    [ds, updateDS],
  );

  const updateMasterColumnLabel = useCallback(
    (colName: string, label: string) => {
      const newColumns = ds.master.columns.map((c) =>
        c.name === colName ? { ...c, label } : c,
      );
      updateDS({ master: { ...ds.master, columns: newColumns } });
    },
    [ds, updateDS],
  );

  // 디테일 추가
  const addDetail = useCallback(() => {
    const newDetail: VisualDetailSource = {
      id: `detail_${Date.now()}`,
      tableName: "",
      columns: [],
      joinKeys: [],
    };
    updateDS({ details: [...ds.details, newDetail] });
    setExpandedDetails((prev) => ({ ...prev, [newDetail.id]: true }));
  }, [ds, updateDS]);

  const removeDetail = useCallback(
    (detailId: string) => {
      updateDS({ details: ds.details.filter((d) => d.id !== detailId) });
    },
    [ds, updateDS],
  );

  const updateDetail = useCallback(
    (detailId: string, patch: Partial<VisualDetailSource>) => {
      updateDS({
        details: ds.details.map((d) => (d.id === detailId ? { ...d, ...patch } : d)),
      });
    },
    [ds, updateDS],
  );

  // 디테일 테이블 변경 시 컬럼 + FK 로드
  const handleDetailTableChange = useCallback(
    async (detailId: string, tableName: string) => {
      const newTableName = tableName === "none" ? "" : tableName;
      updateDetail(detailId, { tableName: newTableName, columns: [], joinKeys: [] });

      if (!newTableName) return;

      setDetailColumnsLoading((prev) => ({ ...prev, [detailId]: true }));
      try {
        const [colRes, fkRes] = await Promise.all([
          reportApi.getSchemaTableColumns(newTableName),
          reportApi.getSchemaTableForeignKeys(newTableName),
        ]);

        if (colRes.success) {
          setDetailColumnsMap((prev) => ({ ...prev, [detailId]: colRes.data }));
        }

        if (fkRes.success) {
          setDetailFkMap((prev) => ({ ...prev, [detailId]: fkRes.data }));

          // FK 자동 감지: 마스터 테이블을 참조하는 FK 찾기
          const matchingFk = fkRes.data.find(
            (fk: ForeignKey) => fk.foreign_table === ds.master.tableName,
          );
          if (matchingFk) {
            const autoJoinKeys: JoinKeyPair[] = matchingFk.columns.map(
              (col: string, idx: number) => ({
                masterColumn: matchingFk.foreign_columns[idx] || "",
                detailColumn: col,
                autoDetected: true,
              }),
            );
            updateDetail(detailId, {
              tableName: newTableName,
              columns: [],
              joinKeys: autoJoinKeys,
            });
          }
        }
      } catch {
        // 무시
      } finally {
        setDetailColumnsLoading((prev) => ({ ...prev, [detailId]: false }));
      }
    },
    [ds.master.tableName, updateDetail],
  );

  const toggleDetailColumn = useCallback(
    (detailId: string, colName: string, dataType: string) => {
      const detail = ds.details.find((d) => d.id === detailId);
      if (!detail) return;
      const existing = detail.columns.find((c) => c.name === colName);
      const newColumns = existing
        ? detail.columns.filter((c) => c.name !== colName)
        : [...detail.columns, { name: colName, label: colName, dataType, selected: true }];
      updateDetail(detailId, { columns: newColumns });
    },
    [ds.details, updateDetail],
  );

  const updateDetailColumnLabel = useCallback(
    (detailId: string, colName: string, label: string) => {
      const detail = ds.details.find((d) => d.id === detailId);
      if (!detail) return;
      const newColumns = detail.columns.map((c) =>
        c.name === colName ? { ...c, label } : c,
      );
      updateDetail(detailId, { columns: newColumns });
    },
    [ds.details, updateDetail],
  );

  // 연결 키 관리
  const addJoinKey = useCallback(
    (detailId: string) => {
      const detail = ds.details.find((d) => d.id === detailId);
      if (!detail) return;
      updateDetail(detailId, {
        joinKeys: [
          ...detail.joinKeys,
          { masterColumn: "", detailColumn: "", autoDetected: false },
        ],
      });
    },
    [ds.details, updateDetail],
  );

  const updateJoinKey = useCallback(
    (detailId: string, keyIdx: number, patch: Partial<JoinKeyPair>) => {
      const detail = ds.details.find((d) => d.id === detailId);
      if (!detail) return;
      const newKeys = detail.joinKeys.map((k, i) =>
        i === keyIdx ? { ...k, ...patch, autoDetected: false } : k,
      );
      updateDetail(detailId, { joinKeys: newKeys });
    },
    [ds.details, updateDetail],
  );

  const removeJoinKey = useCallback(
    (detailId: string, keyIdx: number) => {
      const detail = ds.details.find((d) => d.id === detailId);
      if (!detail) return;
      updateDetail(detailId, {
        joinKeys: detail.joinKeys.filter((_, i) => i !== keyIdx),
      });
    },
    [ds.details, updateDetail],
  );

  const toggleDetailExpanded = useCallback((detailId: string) => {
    setExpandedDetails((prev) => ({ ...prev, [detailId]: !prev[detailId] }));
  }, []);

  // 컬럼 체크박스 렌더링 헬퍼
  const renderColumnCheckboxes = (
    schemaColumns: SchemaColumn[],
    selectedColumns: VisualColumn[],
    onToggle: (colName: string, dataType: string) => void,
    onLabelChange: (colName: string, label: string) => void,
    loading: boolean,
  ) => {
    if (loading) {
      return (
        <div className="flex items-center justify-center py-4">
          <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
          <span className="ml-2 text-xs text-muted-foreground">컬럼 로딩 중...</span>
        </div>
      );
    }
    if (schemaColumns.length === 0) {
      return <p className="py-2 text-xs text-muted-foreground">테이블을 선택해주세요.</p>;
    }
    return (
      <div className="max-h-48 space-y-1 overflow-y-auto">
        {schemaColumns.map((col) => {
          const selected = selectedColumns.find((c) => c.name === col.column_name);
          return (
            <div key={col.column_name} className="flex items-center gap-2 rounded px-1 py-0.5 hover:bg-muted/50">
              <input
                type="checkbox"
                checked={!!selected}
                onChange={() => onToggle(col.column_name, col.data_type)}
                className="h-3.5 w-3.5 rounded border-gray-300"
              />
              <span className="min-w-0 flex-1 truncate text-xs">{col.column_name}</span>
              <span className="shrink-0 text-[9px] text-gray-400">{col.data_type}</span>
              {selected && (
                <Input
                  value={selected.label}
                  onChange={(e) => onLabelChange(col.column_name, e.target.value)}
                  placeholder="라벨"
                  className="h-6 w-24 text-[10px]"
                />
              )}
            </div>
          );
        })}
      </div>
    );
  };

  const content = (
    <div className="space-y-3">
      {/* 마스터 데이터 */}
      <div className="space-y-2">
        <Label className="text-xs font-medium">마스터 테이블</Label>
        <Select
          value={ds.master.tableName || "none"}
          onValueChange={handleMasterTableChange}
          disabled={tablesLoading}
        >
          <SelectTrigger className="h-9 text-sm">
            <SelectValue placeholder={tablesLoading ? "로딩 중..." : "테이블 선택"} />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="none">선택 안함</SelectItem>
            {tables.map((t) => (
              <SelectItem key={t.table_name} value={t.table_name}>
                {t.table_name}
                {t.table_type === "VIEW" && (
                  <span className="ml-1 text-[10px] text-muted-foreground">(뷰)</span>
                )}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>

      {ds.master.tableName && (
        <div className="space-y-1.5">
          <Label className="text-xs font-medium">
            마스터 컬럼
            {ds.master.columns.length > 0 && (
              <Badge variant="secondary" className="ml-2 text-[10px]">
                {ds.master.columns.length}개
              </Badge>
            )}
          </Label>
          {renderColumnCheckboxes(
            masterColumns,
            ds.master.columns,
            toggleMasterColumn,
            updateMasterColumnLabel,
            masterColumnsLoading,
          )}
        </div>
      )}

      {/* 디테일 데이터 */}
      {ds.details.map((detail, idx) => {
        const detailCols = detailColumnsMap[detail.id] || [];
        const isLoading = detailColumnsLoading[detail.id] || false;
        const isExpanded = expandedDetails[detail.id] !== false;

        return (
          <div key={detail.id} className="rounded-lg border border-gray-200 bg-white p-3">
            <div className="mb-2 flex items-center justify-between">
              <button
                type="button"
                onClick={() => toggleDetailExpanded(detail.id)}
                className="flex items-center gap-1.5"
              >
                <Table2 className="h-3.5 w-3.5 text-gray-500" />
                <span className="text-xs font-medium text-foreground">
                  디테일 #{idx + 1}
                  {detail.tableName && (
                    <span className="ml-1 font-normal text-muted-foreground">
                      ({detail.tableName})
                    </span>
                  )}
                </span>
                {isExpanded ? (
                  <ChevronUp className="h-3 w-3 text-gray-400" />
                ) : (
                  <ChevronDown className="h-3 w-3 text-gray-400" />
                )}
              </button>
              <Button
                variant="ghost"
                size="icon"
                className="h-6 w-6 text-red-400 hover:bg-red-50 hover:text-red-600"
                onClick={() => removeDetail(detail.id)}
              >
                <Trash2 className="h-3 w-3" />
              </Button>
            </div>

            {isExpanded && (
              <div className="space-y-2">
                <div className="space-y-1.5">
                  <Label className="text-xs font-medium">테이블</Label>
                  <Select
                    value={detail.tableName || "none"}
                    onValueChange={(v) => handleDetailTableChange(detail.id, v)}
                    disabled={tablesLoading}
                  >
                    <SelectTrigger className="h-9 text-sm">
                      <SelectValue placeholder="테이블 선택" />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="none">선택 안함</SelectItem>
                      {tables.map((t) => (
                        <SelectItem key={t.table_name} value={t.table_name}>
                          {t.table_name}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </div>

                {detail.tableName && (
                  <div className="rounded-lg border border-blue-200 bg-blue-50/50 p-2.5">
                    <div className="mb-1.5 flex items-center justify-between">
                      <div className="flex items-center gap-1.5">
                        <Link2 className="h-3 w-3 text-blue-600" />
                        <span className="text-[11px] font-medium text-blue-700">연결 키</span>
                        {detail.joinKeys.some((k) => k.autoDetected) && (
                          <Badge variant="outline" className="h-4 border-blue-300 px-1 text-[9px] text-blue-600">
                            자동 감지
                          </Badge>
                        )}
                      </div>
                      <Button
                        variant="ghost"
                        size="sm"
                        className="h-5 px-1.5 text-[10px]"
                        onClick={() => addJoinKey(detail.id)}
                      >
                        <Plus className="mr-0.5 h-2.5 w-2.5" />
                        추가
                      </Button>
                    </div>

                    {detail.joinKeys.length === 0 && (
                      <p className="text-[10px] text-blue-600">
                        FK가 감지되지 않았습니다. 수동으로 추가해주세요.
                      </p>
                    )}

                    <div className="space-y-1">
                      {detail.joinKeys.map((jk, ki) => (
                        <div key={ki} className="flex items-center gap-1">
                          <Select
                            value={jk.masterColumn || "none"}
                            onValueChange={(v) =>
                              updateJoinKey(detail.id, ki, {
                                masterColumn: v === "none" ? "" : v,
                              })
                            }
                          >
                            <SelectTrigger className="h-7 flex-1 text-[10px]">
                              <SelectValue placeholder="마스터 컬럼" />
                            </SelectTrigger>
                            <SelectContent>
                              <SelectItem value="none">선택</SelectItem>
                              {ds.master.columns.length > 0
                                ? ds.master.columns.map((c) => (
                                    <SelectItem key={c.name} value={c.name}>
                                      {c.label !== c.name ? `${c.label} (${c.name})` : c.name}
                                    </SelectItem>
                                  ))
                                : masterColumns.map((c) => (
                                    <SelectItem key={c.column_name} value={c.column_name}>
                                      {c.column_name}
                                    </SelectItem>
                                  ))}
                            </SelectContent>
                          </Select>
                          <span className="text-[10px] text-gray-400">↔</span>
                          <Select
                            value={jk.detailColumn || "none"}
                            onValueChange={(v) =>
                              updateJoinKey(detail.id, ki, {
                                detailColumn: v === "none" ? "" : v,
                              })
                            }
                          >
                            <SelectTrigger className="h-7 flex-1 text-[10px]">
                              <SelectValue placeholder="디테일 컬럼" />
                            </SelectTrigger>
                            <SelectContent>
                              <SelectItem value="none">선택</SelectItem>
                              {detailCols.map((c) => (
                                <SelectItem key={c.column_name} value={c.column_name}>
                                  {c.column_name}
                                </SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                          <Button
                            variant="ghost"
                            size="icon"
                            className="h-5 w-5 shrink-0 text-red-400 hover:text-red-600"
                            onClick={() => removeJoinKey(detail.id, ki)}
                          >
                            <Trash2 className="h-2.5 w-2.5" />
                          </Button>
                        </div>
                      ))}
                    </div>
                  </div>
                )}

                {detail.tableName && (
                  <div className="space-y-1.5">
                    <Label className="text-xs font-medium">
                      디테일 컬럼
                      {detail.columns.length > 0 && (
                        <Badge variant="secondary" className="ml-2 text-[10px]">
                          {detail.columns.length}개
                        </Badge>
                      )}
                    </Label>
                    {renderColumnCheckboxes(
                      detailCols,
                      detail.columns,
                      (colName, dataType) => toggleDetailColumn(detail.id, colName, dataType),
                      (colName, label) => updateDetailColumnLabel(detail.id, colName, label),
                      isLoading,
                    )}
                  </div>
                )}
              </div>
            )}
          </div>
        );
      })}

      {ds.master.tableName && (
        <Button
          variant="outline"
          size="sm"
          className="w-full border-dashed text-xs"
          onClick={addDetail}
        >
          <Plus className="mr-1 h-3 w-3" />
          디테일 데이터 추가
        </Button>
      )}

      {!ds.master.tableName && (
        <div className="rounded-lg border border-dashed border-gray-200 p-4 text-center">
          <Database className="mx-auto mb-1.5 h-6 w-6 text-gray-300" />
          <p className="text-[11px] text-muted-foreground">
            마스터 테이블을 선택하면 데이터 소스를 구성할 수 있습니다.
          </p>
        </div>
      )}
    </div>
  );

  if (embedded) return content;

  return (
    <ScrollArea className="h-full">
      <div className="p-4">{content}</div>
    </ScrollArea>
  );
}
