import { useEffect, useState } from "react";
import {
  App as AntApp,
  Button,
  Form,
  Input,
  InputNumber,
  Modal,
  Select,
  Space,
  Table,
  Tag,
  Typography,
} from "antd";
import {
  PlusOutlined,
  ReloadOutlined,
  PlayCircleOutlined,
  PauseCircleOutlined,
  ApiOutlined,
} from "@ant-design/icons";
import {
  Session,
  SyncChannel,
  SyncConflict,
  createSyncChannel,
  deleteSyncChannel,
  listSyncChannels,
  listSyncConflicts,
  reconcileSyncChannel,
  resolveSyncConflict,
  startSyncChannel,
  stopSyncChannel,
  testSyncEndpoints,
  updateSyncChannel,
} from "./api";

type EndpointForm = {
  driver: string;
  dsn: string;
  tables: string;
};

type FormValues = {
  name: string;
  direction: string;
  conflict_policy: string;
  poll_interval_ms: number;
  local: EndpointForm;
  remote: EndpointForm;
  pk_columns: string; // table:pk,table:pk
};

function parsePKs(s: string): Record<string, string> {
  const out: Record<string, string> = {};
  for (const part of (s || "").split(",")) {
    const [t, p] = part.split(":").map((x) => x.trim());
    if (t && p) out[t] = p;
  }
  return out;
}

function toChannelBody(v: FormValues, id?: string): Partial<SyncChannel> {
  return {
    id,
    name: v.name,
    direction: v.direction,
    conflict_policy: v.conflict_policy,
    poll_interval_ms: v.poll_interval_ms || 500,
    local: {
      driver: v.local.driver,
      dsn: v.local.dsn,
      tables: (v.local.tables || "")
        .split(",")
        .map((x) => x.trim())
        .filter(Boolean),
    },
    remote: {
      driver: v.remote.driver,
      dsn: v.remote.dsn,
      tables: (v.remote.tables || "")
        .split(",")
        .map((x) => x.trim())
        .filter(Boolean),
    },
    pk_columns: parsePKs(v.pk_columns),
  };
}

