import { useCallback, useEffect, useMemo, useState } from "react"
import {
  Button,
  Empty,
  Form,
  Input,
  InputNumber,
  Modal,
  Popconfirm,
  Select,
  Space,
  Table,
  Typography,
  type TableColumnsType,
} from "antd"
import { PlusOutlined, ReloadOutlined } from "@ant-design/icons"
import {
  createInstanceNatAcl,
  deleteInstanceNatAcl,
  listInstanceNatAcl,
  type InstanceNatAclItem,
  type InstanceNatAclMeta,
  type ServerDetail,
} from "../../api/servers"
import { toast } from "../../utils/toast"

const { Text } = Typography

interface NatAclFormValues {
  name: string
  ext_port?: number | null
  int_port: number
  protocol: 1 | 2 | 3
}

function externalAddress(natHostIp: string | null, port: number | null | undefined) {
  if (!natHostIp || !port) return "-"
  return `${natHostIp}:${port}`
}

function internalAddress(record: InstanceNatAclItem) {
  const ip = record.int_ip || ""
  if (ip && record.int_port) return `${ip}:${record.int_port}`
  if (ip) return ip
  if (record.int_port) return `内网端口 ${record.int_port}`
  return "-"
}

function protocolLabel(value: number | null | undefined) {
  if (value === 1) return "TCP"
  if (value === 2) return "UDP"
  if (value === 3) return "TCP+UDP"
  return "-"
}

function errorDetail(error: unknown, fallback: string) {
  return (error as { response?: { data?: { detail?: string } } })?.response?.data?.detail || fallback
}

