"use client";

import React, { useEffect, useState } from "react";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Switch } from "@/components/ui/switch";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Plus, Trash2, Upload, X } from "lucide-react";
import { useToast } from "@/hooks/use-toast";
import {
  FileReaderAPI, FileReaderConfig, FileReaderMapping, FileType, SourceMode, SaveMode,
} from "@/lib/api/fileReader";
import { ExternalDbConnectionAPI } from "@/lib/api/externalDbConnection";

interface Props {
  open: boolean;
  editingId: number | null;
  onClose: () => void;
  onSaved: () => void;
}

const defaultConfig: Partial<FileReaderConfig> = {
  name: "",
  company_code: "*",
  file_type: "csv",
  source_mode: "upload",
  has_header: true,
  delimiter: ",",
  encoding: "utf-8",
  skip_rows: 0,
  target_schema: "public",
  save_mode: "INSERT",
  is_active: "Y",
  file_pattern: "*.csv",
  processed_action: "mark",
};

export const FileReaderConnectionModal: React.FC<Props> = ({ open, editingId, onClose, onSaved }) => {
  const { toast } = useToast();
  const [cfg, setCfg] = useState<Partial<FileReaderConfig>>(defaultConfig);
  const [mappings, setMappings] = useState<FileReaderMapping[]>([]);
  const [dbList, setDbList] = useState<Array<{ id: number; connection_name: string }>>([]);
  const [allowedRoots, setAllowedRoots] = useState<string[]>([]);
  const [previewHeaders, setPreviewHeaders] = useState<string[]>([]);
  const [previewRows, setPreviewRows] = useState<Record<string, unknown>[]>([]);
  const [previewTotal, setPreviewTotal] = useState(0);
  const [saving, setSaving] = useState(false);
  const [tempId, setTempId] = useState<number | null>(null);

  useEffect(() => {
    if (!open) return;
    void (async () => {
      try {
        const roots = await FileReaderAPI.allowedRoots();
        setAllowedRoots(roots);
      } catch {/* ignore */}
      try {
        const dbs = await ExternalDbConnectionAPI.getConnections();
        setDbList((dbs as any[]).map(d => ({ id: d.id, connection_name: d.connection_name })));
      } catch {/* ignore */}
      if (editingId) {
        try {
          const { config, mappings: m } = await FileReaderAPI.get(editingId);
          setCfg(config);
          setMappings(m);
          setTempId(editingId);
        } catch (e) {
          toast({ title: "조회 실패", description: (e as Error).message, variant: "destructive" });
        }
      } else {
        setCfg(defaultConfig);
        setMappings([]);
        setTempId(null);
      }
      setPreviewHeaders([]);
      setPreviewRows([]);
      setPreviewTotal(0);
    })();
  }, [open, editingId]);

  const addMapping = (fromCol?: string) => {
    setMappings(m => [...m, {
      from_column: fromCol || "",
      from_column_type: "header",
      to_column: fromCol || "",
      to_data_type: "TEXT",
      is_required: false,
      mapping_order: m.length,
    }]);
  };

  const updateMapping = (i: number, patch: Partial<FileReaderMapping>) => {
    setMappings(m => m.map((x, idx) => idx === i ? { ...x, ...patch } : x));
  };

  const removeMapping = (i: number) => {
    setMappings(m => m.filter((_, idx) => idx !== i));
  };

  const handlePreview = async () => {
    // 미리보기는 저장된 config 필요 — 임시 저장 후 preview
    let id = tempId;
    if (!id) {
      try {
        id = await FileReaderAPI.create({ ...cfg, name: cfg.name || `temp_${Date.now()}` });
        setTempId(id);
      } catch (e) {
        toast({ title: "임시 저장 실패", description: (e as Error).message, variant: "destructive" });
        return;
      }
    } else {
      try {
        await FileReaderAPI.update(id, cfg);
      } catch (e) {
        toast({ title: "설정 동기화 실패", description: (e as Error).message, variant: "destructive" });
        return;
      }
    }
    const inp = document.createElement("input");
    inp.type = "file";
    inp.accept = ".csv,.tsv,.txt,.xlsx,.xls";
    inp.onchange = async () => {
      if (!inp.files || inp.files.length === 0) return;
      try {
        const r = await FileReaderAPI.preview(id!, inp.files[0]);
        setPreviewHeaders(r.headers);
        setPreviewRows(r.sampleRows);
        setPreviewTotal(r.totalRows);
        toast({ title: "미리보기", description: `총 ${r.totalRows}행 / 헤더 ${r.headers.length}개` });
      } catch (e) {
        toast({ title: "미리보기 실패", description: (e as Error).message, variant: "destructive" });
      }
    };
    inp.click();
  };

  const handleSave = async () => {
    if (!cfg.name) {
      toast({ title: "이름 필수", variant: "destructive" });
      return;
    }
    setSaving(true);
    try {
      const payload = { ...cfg, mappings };
      if (tempId) {
        await FileReaderAPI.update(tempId, payload);
      } else {
        await FileReaderAPI.create(payload);
      }
      toast({ title: "저장 완료" });
      onSaved();
    } catch (e) {
      toast({ title: "저장 실패", description: (e as Error).message, variant: "destructive" });
    } finally {
      setSaving(false);
    }
  };

  return (
    <Dialog open={open} onOpenChange={(o) => !o && onClose()}>
      <DialogContent className="max-w-5xl max-h-[90vh] overflow-y-auto">
        <DialogHeader>
          <DialogTitle>{editingId ? "파일 리더 수정" : "새 파일 리더"}</DialogTitle>
        </DialogHeader>

        {/* 기본 정보 */}
        <div className="grid grid-cols-2 gap-3">
          <div>
            <Label>이름 *</Label>
            <Input value={cfg.name || ""} onChange={e => setCfg(c => ({ ...c, name: e.target.value }))} />
          </div>
          <div>
            <Label>파일 유형</Label>
            <Select value={cfg.file_type}
              onValueChange={(v: FileType) => setCfg(c => ({ ...c, file_type: v }))}>
              <SelectTrigger><SelectValue /></SelectTrigger>
              <SelectContent>
                <SelectItem value="csv">CSV</SelectItem>
                <SelectItem value="tsv">TSV</SelectItem>
                <SelectItem value="txt">TXT</SelectItem>
                <SelectItem value="xlsx">Excel (xlsx)</SelectItem>
                <SelectItem value="xls">Excel (xls)</SelectItem>
              </SelectContent>
            </Select>
          </div>

          <div>
            <Label>소스 모드</Label>
            <Select value={cfg.source_mode}
              onValueChange={(v: SourceMode) => setCfg(c => ({ ...c, source_mode: v }))}>
              <SelectTrigger><SelectValue /></SelectTrigger>
              <SelectContent>
                <SelectItem value="upload">UI 업로드 (1회 적재)</SelectItem>
                <SelectItem value="watch">감시 폴더 (주기 스캔)</SelectItem>
              </SelectContent>
            </Select>
          </div>
          <div className="flex items-end gap-2">
            <Switch checked={cfg.is_active === "Y"}
              onCheckedChange={(v) => setCfg(c => ({ ...c, is_active: v ? "Y" : "N" }))} />
            <span className="text-sm pb-2">활성</span>
          </div>

          {cfg.source_mode === "watch" && (
            <>
              <div className="col-span-2">
                <Label>호스트 경로 (감시 디렉토리)</Label>
                <Input value={cfg.host_path || ""} placeholder="/home/wace/file-imports/erp"
                  onChange={e => setCfg(c => ({ ...c, host_path: e.target.value }))} />
                <div className="text-xs text-muted-foreground mt-1">
                  허용 루트: {allowedRoots.length ? allowedRoots.join(", ") : "(로드 중)"}
                </div>
              </div>
              <div>
                <Label>파일 패턴 (glob)</Label>
                <Input value={cfg.file_pattern || "*"} placeholder="*.csv"
                  onChange={e => setCfg(c => ({ ...c, file_pattern: e.target.value }))} />
              </div>
              <div>
                <Label>스케줄 (cron 5/6필드)</Label>
                <Input value={cfg.cron_schedule || ""} placeholder="*/5 * * * *"
                  onChange={e => setCfg(c => ({ ...c, cron_schedule: e.target.value }))} />
              </div>
              <div>
                <Label>처리 후 동작</Label>
                <Select value={cfg.processed_action || "mark"}
                  onValueChange={v => setCfg(c => ({ ...c, processed_action: v as any }))}>
                  <SelectTrigger><SelectValue /></SelectTrigger>
                  <SelectContent>
                    <SelectItem value="mark">DB에 처리완료만 기록</SelectItem>
                    <SelectItem value="archive">_processed 하위로 이동</SelectItem>
                    <SelectItem value="delete">파일 삭제</SelectItem>
                  </SelectContent>
                </Select>
              </div>
              <div>
                <Label>archive 하위폴더명</Label>
                <Input value={cfg.archive_subdir || "_processed"}
                  onChange={e => setCfg(c => ({ ...c, archive_subdir: e.target.value }))} />
              </div>
            </>
          )}

          {/* 파싱 옵션 */}
          <div className="flex items-end gap-2">
            <Switch checked={cfg.has_header !== false}
              onCheckedChange={(v) => setCfg(c => ({ ...c, has_header: v }))} />
            <span className="text-sm pb-2">첫 행이 헤더</span>
          </div>
          <div>
            <Label>구분자 (CSV/TSV/TXT)</Label>
            <Input value={cfg.delimiter || ","}
              onChange={e => setCfg(c => ({ ...c, delimiter: e.target.value }))} />
          </div>
          <div>
            <Label>인코딩</Label>
            <Input value={cfg.encoding || "utf-8"}
              onChange={e => setCfg(c => ({ ...c, encoding: e.target.value }))} />
          </div>
          <div>
            <Label>건너뛸 행 수</Label>
            <Input type="number" value={cfg.skip_rows ?? 0}
              onChange={e => setCfg(c => ({ ...c, skip_rows: Number(e.target.value) }))} />
          </div>
          {(cfg.file_type === "xlsx" || cfg.file_type === "xls") && (
            <div className="col-span-2">
              <Label>시트 이름 (비우면 첫 시트)</Label>
              <Input value={cfg.sheet_name || ""}
                onChange={e => setCfg(c => ({ ...c, sheet_name: e.target.value }))} />
            </div>
          )}

          {/* 타겟 DB */}
          <div>
            <Label>타겟 DB</Label>
            <Select value={cfg.target_db_id ? String(cfg.target_db_id) : ""}
              onValueChange={v => setCfg(c => ({ ...c, target_db_id: Number(v) }))}>
              <SelectTrigger><SelectValue placeholder="DB 선택" /></SelectTrigger>
              <SelectContent>
                {dbList.map(d => (
                  <SelectItem key={d.id} value={String(d.id)}>{d.connection_name}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div>
            <Label>저장 모드</Label>
            <Select value={cfg.save_mode || "INSERT"}
              onValueChange={(v: SaveMode) => setCfg(c => ({ ...c, save_mode: v }))}>
              <SelectTrigger><SelectValue /></SelectTrigger>
              <SelectContent>
                <SelectItem value="INSERT">INSERT</SelectItem>
                <SelectItem value="UPSERT">UPSERT</SelectItem>
                <SelectItem value="REPLACE">REPLACE (전체 삭제 후 INSERT)</SelectItem>
              </SelectContent>
            </Select>
          </div>
          <div>
            <Label>타겟 스키마</Label>
            <Input value={cfg.target_schema || "public"}
              onChange={e => setCfg(c => ({ ...c, target_schema: e.target.value }))} />
          </div>
          <div>
            <Label>타겟 테이블</Label>
            <Input value={cfg.target_table || ""}
              onChange={e => setCfg(c => ({ ...c, target_table: e.target.value }))} />
          </div>
          {cfg.save_mode === "UPSERT" && (
            <div className="col-span-2">
              <Label>UPSERT conflict 컬럼 (콤마 구분)</Label>
              <Input value={cfg.conflict_keys || ""} placeholder="id,date"
                onChange={e => setCfg(c => ({ ...c, conflict_keys: e.target.value }))} />
            </div>
          )}
          <div className="col-span-2">
            <Label>설명</Label>
            <Textarea value={cfg.description || ""}
              onChange={e => setCfg(c => ({ ...c, description: e.target.value }))} />
          </div>
        </div>

        {/* 미리보기 */}
        <div className="border-t pt-3 mt-2">
          <div className="flex items-center justify-between mb-2">
            <Label className="text-base">샘플 파일 미리보기</Label>
            <Button variant="outline" size="sm" onClick={handlePreview}>
              <Upload className="w-3 h-3 mr-1" /> 샘플 업로드 + 미리보기
            </Button>
          </div>
          {previewHeaders.length > 0 && (
            <div className="text-xs space-y-2">
              <div className="text-muted-foreground">
                헤더 {previewHeaders.length}개 · 총 {previewTotal}행 (미리보기 {previewRows.length}행)
              </div>
              <div className="overflow-x-auto border rounded">
                <table className="text-xs">
                  <thead>
                    <tr>
                      {previewHeaders.map(h => (
                        <th key={h} className="border-b px-2 py-1 bg-muted text-left font-mono">{h}</th>
                      ))}
                    </tr>
                  </thead>
                  <tbody>
                    {previewRows.slice(0, 10).map((row, i) => (
                      <tr key={i}>
                        {previewHeaders.map(h => (
                          <td key={h} className="border-b px-2 py-1 font-mono">
                            {row[h] === null || row[h] === undefined ? "" : String(row[h])}
                          </td>
                        ))}
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
              <Button variant="outline" size="sm"
                onClick={() => previewHeaders.forEach(h => addMapping(h))}>
                <Plus className="w-3 h-3 mr-1" /> 모든 헤더 → 매핑에 추가
              </Button>
            </div>
          )}
        </div>

        {/* 매핑 */}
        <div className="border-t pt-3 mt-2">
          <div className="flex items-center justify-between mb-2">
            <Label className="text-base">컬럼 매핑 ({mappings.length}개)</Label>
            <Button variant="outline" size="sm" onClick={() => addMapping()}>
              <Plus className="w-3 h-3 mr-1" /> 행 추가
            </Button>
          </div>
          {mappings.length === 0 ? (
            <div className="text-xs text-muted-foreground text-center py-4 border rounded">
              매핑 없음. 샘플 파일을 업로드 후 "모든 헤더 → 매핑에 추가" 버튼을 사용하면 빠릅니다.
            </div>
          ) : (
            <div className="space-y-1 max-h-80 overflow-y-auto">
              <div className="grid grid-cols-12 gap-1 text-xs text-muted-foreground px-1">
                <div className="col-span-3">파일 컬럼명/인덱스</div>
                <div className="col-span-1">유형</div>
                <div className="col-span-3">→ 타겟 컬럼</div>
                <div className="col-span-2">데이터 타입</div>
                <div className="col-span-2">변환식</div>
                <div className="col-span-1"></div>
              </div>
              {mappings.map((m, i) => (
                <div key={i} className="grid grid-cols-12 gap-1">
                  <Input className="col-span-3 text-xs" value={m.from_column}
                    onChange={e => updateMapping(i, { from_column: e.target.value })} />
                  <Select value={m.from_column_type}
                    onValueChange={v => updateMapping(i, { from_column_type: v as any })}>
                    <SelectTrigger className="col-span-1 text-xs"><SelectValue /></SelectTrigger>
                    <SelectContent>
                      <SelectItem value="header">헤더</SelectItem>
                      <SelectItem value="index">인덱스</SelectItem>
                    </SelectContent>
                  </Select>
                  <Input className="col-span-3 text-xs" value={m.to_column}
                    onChange={e => updateMapping(i, { to_column: e.target.value })} />
                  <Select value={m.to_data_type}
                    onValueChange={v => updateMapping(i, { to_data_type: v })}>
                    <SelectTrigger className="col-span-2 text-xs"><SelectValue /></SelectTrigger>
                    <SelectContent>
                      <SelectItem value="TEXT">TEXT</SelectItem>
                      <SelectItem value="INTEGER">INTEGER</SelectItem>
                      <SelectItem value="NUMERIC">NUMERIC</SelectItem>
                      <SelectItem value="BOOLEAN">BOOLEAN</SelectItem>
                      <SelectItem value="DATE">DATE</SelectItem>
                      <SelectItem value="TIMESTAMP">TIMESTAMP</SelectItem>
                      <SelectItem value="TIMESTAMPTZ">TIMESTAMPTZ</SelectItem>
                      <SelectItem value="JSONB">JSONB</SelectItem>
                    </SelectContent>
                  </Select>
                  <Input className="col-span-2 text-xs" placeholder="TRIM / x*1000"
                    value={m.transform_expr || ""}
                    onChange={e => updateMapping(i, { transform_expr: e.target.value })} />
                  <Button variant="ghost" size="sm" className="col-span-1"
                    onClick={() => removeMapping(i)}>
                    <Trash2 className="w-3 h-3 text-rose-600" />
                  </Button>
                </div>
              ))}
            </div>
          )}
        </div>

        <DialogFooter>
          <Button variant="outline" onClick={onClose}><X className="w-3 h-3 mr-1" /> 취소</Button>
          <Button onClick={handleSave} disabled={saving}>{saving ? "저장 중..." : "저장"}</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
};

export default FileReaderConnectionModal;