export function SyncPage(props: {
  session: Session;
  busy: boolean;
  setBusy: (v: boolean) => void;
  setError: (v: string) => void;
  setInfo: (v: string) => void;
}) {
  const { session, busy, setBusy, setError, setInfo } = props;
  const { message } = AntApp.useApp();
  const [items, setItems] = useState<SyncChannel[]>([]);
  const [conflicts, setConflicts] = useState<SyncConflict[]>([]);
  const [loading, setLoading] = useState(false);
  const [open, setOpen] = useState(false);
  const [editing, setEditing] = useState<SyncChannel | null>(null);
  const [form] = Form.useForm<FormValues>();

  async function refresh() {
    setLoading(true);
    try {
      const [ch, cf] = await Promise.all([
        listSyncChannels(session),
        listSyncConflicts(session, true),
      ]);
      setItems(ch.items || []);
      setConflicts(cf.items || []);
    } catch (e: any) {
      const msg = e.message || String(e);
      setError(msg);
      message.error(msg);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    void refresh();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [session.accessToken]);

  function openCreate() {
    setEditing(null);
    form.setFieldsValue({
      name: "本地 B ↔ 线上 A",
      direction: "bidirectional",
      conflict_policy: "queue",
      poll_interval_ms: 500,
      local: { driver: "sqlite", dsn: "file:./data/local.db", tables: "article" },
      remote: {
        driver: "mysql",
        dsn: "user:pass@tcp(127.0.0.1:3306)/app?parseTime=true&charset=utf8mb4",
        tables: "article",
      },
      pk_columns: "article:id",
    });
    setOpen(true);
  }

  function openEdit(ch: SyncChannel) {
    setEditing(ch);
    form.setFieldsValue({
      name: ch.name,
      direction: ch.direction,
      conflict_policy: ch.conflict_policy,
      poll_interval_ms: ch.poll_interval_ms,
      local: {
        driver: ch.local.driver,
        dsn: ch.local.dsn,
        tables: (ch.local.tables || []).join(","),
      },
      remote: {
        driver: ch.remote.driver,
        dsn: ch.remote.dsn,
        tables: (ch.remote.tables || []).join(","),
      },
      pk_columns: Object.entries(ch.pk_columns || {})
        .map(([t, p]) => `${t}:${p}`)
        .join(","),
    });
    setOpen(true);
  }

  async function onSave() {
    const v = await form.validateFields();
    setBusy(true);
    try {
      const body = toChannelBody(v, editing?.id);
      if (editing) await updateSyncChannel(session, editing.id, body);
      else await createSyncChannel(session, body);
      setOpen(false);
      setInfo("同步通道已保存");
      await refresh();
    } catch (e: any) {
      message.error(e.message || String(e));
    } finally {
      setBusy(false);
    }
  }

  async function onTest() {
    const v = await form.validateFields();
    setBusy(true);
    try {
      const body = toChannelBody(v);
      const res = await testSyncEndpoints(session, {
        local: body.local!,
        remote: body.remote!,
        side: "both",
      });
      const lok = (res.local as any)?.ok;
      const rok = (res.remote as any)?.ok;
      if (lok && rok) message.success("本地与线上数据库均可连接");
      else message.warning(JSON.stringify(res));
    } catch (e: any) {
      message.error(e.message || String(e));
    } finally {
      setBusy(false);
    }
  }

  return (
    <div className="panel">
      <Typography.Title level={4} style={{ marginTop: 0 }}>
        数据同步
      </Typography.Title>
      <Typography.Paragraph type="secondary">
        仅本<strong>公司顶级权限（管理员）</strong>可配置；通道按公司隔离，看不到其他公司的服务器。
        典型拓扑：A 线上 ↔ B 本地（双向），额外源 C 写入 B 再推到 A。
        防回声 + 版本幂等避免「多」；触发器与对账避免「漏」。
      </Typography.Paragraph>

      <Space style={{ marginBottom: 12 }}>
        <Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>
          新建通道
        </Button>
        <Button icon={<ReloadOutlined />} loading={loading} onClick={() => void refresh()}>
          刷新
        </Button>
      </Space>

      <Table
        rowKey="id"
        loading={loading}
        dataSource={items}
        pagination={false}
        columns={[
          { title: "名称", dataIndex: "name" },
          {
            title: "方向",
            dataIndex: "direction",
            render: (d: string) => <Tag>{d}</Tag>,
          },
          {
            title: "本地",
            render: (_: unknown, r: SyncChannel) => `${r.local.driver}`,
          },
          {
            title: "线上",
            render: (_: unknown, r: SyncChannel) => (
              <span>
                {r.remote.driver}
                <br />
                <Typography.Text type="secondary" style={{ fontSize: 12 }}>
                  {(r.remote.dsn || "").replace(/:[^:@/]+@/, ":***@")}
                </Typography.Text>
              </span>
            ),
          },
          {
            title: "状态",
            render: (_: unknown, r: SyncChannel) =>
              r.enabled ? <Tag color="green">运行中</Tag> : <Tag>已停止</Tag>,
          },
          {
            title: "统计",
            render: (_: unknown, r: SyncChannel) =>
              `↑${r.stats?.pushed_ok || 0} ↓${r.stats?.pulled_ok || 0} 冲突${r.stats?.conflicts || 0}`,
          },
          {
            title: "操作",
            render: (_: unknown, r: SyncChannel) => (
              <Space wrap>
                <Button size="small" onClick={() => openEdit(r)}>
                  配置
                </Button>
                {r.enabled ? (
                  <Button
                    size="small"
                    icon={<PauseCircleOutlined />}
                    onClick={async () => {
                      await stopSyncChannel(session, r.id);
                      await refresh();
                    }}
                  >
                    停止
                  </Button>
                ) : (
                  <Button
                    size="small"
                    type="primary"
                    icon={<PlayCircleOutlined />}
                    onClick={async () => {
                      try {
                        await startSyncChannel(session, r.id);
                        setInfo("同步已启动");
                        await refresh();
                      } catch (e: any) {
                        message.error(e.message || String(e));
                      }
                    }}
                  >
                    启动
                  </Button>
                )}
                <Button
                  size="small"
                  onClick={async () => {
                    setBusy(true);
                    try {
                      const res = await reconcileSyncChannel(session, r.id);
                      const parts = (res.reports || []).map(
                        (x) =>
                          `${x.table}: 补推${x.patched_push} 补拉${x.patched_pull}（仅本地${(x.only_local || []).length} 仅线上${(x.only_remote || []).length}）`
                      );
                      message.success(parts.length ? parts.join("；") : "对账完成，无差异");
                      setInfo("对账完成");
                      await refresh();
                    } catch (e: any) {
                      message.error(e.message || String(e));
                    } finally {
                      setBusy(false);
                    }
                  }}
                >
                  对账
                </Button>
                <Button
                  size="small"
                  danger
                  onClick={async () => {
                    await deleteSyncChannel(session, r.id);
                    await refresh();
                  }}
                >
                  删除
                </Button>
              </Space>
            ),
          },
        ]}
      />

      <Typography.Title level={5} style={{ marginTop: 24 }}>
        冲突队列（未解决）
      </Typography.Title>
      <Table
        rowKey="id"
        dataSource={conflicts}
        pagination={false}
        columns={[
          { title: "通道", dataIndex: "channel_id", ellipsis: true },
          { title: "表", dataIndex: "table" },
          { title: "主键", dataIndex: "row_pk" },
          { title: "来源", dataIndex: "source" },
          { title: "说明", dataIndex: "message", ellipsis: true },
          {
            title: "操作",
            render: (_: unknown, r: SyncConflict) => (
              <Space>
                <Button
                  size="small"
                  onClick={async () => {
                    await resolveSyncConflict(session, r.id, "keep_target");
                    await refresh();
                  }}
                >
                  保留目标
                </Button>
                <Button
                  size="small"
                  onClick={async () => {
                    await resolveSyncConflict(session, r.id, "discard");
                    await refresh();
                  }}
                >
                  丢弃
                </Button>
              </Space>
            ),
          },
        ]}
      />

      <Modal
        title={editing ? "编辑同步通道" : "新建同步通道"}
        open={open}
        onCancel={() => setOpen(false)}
        width={720}
        footer={
          <Space>
            <Button icon={<ApiOutlined />} loading={busy} onClick={() => void onTest()}>
              测试连接
            </Button>
            <Button onClick={() => setOpen(false)}>取消</Button>
            <Button type="primary" loading={busy} onClick={() => void onSave()}>
              保存
            </Button>
          </Space>
        }
      >
        <Form form={form} layout="vertical">
          <Form.Item name="name" label="名称" rules={[{ required: true }]}>
            <Input />
          </Form.Item>
          <Form.Item name="direction" label="方向" rules={[{ required: true }]}>
            <Select
              options={[
                { value: "local_to_remote", label: "本地 → 线上" },
                { value: "remote_to_local", label: "线上 → 本地" },
                { value: "bidirectional", label: "双向" },
              ]}
            />
          </Form.Item>
          <Form.Item name="conflict_policy" label="冲突策略">
            <Select
              options={[
                { value: "queue", label: "入冲突队列（推荐）" },
                { value: "lww_source", label: "源端覆盖" },
                { value: "lww_target", label: "保留目标" },
              ]}
            />
          </Form.Item>
          <Form.Item name="poll_interval_ms" label="轮询间隔(ms)">
            <InputNumber min={100} max={60000} style={{ width: "100%" }} />
          </Form.Item>

          <Typography.Text strong>本地库</Typography.Text>
          <Form.Item name={["local", "driver"]} label="驱动" rules={[{ required: true }]}>
            <Select options={[{ value: "sqlite" }, { value: "mysql" }, { value: "postgres" }]} />
          </Form.Item>
          <Form.Item
            name={["local", "dsn"]}
            label="DSN"
            rules={[{ required: true }]}
            extra="SQLite 例：file:./data/local.db"
          >
            <Input.TextArea rows={2} />
          </Form.Item>
          <Form.Item name={["local", "tables"]} label="表（逗号分隔）" rules={[{ required: true }]}>
            <Input placeholder="article,order" />
          </Form.Item>

          <Typography.Text strong>线上库（可随时改地址）</Typography.Text>
          <Form.Item name={["remote", "driver"]} label="驱动" rules={[{ required: true }]}>
            <Select options={[{ value: "mysql" }, { value: "postgres" }, { value: "sqlite" }]} />
          </Form.Item>
          <Form.Item
            name={["remote", "dsn"]}
            label="线上 DSN"
            rules={[{ required: true }]}
            extra="MySQL 例：user:pass@tcp(host:3306)/dbname?parseTime=true"
          >
            <Input.TextArea rows={2} />
          </Form.Item>
          <Form.Item name={["remote", "tables"]} label="表（逗号分隔）" rules={[{ required: true }]}>
            <Input />
          </Form.Item>
          <Form.Item
            name="pk_columns"
            label="主键映射"
            extra="格式 table:pk，多个用逗号。默认每表 id"
          >
            <Input placeholder="article:id" />
          </Form.Item>
        </Form>
      </Modal>
    </div>
  );
}