export default function NatForwardingTab({ server }: { server: ServerDetail }) {
  const [form] = Form.useForm<NatAclFormValues>()
  const [loading, setLoading] = useState(false)
  const [saving, setSaving] = useState(false)
  const [deletingId, setDeletingId] = useState<number | null>(null)
  const [modalOpen, setModalOpen] = useState(false)
  const [items, setItems] = useState<InstanceNatAclItem[]>([])
  const [natHostIp, setNatHostIp] = useState<string | null>(null)
  const [meta, setMeta] = useState<InstanceNatAclMeta>({ total: 0, total_page: 0, page: 1, per_page: 20 })
  const [page, setPage] = useState(1)
  const [pageSize, setPageSize] = useState(20)

  const limit = Number(server.nat_acl_limit || 0)
  const limitReached = limit > 0 && meta.total >= limit

  const reload = useCallback(async () => {
    setLoading(true)
    try {
      const res = await listInstanceNatAcl(server.id, {
        page,
        per_page: pageSize,
        orderby: "id",
        sort: "desc",
        list_type: "page",
      })
      const data = res.data.data
      setItems(data?.list ?? [])
      setMeta(data?.meta ?? { total: 0, total_page: 0, page, per_page: pageSize })
      setNatHostIp(data?.nat_host_ip ?? null)
    } catch (error: unknown) {
      toast.error(errorDetail(error, "NAT 转发列表加载失败"))
      setItems([])
      setNatHostIp(null)
      setMeta({ total: 0, total_page: 0, page, per_page: pageSize })
    } finally {
      setLoading(false)
    }
  }, [page, pageSize, server.id])

  useEffect(() => {
    void reload()
  }, [reload])

  const copyExternalAddress = async (value: string) => {
    try {
      await navigator.clipboard.writeText(value)
      toast.success("已复制外网地址")
    } catch {
      toast.error("复制失败")
    }
  }

  const openCreate = () => {
    form.setFieldsValue({ name: "", ext_port: null, int_port: 22, protocol: 1 })
    setModalOpen(true)
  }

  const handleCreate = async () => {
    const values = await form.validateFields()
    setSaving(true)
    try {
      await createInstanceNatAcl(server.id, {
        name: values.name.trim(),
        ext_port: values.ext_port ?? null,
        int_port: values.int_port,
        protocol: values.protocol,
      })
      toast.success("NAT 转发已添加")
      setModalOpen(false)
      setPage(1)
      await reload()
    } catch (error: unknown) {
      toast.error(errorDetail(error, "添加 NAT 转发失败"))
    } finally {
      setSaving(false)
    }
  }

  const handleDelete = useCallback(async (record: InstanceNatAclItem) => {
    if (!record.id) return
    setDeletingId(record.id)
    try {
      await deleteInstanceNatAcl(server.id, record.id)
      toast.success("NAT 转发已删除")
      await reload()
    } catch (error: unknown) {
      toast.error(errorDetail(error, "删除 NAT 转发失败"))
    } finally {
      setDeletingId(null)
    }
  }, [reload, server.id])

  const columns: TableColumnsType<InstanceNatAclItem> = useMemo(() => [
    { title: "名称", dataIndex: "name", render: (value) => value || "-" },
    {
      title: "外网地址",
      render: (_, record) => {
        const value = externalAddress(natHostIp, record.ext_port)
        return value === "-" ? "-" : (
          <Text style={{ color: "#1677ff", cursor: "pointer" }} onClick={() => void copyExternalAddress(value)}>
            {value}
          </Text>
        )
      },
    },
    { title: "内网地址", render: (_, record) => internalAddress(record) },
    { title: "协议", width: 110, render: (_, record) => protocolLabel(record.protocol) },
    {
      title: "操作",
      width: 110,
      render: (_, record) => (
        <Popconfirm
          title="删除 NAT 转发？"
          okText="删除"
          cancelText="取消"
          okButtonProps={{ danger: true }}
          disabled={!record.id}
          onConfirm={() => void handleDelete(record)}
        >
          <Button size="small" danger disabled={!record.id} loading={deletingId === record.id}>
            删除
          </Button>
        </Popconfirm>
      ),
    },
  ], [deletingId, handleDelete, natHostIp])

  if (!server.upstream_id) {
    return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="实例尚未开通，暂无 NAT 转发规则" />
  }

  return (
    <Space direction="vertical" size={12} style={{ width: "100%" }}>
      <Space wrap>
        <Button type="primary" icon={<PlusOutlined />} disabled={limitReached} onClick={openCreate}>
          添加 NAT 转发
        </Button>
        <Button icon={<ReloadOutlined />} loading={loading} onClick={() => void reload()}>
          刷新
        </Button>
        <Text type="secondary">NAT 转发限制：{limit > 0 ? `${meta.total} / ${limit}` : "-"}</Text>
      </Space>

      <Table
        rowKey={(record) => String(record.id ?? `${record.ext_port}-${record.int_port}-${record.name}`)}
        loading={loading}
        columns={columns}
        dataSource={items}
        pagination={{
          current: page,
          pageSize,
          total: meta.total,
          showSizeChanger: true,
          pageSizeOptions: [10, 20, 50, 100],
        }}
        onChange={(pagination) => {
          setPage(pagination.current || 1)
          setPageSize(pagination.pageSize || pageSize)
        }}
        locale={{ emptyText: <Empty description="暂无 NAT 转发规则" /> }}
      />

      <Modal
        title="添加 NAT 转发"
        open={modalOpen}
        okText="添加"
        cancelText="取消"
        confirmLoading={saving}
        onOk={handleCreate}
        onCancel={() => setModalOpen(false)}
        destroyOnHidden
      >
        <Form<NatAclFormValues> form={form} layout="vertical" style={{ marginTop: 20 }}>
          <Form.Item name="name" label="名称" rules={[{ required: true, message: "请输入名称" }]}>
            <Input maxLength={100} placeholder="例如 SSH" allowClear />
          </Form.Item>
          <Form.Item
            name="ext_port"
            label="外部端口"
            rules={[{
              validator: (_, value: number | null | undefined) => (
                value == null || ![22, 80, 443].includes(Number(value))
                  ? Promise.resolve()
                  : Promise.reject(new Error("外部端口不能使用 22、80、443"))
              ),
            }]}
          >
            <InputNumber min={0} max={65535} precision={0} placeholder="不填则由上游分配" style={{ width: "100%" }} />
          </Form.Item>
          <Form.Item name="int_port" label="内部端口" rules={[{ required: true, message: "请输入内部端口" }]}>
            <InputNumber min={0} max={65535} precision={0} style={{ width: "100%" }} />
          </Form.Item>
          <Form.Item name="protocol" label="协议" rules={[{ required: true, message: "请选择协议" }]}>
            <Select
              options={[
                { value: 1, label: "TCP" },
                { value: 2, label: "UDP" },
                { value: 3, label: "TCP+UDP" },
              ]}
            />
          </Form.Item>
        </Form>
      </Modal>
    </Space>
  )
}
