"use client";

import { useEffect, useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import { toast } from "sonner";
import {
  api,
  type Connection,
  type Pipeline,
  type StreamConfig,
  type StreamInfo,
} from "@/components/api";
import { keyValueLinesFromJson, parseKeyValueLines } from "@/components/kv";
import { Button } from "@/components/ui/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";

const MODES = [
  { value: "full-refresh", label: "full-refresh（全量覆盖，默认）" },
  { value: "truncate", label: "truncate（清空后写入）" },
  { value: "incremental", label: "incremental（增量）" },
  { value: "snapshot", label: "snapshot（快照）" },
];

export function PipelineForm({ initial }: { initial?: Pipeline }) {
  const router = useRouter();
  const isEdit = !!initial;
  const [connections, setConnections] = useState<Connection[]>([]);
  const [connError, setConnError] = useState<string | null>(null);

  const [name, setName] = useState(initial?.name ?? "");
  const [sourceId, setSourceId] = useState(
    initial ? String(initial.source_conn_id) : ""
  );
  const [targetId, setTargetId] = useState(
    initial ? String(initial.target_conn_id) : ""
  );
  const [mode, setMode] = useState(initial?.mode ?? "full-refresh");
  const [schemaSync, setSchemaSync] = useState(
    initial ? !!initial.schema_sync : true
  );
  const [schemaScope, setSchemaScope] = useState(
    initial?.schema_scope ?? "selected"
  );
  const [includeFk, setIncludeFk] = useState(initial ? !!initial.include_fk : false);
  const [envText, setEnvText] = useState(() =>
    initial ? keyValueLinesFromJson(initial.env) : ""
  );

  const [streamList, setStreamList] = useState<StreamInfo[] | null>(null);
  const [streamsLoading, setStreamsLoading] = useState(false);
  const [selected, setSelected] = useState<Record<string, StreamConfig>>(() => {
    if (!initial) return {};
    try {
      const streams = JSON.parse(initial.streams || "[]") as StreamConfig[];
      return Object.fromEntries(streams.map((s) => [s.name, s]));
    } catch {
      return {};
    }
  });
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    api<Connection[]>("/api/connections")
      .then(setConnections)
      .catch((e) => setConnError(e instanceof Error ? e.message : "加载失败"));
  }, []);

  // 编辑模式：加载现有流水线后自动拉取表列表，回填勾选状态
  useEffect(() => {
    if (isEdit && sourceId) void loadStreams();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isEdit, sourceId]);

  const selectedList = useMemo(() => Object.values(selected), [selected]);

  async function loadStreams() {
    if (!sourceId) return;
    setStreamsLoading(true);
    try {
      const list = await api<StreamInfo[]>(
        `/api/connections/${sourceId}/streams`
      );
      setStreamList(list);
      if (list.length === 0) toast.info("该连接没有可同步的表");
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "加载表失败");
    } finally {
      setStreamsLoading(false);
    }
  }

  function toggleStream(s: StreamInfo, checked: boolean) {
    setSelected((m) => {
      const next = { ...m };
      if (checked) next[s.name] = m[s.name] ?? { name: s.name };
      else delete next[s.name];
      return next;
    });
  }

  function selectAll(on: boolean) {
    if (!streamList) return;
    setSelected(
      on
        ? Object.fromEntries(
            streamList.map((s) => [s.name, selected[s.name] ?? { name: s.name }])
          )
        : {}
    );
  }

  function setStreamField(
    name: string,
    field: "primary_key" | "update_key",
    value: string
  ) {
    setSelected((m) => ({
      ...m,
      [name]: { ...m[name], name, [field]: value || undefined },
    }));
  }

  async function submit() {
    if (!name.trim()) return toast.error("请填写流水线名称");
    if (!sourceId || !targetId) return toast.error("请选择源连接和目标连接");
    if (sourceId === targetId) return toast.error("源连接和目标连接不能相同");
    if (selectedList.length === 0) return toast.error("请至少选择一张表");

    setSaving(true);
    const payload = {
      name: name.trim(),
      source_conn_id: Number(sourceId),
      target_conn_id: Number(targetId),
      schema_sync: schemaSync ? 1 : 0,
      schema_scope: schemaScope,
      include_fk: includeFk ? 1 : 0,
      mode,
      streams: JSON.stringify(selectedList),
      env: parseKeyValueLines(envText),
    };
    try {
      const p = isEdit
        ? await api<Pipeline>(`/api/pipelines/${initial.id}`, {
            method: "PUT",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(payload),
          })
        : await api<Pipeline>("/api/pipelines", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(payload),
          });
      toast.success(isEdit ? "流水线已保存" : "流水线已创建");
      router.push(`/pipelines/${p.id}`);
    } catch (e) {
      toast.error(e instanceof Error ? e.message : isEdit ? "保存失败" : "创建失败");
      setSaving(false);
    }
  }

  const cancelHref = isEdit ? `/pipelines/${initial.id}` : "/pipelines";

  return (
    <div className="flex max-w-3xl flex-col gap-6">
      <h1 className="text-xl font-semibold">
        {isEdit ? `编辑流水线：${initial.name}` : "新建流水线"}
      </h1>

      {connError ? (
        <div className="text-sm text-red-500">连接列表加载失败：{connError}</div>
      ) : null}

      <Card>
        <CardHeader>
          <CardTitle>基本信息</CardTitle>
        </CardHeader>
        <CardContent className="grid gap-4">
          <div className="grid gap-1.5">
            <Label htmlFor="p-name">名称</Label>
            <Input
              id="p-name"
              value={name}
              onChange={(e) => setName(e.target.value)}
              placeholder="例如：测试库 → 本地 dev"
            />
          </div>
          <div className="grid grid-cols-2 gap-4">
            <div className="grid gap-1.5">
              <Label>源连接</Label>
              <Select
                value={sourceId}
                onValueChange={(v) => {
                  setSourceId(String(v));
                  setStreamList(null);
                  setSelected({});
                }}
              >
                <SelectTrigger className="w-full">
                  <SelectValue placeholder="选择源连接">
                    {(v) => {
                      const c = connections.find((x) => String(x.id) === String(v));
                      return c ? `${c.name}（${c.database}）` : String(v ?? "");
                    }}
                  </SelectValue>
                </SelectTrigger>
                <SelectContent>
                  {connections.map((c) => (
                    <SelectItem key={c.id} value={String(c.id)}>
                      {c.name}（{c.database}）
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div className="grid gap-1.5">
              <Label>目标连接</Label>
              <Select value={targetId} onValueChange={(v) => setTargetId(String(v))}>
                <SelectTrigger className="w-full">
                  <SelectValue placeholder="选择目标连接">
                    {(v) => {
                      const c = connections.find((x) => String(x.id) === String(v));
                      return c ? `${c.name}（${c.database}）` : String(v ?? "");
                    }}
                  </SelectValue>
                </SelectTrigger>
                <SelectContent>
                  {connections.map((c) => (
                    <SelectItem key={c.id} value={String(c.id)}>
                      {c.name}（{c.database}）
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
          </div>
          <div className="grid gap-1.5">
            <Label>同步模式</Label>
            <Select value={mode} onValueChange={(v) => setMode(String(v))}>
              <SelectTrigger className="w-full">
                <SelectValue>
                  {(v) => MODES.find((m) => m.value === v)?.label ?? String(v ?? "")}
                </SelectValue>
              </SelectTrigger>
              <SelectContent>
                {MODES.map((m) => (
                  <SelectItem key={m.value} value={m.value}>
                    {m.label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="flex items-center justify-between rounded-md border p-3">
            <div className="flex flex-col gap-0.5">
              <Label>Schema 同步</Label>
              <span className="text-xs text-muted-foreground">
                先用 Atlas 同步 schema（表/索引/约束），再迁移数据
              </span>
            </div>
            <Switch checked={schemaSync} onCheckedChange={(c) => setSchemaSync(!!c)} />
          </div>
          <div
            className={`flex items-center justify-between rounded-md border p-3 ${
              schemaSync ? "" : "opacity-50"
            }`}
          >
            <div className="flex flex-col gap-0.5">
              <Label>Schema 同步范围</Label>
              <span className="text-xs text-muted-foreground">
                整库模式会同步源库所有表，且目标库独有的表可能被删除
              </span>
            </div>
            <Select
              value={schemaScope}
              onValueChange={(v) => setSchemaScope(String(v))}
              disabled={!schemaSync}
            >
              <SelectTrigger className="w-36">
                <SelectValue>
                  {(v) => (v === "all" ? "整个库" : "仅选中的表")}
                </SelectValue>
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="selected">仅选中的表</SelectItem>
                <SelectItem value="all">整个库</SelectItem>
              </SelectContent>
            </Select>
          </div>
          <div
            className={`flex items-center justify-between rounded-md border p-3 ${
              schemaSync ? "" : "opacity-50"
            }`}
          >
            <div className="flex flex-col gap-0.5">
              <Label>包含外键约束</Label>
              <span className="text-xs text-muted-foreground">
                关闭可避免选中表引用了未迁移表导致的失败；排除父表时引用它的外键会自动跳过
              </span>
            </div>
            <Switch
              checked={includeFk}
              onCheckedChange={(c) => setIncludeFk(!!c)}
              disabled={!schemaSync}
            />
          </div>
          <div className="grid gap-1.5">
            <Label htmlFor="p-env">环境变量</Label>
            <Textarea
              id="p-env"
              className="font-mono text-xs"
              rows={3}
              value={envText}
              onChange={(e) => setEnvText(e.target.value)}
              placeholder={"SLING_THREADS=4"}
            />
            <p className="text-xs text-muted-foreground">
              每行一个 key=value，写入 sling replication 的顶层 env（sling 会导出为进程环境变量），如
              SLING_THREADS=4。
            </p>
          </div>
        </CardContent>
      </Card>

      <Card>
        <CardHeader>
          <CardTitle>选择要同步的表</CardTitle>
          <CardDescription>
            选择源连接后点击「加载表」，勾选需要同步的表。
          </CardDescription>
        </CardHeader>
        <CardContent className="flex flex-col gap-3">
          <div className="flex items-center gap-2">
            <Button
              variant="outline"
              onClick={loadStreams}
              disabled={!sourceId || streamsLoading}
            >
              {streamsLoading ? "加载中…" : "加载表"}
            </Button>
            {streamList && streamList.length > 0 ? (
              <>
                <Button variant="ghost" size="sm" onClick={() => selectAll(true)}>
                  全选
                </Button>
                <Button variant="ghost" size="sm" onClick={() => selectAll(false)}>
                  全不选
                </Button>
                <span className="text-xs text-muted-foreground">
                  已选 {selectedList.length} / {streamList.length}
                </span>
              </>
            ) : null}
          </div>

          {streamList === null ? (
            selectedList.length > 0 ? (
              <div className="text-sm text-muted-foreground">
                当前已选 {selectedList.length} 张表（
                {selectedList.map((s) => s.name).join("、")}），点击「加载表」可修改。
              </div>
            ) : null
          ) : streamList.length === 0 ? (
            <div className="text-sm text-muted-foreground">没有可同步的表。</div>
          ) : (
            <div className="max-h-96 overflow-auto rounded-md border">
              {streamList.map((s) => {
                const checked = !!selected[s.name];
                return (
                  <div
                    key={s.name}
                    className="flex items-center gap-3 border-b px-3 py-2 last:border-b-0"
                  >
                    <Checkbox
                      checked={checked}
                      onCheckedChange={(c) => toggleStream(s, !!c)}
                    />
                    <span className="flex-1 font-mono text-sm">{s.name}</span>
                    {mode === "incremental" && checked ? (
                      <div className="flex items-center gap-2">
                        <Input
                          className="h-7 w-36 font-mono text-xs"
                          placeholder="primary_key"
                          value={selected[s.name].primary_key ?? ""}
                          onChange={(e) =>
                            setStreamField(s.name, "primary_key", e.target.value)
                          }
                        />
                        <Input
                          className="h-7 w-36 font-mono text-xs"
                          placeholder="update_key"
                          value={selected[s.name].update_key ?? ""}
                          onChange={(e) =>
                            setStreamField(s.name, "update_key", e.target.value)
                          }
                        />
                      </div>
                    ) : null}
                  </div>
                );
              })}
            </div>
          )}
        </CardContent>
      </Card>

      <div className="flex gap-2">
        <Button onClick={submit} disabled={saving}>
          {saving
            ? isEdit
              ? "保存中…"
              : "创建中…"
            : isEdit
              ? "保存修改"
              : "创建流水线"}
        </Button>
        <Button variant="outline" onClick={() => router.push(cancelHref)}>
          取消
        </Button>
      </div>
    </div>
  );
}
