import { useCallback, useEffect, useMemo, useState } from "react"
import { Link, useNavigate, useParams } from "react-router-dom"
import {
  ArrowLeftOutlined,
  DeleteOutlined,
  EditOutlined,
  PlusOutlined,
  ReloadOutlined,
  SafetyCertificateOutlined,
  ThunderboltOutlined,
} from "@ant-design/icons"
import { Button, Card, Empty, Form, Input, Modal, Popconfirm, Select, Space, Switch, Tag, Typography } from "antd"
import {
  createSecurityGroupRule,
  deleteSecurityGroup,
  deleteSecurityGroupRule,
  getSecurityGroup,
  listSecurityGroupRuleProtocols,
  type SecurityGroupDetail as SecurityGroupDetailData,
  type SecurityGroupRule,
  type SecurityGroupRulePayload,
  type SecurityGroupRuleProtocol,
  updateSecurityGroup,
  updateSecurityGroupRule,
} from "../api/securityGroups"
import { toast } from "../utils/toast"

const { Title, Paragraph, Text } = Typography
const PORT_RANGE_PATTERN = /^\d{1,5}(-\d{1,5})?$/
const IPV4_CIDR_PATTERN = /^(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?$/

const FALLBACK_PROTOCOLS: SecurityGroupRuleProtocol[] = [
  { name: "全部协议", value: "all", port: "1-65535" },
  { name: "全部 TCP", value: "all_tcp", port: "1-65535" },
  { name: "全部 UDP", value: "all_udp", port: "1-65535" },
  { name: "TCP", value: "tcp", port: "" },
  { name: "UDP", value: "udp", port: "" },
  { name: "ICMP", value: "icmp", port: "1-65535" },
  { name: "SSH", value: "ssh", port: "22" },
  { name: "HTTP", value: "http", port: "80" },
  { name: "HTTPS", value: "https", port: "443" },
  { name: "RDP", value: "rdp", port: "3389" },
  { name: "MySQL", value: "mysql", port: "3306" },
  { name: "Redis", value: "redis", port: "6379" },
  { name: "PostgreSQL", value: "postgresql", port: "5432" },
  { name: "MSSQL", value: "mssql", port: "1433" },
  { name: "GRE", value: "gre", port: "1-65535" },
]

const COMMON_RULES: Array<{
  name: string
  description: string
  direction: "in" | "out"
  protocol: string
  port: string
  ip: string
}> = [
  { name: "SSH", description: "Linux 远程登录", direction: "in", protocol: "ssh", port: "22", ip: "0.0.0.0/0" },
  { name: "HTTP", description: "网站 HTTP", direction: "in", protocol: "http", port: "80", ip: "0.0.0.0/0" },
  { name: "HTTPS", description: "网站 HTTPS", direction: "in", protocol: "https", port: "443", ip: "0.0.0.0/0" },
  { name: "RDP", description: "Windows 远程桌面", direction: "in", protocol: "rdp", port: "3389", ip: "0.0.0.0/0" },
  { name: "MySQL", description: "MySQL 数据库", direction: "in", protocol: "mysql", port: "3306", ip: "0.0.0.0/0" },
  { name: "Redis", description: "Redis 数据库", direction: "in", protocol: "redis", port: "6379", ip: "0.0.0.0/0" },
  { name: "PostgreSQL", description: "PostgreSQL 数据库", direction: "in", protocol: "postgresql", port: "5432", ip: "0.0.0.0/0" },
  { name: "全部出站", description: "允许全部出站流量", direction: "out", protocol: "all", port: "1-65535", ip: "0.0.0.0/0" },
]

interface RuleFormValues {
  description?: string
  direction: "in" | "out"
  protocol: string
  port: string
  ip: string
  lock: boolean
}

function formatDate(value?: string | null) {
  if (!value || value === "0000-00-00 00:00:00") return "-"
  const date = new Date(value)
  if (Number.isNaN(date.getTime())) return value
  return date.toLocaleString("zh-CN", { hour12: false })
}

function normalizeDirection(value?: string | null): "in" | "out" {
  if (!value) return "in"
  const normalized = value.toLowerCase()
  if (normalized === "out" || normalized === "egress" || value === "出站") return "out"
  return "in"
}

function directionLabel(value?: string | null) {
  return normalizeDirection(value) === "in" ? "入站" : "出站"
}

function protocolKey(value?: string | null) {
  return (value || "all").toLowerCase()
}

function protocolLabel(value: string | null | undefined, protocolMap: Map<string, SecurityGroupRuleProtocol>) {
  const key = protocolKey(value)
  return protocolMap.get(key)?.name || key.toUpperCase()
}

function isValidPortRange(value?: string) {
  if (!value || !PORT_RANGE_PATTERN.test(value)) return false
  const values = value.split("-").map((item) => Number(item))
  if (values.some((item) => !Number.isInteger(item) || item < 1 || item > 65535)) return false
  return values.length === 1 || values[0] <= values[1]
}

function isValidIpv4Cidr(value?: string) {
  if (!value || !IPV4_CIDR_PATTERN.test(value)) return false
  const [ip, cidr] = value.split("/")
  const segments = ip.split(".").map((item) => Number(item))
  if (segments.some((item) => !Number.isInteger(item) || item < 0 || item > 255)) return false
  if (cidr === undefined) return true
  const cidrValue = Number(cidr)
  return Number.isInteger(cidrValue) && cidrValue >= 0 && cidrValue <= 32
}

function isSameRule(rule: SecurityGroupRule, payload: Pick<SecurityGroupRulePayload, "direction" | "protocol" | "port" | "ip">) {
  return (
    normalizeDirection(rule.direction) === payload.direction
    && protocolKey(rule.protocol) === payload.protocol.toLowerCase()
    && String(rule.port || "").trim() === payload.port.trim()
    && String(rule.ip || "").trim() === payload.ip.trim()
  )
}

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

export default function SecurityGroupDetail() {
  const { id } = useParams()
  const navigate = useNavigate()
  const [groupForm] = Form.useForm<{ name: string }>()
  const [ruleForm] = Form.useForm<RuleFormValues>()
  const [detail, setDetail] = useState<SecurityGroupDetailData | null>(null)
  const [protocols, setProtocols] = useState<SecurityGroupRuleProtocol[]>(FALLBACK_PROTOCOLS)
  const [loading, setLoading] = useState(true)
  const [editOpen, setEditOpen] = useState(false)
  const [ruleOpen, setRuleOpen] = useState(false)
  const [commonOpen, setCommonOpen] = useState(false)
  const [editingRule, setEditingRule] = useState<SecurityGroupRule | null>(null)
  const [saving, setSaving] = useState(false)
  const [ruleSaving, setRuleSaving] = useState(false)
  const [deleting, setDeleting] = useState(false)
  const [deletingRuleId, setDeletingRuleId] = useState<number | string | null>(null)

  const protocolMap = useMemo(
    () => new Map(protocols.map((item) => [item.value.toLowerCase(), item])),
    [protocols],
  )

  const protocolOptions = useMemo(
    () => protocols.map((item) => ({
      label: item.port ? `${item.name} (${item.port})` : item.name,
      value: item.value,
    })),
    [protocols],
  )

  const loadDetail = useCallback(async () => {
    if (!id) {
      setLoading(false)
      return
    }

    setLoading(true)
    try {
      const res = await getSecurityGroup(id, true)
      setDetail(res.data.data)
    } catch (error) {
      toast.error(errorDetail(error, "安全组详情加载失败"))
      setDetail(null)
    } finally {
      setLoading(false)
    }
  }, [id])

  const loadProtocols = useCallback(async () => {
    try {
      const res = await listSecurityGroupRuleProtocols()
      const list = res.data.data ?? []
      if (list.length > 0) setProtocols(list)
    } catch {
      setProtocols(FALLBACK_PROTOCOLS)
    }
  }, [])

  useEffect(() => {
    const timer = window.setTimeout(() => {
      void loadDetail()
      void loadProtocols()
    }, 0)
    return () => window.clearTimeout(timer)
  }, [loadDetail, loadProtocols])

  const openEditModal = () => {
    if (!detail) return
    groupForm.setFieldsValue({ name: detail.name })
    setEditOpen(true)
  }

  const handleUpdate = async () => {
    if (!id) return
    const values = await groupForm.validateFields()
    const name = values.name.trim()
    if (!name) {
      groupForm.setFields([{ name: "name", errors: ["请输入安全组名称"] }])
      return
    }

    setSaving(true)
    try {
      await updateSecurityGroup(id, { name })
      toast.success("安全组修改成功")
      setEditOpen(false)
      await loadDetail()
    } catch (error) {
      toast.error(errorDetail(error, "安全组修改失败"))
    } finally {
      setSaving(false)
    }
  }

  const handleDelete = async () => {
    if (!id) return
    setDeleting(true)
    try {
      await deleteSecurityGroup(id)
      toast.success("安全组删除成功")
      navigate("/control/security-groups")
    } catch (error) {
      toast.error(errorDetail(error, "安全组删除失败"))
    } finally {
      setDeleting(false)
    }
  }

  const defaultRuleValues = (): Partial<RuleFormValues> => ({
    direction: "in",
    ip: "0.0.0.0/0",
    lock: false,
  })

  const openCreateRuleModal = () => {
    setEditingRule(null)
    ruleForm.resetFields()
    ruleForm.setFieldsValue(defaultRuleValues())
    setRuleOpen(true)
  }

  const openEditRuleModal = (rule: SecurityGroupRule) => {
    const protocol = protocolKey(rule.protocol)
    setEditingRule(rule)
    ruleForm.setFieldsValue({
      description: rule.description || "",
      direction: normalizeDirection(rule.direction),
      protocol,
      port: rule.port || protocolMap.get(protocol)?.port || "",
      ip: rule.ip || "0.0.0.0/0",
      lock: String(rule.lock ?? 0) === "1",
    })
    setRuleOpen(true)
  }

  const handleProtocolChange = (value: string) => {
    const port = protocolMap.get(value.toLowerCase())?.port ?? ""
    ruleForm.setFieldValue("port", port)
  }

  const buildRulePayload = async (): Promise<SecurityGroupRulePayload | null> => {
    const values = await ruleForm.validateFields()
    const port = values.port.trim()
    const ip = values.ip.trim()
    if (!port) {
      ruleForm.setFields([{ name: "port", errors: ["请输入端口范围"] }])
      return null
    }
    if (!ip) {
      ruleForm.setFields([{ name: "ip", errors: ["请输入授权 IP"] }])
      return null
    }

    return {
      description: values.description?.trim() || undefined,
      direction: values.direction,
      protocol: values.protocol,
      port,
      ip,
      lock: values.lock ? 1 : 0,
    }
  }

  const handleRuleSave = async () => {
    if (!id) return
    const payload = await buildRulePayload()
    if (!payload) return
    const duplicate = detail?.rule.find((rule) => {
      if (editingRule && String(rule.id) === String(editingRule.id)) return false
      return isSameRule(rule, payload)
    })
    if (duplicate) {
      toast.info("已存在相同方向、协议、端口和授权 IP 的规则")
      return
    }

    setRuleSaving(true)
    try {
      if (editingRule) {
        await updateSecurityGroupRule(editingRule.id, payload)
        toast.success("规则修改成功")
      } else {
        await createSecurityGroupRule(id, payload)
        toast.success("规则添加成功")
      }
      setRuleOpen(false)
      setEditingRule(null)
      ruleForm.resetFields()
      await loadDetail()
    } catch (error) {
      toast.error(errorDetail(error, editingRule ? "规则修改失败" : "规则添加失败"))
    } finally {
      setRuleSaving(false)
    }
  }

  const handleRuleDelete = async (rule: SecurityGroupRule) => {
    setDeletingRuleId(rule.id)
    try {
      await deleteSecurityGroupRule(rule.id)
      toast.success("规则删除成功")
      await loadDetail()
    } catch (error) {
      toast.error(errorDetail(error, "规则删除失败"))
    } finally {
      setDeletingRuleId(null)
    }
  }

  const applyCommonRule = (preset: (typeof COMMON_RULES)[number]) => {
    setCommonOpen(false)
    setEditingRule(null)
    ruleForm.resetFields()
    ruleForm.setFieldsValue({ ...preset, lock: false })
    setRuleOpen(true)
  }

  const commonRuleExists = (preset: (typeof COMMON_RULES)[number]) => (
    detail?.rule.some((rule) => isSameRule(rule, preset)) ?? false
  )

  return (
    <Space orientation="vertical" size={20} style={{ width: "100%" }}>
      <div>
        <Link to="/control/security-groups">
          <Button type="text" icon={<ArrowLeftOutlined />} style={{ paddingInline: 0 }}>
            返回安全组列表
          </Button>
        </Link>
        <Title level={3} style={{ margin: 0 }}>{detail?.name || "安全组管理"}</Title>
        <Paragraph type="secondary" style={{ marginTop: 8, marginBottom: 0 }}>
          管理安全组规则和关联实例。
        </Paragraph>
      </div>

      <Card
        loading={loading}
        variant="outlined"
        title={<Space><SafetyCertificateOutlined /> 安全组详情</Space>}
        extra={detail ? (
          <Space>
            <Button size="small" icon={<EditOutlined />} onClick={openEditModal}>
              修改
            </Button>
            <Popconfirm
              title="删除安全组"
              description="确认删除这个安全组吗？"
              okText="删除"
              cancelText="取消"
              okButtonProps={{ danger: true }}
              onConfirm={handleDelete}
            >
              <Button danger size="small" icon={<DeleteOutlined />} loading={deleting}>
                删除
              </Button>
            </Popconfirm>
          </Space>
        ) : null}
      >
        {!detail ? (
          <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无安全组详情" />
        ) : (
          <Space size={32} wrap>
            <InfoItem label="关联实例" value={`${detail.cloud_num} 台`} />
            <InfoItem label="规则数量" value={`${detail.rule.length} 条`} />
            <InfoItem label="创建时间" value={formatDate(detail.create_time)} />
            <InfoItem label="更新时间" value={formatDate(detail.update_time)} />
          </Space>
        )}
      </Card>

      <Card
        loading={loading}
        variant="outlined"
        title="规则列表"
        extra={(
          <Space>
            <Button icon={<ReloadOutlined />} loading={loading} onClick={() => void loadDetail()}>
              刷新
            </Button>
            <Button icon={<ThunderboltOutlined />} disabled={!detail} onClick={() => setCommonOpen(true)}>
              常用规则
            </Button>
            <Button type="primary" icon={<PlusOutlined />} disabled={!detail} onClick={openCreateRuleModal}>
              添加规则
            </Button>
          </Space>
        )}
      >
        {!detail || detail.rule.length === 0 ? (
          <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无安全组规则" />
        ) : (
          <Space orientation="vertical" size={0} style={{ width: "100%" }}>
            {detail.rule.map((rule, index) => (
              <div
                key={String(rule.id)}
                style={{
                  minHeight: 72,
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "space-between",
                  gap: 16,
                  padding: "12px 0",
                  borderBottom: index === detail.rule.length - 1 ? "none" : "1px solid #f0f0f0",
                }}
              >
                <Space direction="vertical" size={4}>
                  <Space size={12} wrap>
                    <Tag color={normalizeDirection(rule.direction) === "in" ? "blue" : "purple"}>
                      {directionLabel(rule.direction)}
                    </Tag>
                    <Text strong>{protocolLabel(rule.protocol, protocolMap)}</Text>
                    <Text type="secondary">端口 {rule.port || "-"}</Text>
                    <Text type="secondary">授权 IP {rule.ip || "-"}</Text>
                    {String(rule.lock ?? 0) === "1" ? <Tag color="red">已锁定</Tag> : null}
                  </Space>
                  {rule.description ? (
                    <Text type="secondary" style={{ fontSize: 12 }}>备注：{rule.description}</Text>
                  ) : null}
                </Space>
                <Space size={12}>
                  <Text type="secondary">{formatDate(rule.create_time)}</Text>
                  <Button size="small" icon={<EditOutlined />} onClick={() => openEditRuleModal(rule)}>
                    修改
                  </Button>
                  <Popconfirm
                    title="删除规则"
                    description="确认删除这条安全组规则吗？"
                    okText="删除"
                    cancelText="取消"
                    okButtonProps={{ danger: true }}
                    onConfirm={() => handleRuleDelete(rule)}
                  >
                    <Button danger size="small" icon={<DeleteOutlined />} loading={deletingRuleId === rule.id}>
                      删除
                    </Button>
                  </Popconfirm>
                </Space>
              </div>
            ))}
          </Space>
        )}
      </Card>

      <Modal
        title="修改安全组"
        open={editOpen}
        okText="保存"
        cancelText="取消"
        confirmLoading={saving}
        onOk={handleUpdate}
        onCancel={() => setEditOpen(false)}
        destroyOnHidden
      >
        <Form form={groupForm} layout="vertical" style={{ marginTop: 20 }}>
          <Form.Item
            name="name"
            label="安全组名称"
            rules={[
              { required: true, message: "请输入安全组名称" },
              { max: 64, message: "安全组名称不能超过 64 个字符" },
            ]}
          >
            <Input placeholder="请输入安全组名称" allowClear autoFocus />
          </Form.Item>
        </Form>
      </Modal>

      <Modal
        title={editingRule ? "修改规则" : "添加规则"}
        open={ruleOpen}
        okText={editingRule ? "保存" : "添加"}
        cancelText="取消"
        confirmLoading={ruleSaving}
        onOk={handleRuleSave}
        onCancel={() => {
          setRuleOpen(false)
          setEditingRule(null)
        }}
        destroyOnHidden
      >
        <Form<RuleFormValues> form={ruleForm} layout="vertical" style={{ marginTop: 20 }}>
          <Form.Item name="description" label="备注">
            <Input placeholder="请输入规则备注" allowClear />
          </Form.Item>
          <Form.Item name="direction" label="规则方向" rules={[{ required: true, message: "请选择规则方向" }]}>
            <Select
              options={[
                { label: "入站", value: "in" },
                { label: "出站", value: "out" },
              ]}
            />
          </Form.Item>
          <Form.Item name="protocol" label="协议" rules={[{ required: true, message: "请选择协议" }]}>
            <Select
              showSearch
              optionFilterProp="label"
              options={protocolOptions}
              onChange={handleProtocolChange}
              placeholder="请选择协议"
            />
          </Form.Item>
          <Form.Item
            name="port"
            label="端口范围"
            rules={[
              { required: true, message: "请输入端口范围" },
              {
                validator: (_, value: string | undefined) => (
                  isValidPortRange(value)
                    ? Promise.resolve()
                    : Promise.reject(new Error("请输入 22 或 1-65535 这样的端口范围"))
                ),
              },
            ]}
          >
            <Input placeholder="例如 22 或 1-65535" allowClear />
          </Form.Item>
          <Form.Item
            name="ip"
            label="授权 IP"
            rules={[
              { required: true, message: "请输入授权 IP" },
              {
                validator: (_, value: string | undefined) => (
                  isValidIpv4Cidr(value)
                    ? Promise.resolve()
                    : Promise.reject(new Error("请输入 0.0.0.0/0 这样的 IPv4 或 CIDR"))
                ),
              },
            ]}
          >
            <Input placeholder="例如 0.0.0.0/0" allowClear />
          </Form.Item>
          <Form.Item name="lock" label="锁定规则" valuePropName="checked">
            <Switch checkedChildren="锁定" unCheckedChildren="不锁定" />
          </Form.Item>
        </Form>
      </Modal>

      <Modal
        title="常用规则"
        open={commonOpen}
        footer={null}
        onCancel={() => setCommonOpen(false)}
        destroyOnHidden
      >
        <Space orientation="vertical" size={0} style={{ width: "100%", marginTop: 8 }}>
          {COMMON_RULES.map((preset, index) => (
            <div
              key={`${preset.protocol}-${preset.port}-${preset.direction}`}
              style={{
                minHeight: 58,
                display: "flex",
                alignItems: "center",
                justifyContent: "space-between",
                gap: 16,
                padding: "10px 0",
                borderBottom: index === COMMON_RULES.length - 1 ? "none" : "1px solid #f0f0f0",
              }}
            >
              <div>
                <Text strong>{preset.name}</Text>
                <div>
                  <Text type="secondary" style={{ fontSize: 12 }}>
                    {directionLabel(preset.direction)} · {preset.port} · {preset.ip}
                  </Text>
                </div>
              </div>
              <Button
                size="small"
                type="primary"
                disabled={commonRuleExists(preset)}
                onClick={() => applyCommonRule(preset)}
              >
                {commonRuleExists(preset) ? "已存在" : "选择"}
              </Button>
            </div>
          ))}
        </Space>
      </Modal>
    </Space>
  )
}

function InfoItem({ label, value }: { label: string; value: string }) {
  return (
    <Space orientation="vertical" size={2}>
      <Text type="secondary">{label}</Text>
      <Text strong>{value}</Text>
    </Space>
  )
}
