import { useCallback, useEffect, useState } from "react"
import { Link, useParams } from "react-router-dom"
import {
  ArrowLeftOutlined,
  CheckCircleOutlined,
  CloudServerOutlined,
  FileTextOutlined,
  MessageOutlined,
  ReloadOutlined,
  SendOutlined,
  StarOutlined,
} from "@ant-design/icons"
import { Button, Card, Col, Form, Popconfirm, Rate, Row, Select, Space, Spin, Switch, Tag, Timeline, Typography } from "antd"
import { toast } from "../../utils/toast"
import {
  closeAdminTicket,
  getAdminTicket,
  listAdminTicketReplyTemplates,
  listAdminTicketDepartments,
  listAdminTicketStaff,
  reopenAdminTicket,
  replyAdminTicket,
  replyAdminTicketWithTemplate,
  updateAdminTicket,
  uploadAdminTicketImage,
  type AdminTicketDetail as AdminTicketDetailData,
  type TicketReplyTemplate,
} from "../api/tickets"
import type { TicketActor, TicketDepartment, TicketPriority, TicketStatus } from "../../api/tickets"
import RichTextEditor from "../../components/RichTextEditor"
import TicketMessageItem from "../../components/TicketMessageItem"
import { TICKET_PRIORITY_META, TICKET_STATUS_META } from "../../utils/ticketMeta"
import { isRichTextEmpty, sanitizeRichText } from "../../utils/richText"

const { Title, Paragraph, Text } = Typography

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

function formatMemory(memoryMb: number | null | undefined) {
  if (memoryMb == null) return "-"
  if (memoryMb >= 1024) {
    const gb = memoryMb / 1024
    return `${Number.isInteger(gb) ? gb : gb.toFixed(1)} GB`
  }
  return `${memoryMb} MB`
}

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

function ticketEventText(eventType: string, fallback?: string | null) {
  const labels: Record<string, string> = {
    created: "创建工单",
    user_replied: "用户回复",
    admin_replied: "客服回复",
    internal_note_added: "内部备注",
    assigned: "负责人变更",
    status_changed: "状态更新",
    priority_changed: "优先级更新",
    department_changed: "部门调整",
    closed: "关闭工单",
    reopened: "重新打开",
    rated: "满意度评价",
  }
  return fallback || labels[eventType] || eventType
}

function eventDetail(fromValue?: string | null, toValue?: string | null) {
  if (!fromValue && !toValue) return null
  const label = (value: string) =>
    TICKET_STATUS_META[value as TicketStatus]?.label
    || TICKET_PRIORITY_META[value as TicketPriority]?.label
    || value
  if (!fromValue) return `设置为 ${label(String(toValue))}`
  if (!toValue) return `由 ${label(fromValue)} 清空`
  return `${label(fromValue)} → ${label(toValue)}`
}

/** Polling interval — 30s instead of 10s */
const POLL_INTERVAL = 30000

export default function AdminTicketDetail() {
  const { id } = useParams<{ id: string }>()
  const [form] = Form.useForm<{ content: string; is_internal: boolean }>()
  const isInternalReply = Form.useWatch("is_internal", form) ?? false
  const [ticket, setTicket] = useState<AdminTicketDetailData | null>(null)
  const [departments, setDepartments] = useState<TicketDepartment[]>([])
  const [staff, setStaff] = useState<TicketActor[]>([])
  const [templates, setTemplates] = useState<TicketReplyTemplate[]>([])
  const [selectedTemplateId, setSelectedTemplateId] = useState<number | undefined>()
  const [loading, setLoading] = useState(true)
  const [refreshing, setRefreshing] = useState(false)
  const [saving, setSaving] = useState(false)
  const [replying, setReplying] = useState(false)
  const [templatesLoading, setTemplatesLoading] = useState(false)
  const [templateReplying, setTemplateReplying] = useState(false)

  const loadTemplates = useCallback(async (departmentId?: number | null) => {
    setTemplatesLoading(true)
    try {
      const res = await listAdminTicketReplyTemplates({
        department_id: departmentId ?? undefined,
        enabled_only: true,
        include_global: Boolean(departmentId),
      })
      setTemplates(res.data ?? [])
    } catch (error) {
      toast.error(errorDetail(error, "快捷回复模板加载失败"))
    } finally {
      setTemplatesLoading(false)
    }
  }, [])

  const loadTicket = useCallback(async (silent = false) => {
    if (!id) return
    if (silent) setRefreshing(true)
    else setLoading(true)
    try {
      const [ticketRes, departmentsRes, staffRes] = await Promise.all([
        getAdminTicket(id),
        listAdminTicketDepartments(),
        listAdminTicketStaff(),
      ])
      const ticketData = ticketRes.data ?? null
      setTicket(ticketData)
      setDepartments(departmentsRes.data ?? [])
      setStaff(staffRes.data ?? [])
      await loadTemplates(ticketData?.department_id ?? null)
    } catch (error) {
      toast.error(errorDetail(error, "工单详情加载失败"))
    } finally {
      setLoading(false)
      setRefreshing(false)
    }
  }, [id, loadTemplates])

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

  // Poll + visibility-aware
  useEffect(() => {
    let timer: number
    const startPolling = () => {
      timer = window.setInterval(() => {
        void loadTicket(true)
      }, POLL_INTERVAL)
    }
    const handleVisibility = () => {
      window.clearInterval(timer)
      if (document.visibilityState === "visible") {
        void loadTicket(true)
        startPolling()
      }
    }
    startPolling()
    document.addEventListener("visibilitychange", handleVisibility)
    return () => {
      window.clearInterval(timer)
      document.removeEventListener("visibilitychange", handleVisibility)
    }
  }, [loadTicket])

  const handlePatch = async (payload: {
    status?: TicketStatus
    priority?: TicketPriority
    department_id?: number | null
    assignee_id?: number | null
  }) => {
    if (!id) return
    setSaving(true)
    try {
      await updateAdminTicket(id, payload)
      await loadTicket(true)
      toast.success("工单已更新")
    } catch (error) {
      toast.error(errorDetail(error, "工单更新失败"))
    } finally {
      setSaving(false)
    }
  }

  const handleReply = async () => {
    if (!id) return
    const values = await form.validateFields()
    setReplying(true)
    try {
      await replyAdminTicket(id, {
        content: sanitizeRichText(values.content).trim(),
        is_internal: values.is_internal,
      })
      form.resetFields()
      form.setFieldsValue({ is_internal: false })
      toast.success(values.is_internal ? "内部备注已添加" : "回复已发送")
      await loadTicket(true)
    } catch (error) {
      toast.error(errorDetail(error, "回复失败"))
    } finally {
      setReplying(false)
    }
  }

  const selectedTemplate = templates.find((item) => item.id === selectedTemplateId)

  const handleApplyTemplate = () => {
    if (!selectedTemplate) return
    form.setFieldsValue({ content: selectedTemplate.content })
    toast.success("模板已套用")
  }

  const handleTemplateReply = async () => {
    if (!id || !selectedTemplateId) return
    setTemplateReplying(true)
    try {
      await replyAdminTicketWithTemplate(id, {
        template_id: selectedTemplateId,
        is_internal: isInternalReply,
      })
      form.resetFields()
      form.setFieldsValue({ is_internal: false })
      setSelectedTemplateId(undefined)
      toast.success(isInternalReply ? "内部备注已添加" : "模板回复已发送")
      await loadTicket(true)
    } catch (error) {
      toast.error(errorDetail(error, "模板回复失败"))
    } finally {
      setTemplateReplying(false)
    }
  }

  const handleUploadImage = useCallback(async (file: File) => {
    const res = await uploadAdminTicketImage(file)
    if (!res.data) throw new Error("图片上传失败")
    return res.data
  }, [])

  const handleClose = async () => {
    if (!id) return
    setSaving(true)
    try {
      await closeAdminTicket(id)
      toast.success("工单已关闭")
      await loadTicket(true)
    } catch (error) {
      toast.error(errorDetail(error, "关闭失败"))
    } finally {
      setSaving(false)
    }
  }

  const handleReopen = async () => {
    if (!id) return
    setSaving(true)
    try {
      await reopenAdminTicket(id)
      toast.success("工单已重新打开")
      await loadTicket(true)
    } catch (error) {
      toast.error(errorDetail(error, "重新打开失败"))
    } finally {
      setSaving(false)
    }
  }

  if (loading) {
    return (
      <div style={{ height: 420, display: "flex", alignItems: "center", justifyContent: "center" }}>
        <Spin size="large" description="正在加载工单详情" />
      </div>
    )
  }

  if (!ticket) {
    return (
      <Card variant="outlined">
        <Space orientation="vertical" size={12}>
          <Text>工单不存在。</Text>
          <Link to="/admin/tickets"><Button>返回工单管理</Button></Link>
        </Space>
      </Card>
    )
  }

  const statusMeta = TICKET_STATUS_META[ticket.status]

  return (
    <Space orientation="vertical" size={20} style={{ width: "100%" }}>
      <div>
        <Link to="/admin/tickets">
          <Button type="link" icon={<ArrowLeftOutlined />} style={{ paddingLeft: 0 }}>返回工单管理</Button>
        </Link>
        <Space align="center" wrap>
          <Title level={3} style={{ margin: 0 }}>{ticket.subject}</Title>
          <Tag color={statusMeta.color}>{statusMeta.label}</Tag>
          {ticket.unread_count > 0 && <Tag color="red">{ticket.unread_count} 条未读</Tag>}
        </Space>
        <Paragraph type="secondary" style={{ marginTop: 8, marginBottom: 0 }}>
          {ticket.ticket_no} · 用户 {ticket.user?.nickname || ticket.user?.username || `#${ticket.user?.id}`} · 创建于 {formatDate(ticket.created_at)}
        </Paragraph>
      </div>

      <Row gutter={[16, 16]}>
        <Col xs={24} lg={16}>
          <Card
            variant="outlined"
            title={<Space><MessageOutlined /> 沟通记录</Space>}
            extra={<Button icon={<ReloadOutlined />} loading={refreshing} onClick={() => loadTicket(true)}>刷新</Button>}
          >
            <Space orientation="vertical" size={16} style={{ width: "100%" }}>
              {ticket.messages.map((message) => (
                <TicketMessageItem
                  key={message.id}
                  message={message}
                  mode="admin"
                />
              ))}
            </Space>
          </Card>

          <Card variant="outlined" style={{ marginTop: 16 }} title="回复/备注">
            <Space wrap style={{ marginBottom: 12 }}>
              <Select
                allowClear
                showSearch
                loading={templatesLoading}
                placeholder="选择快捷回复模板"
                value={selectedTemplateId}
                onChange={(value) => setSelectedTemplateId(value)}
                style={{ width: 280 }}
                optionFilterProp="label"
                options={templates.map((item) => ({
                  value: item.id,
                  label: `${item.title}${item.department_name ? ` · ${item.department_name}` : " · 全局"}`,
                }))}
              />
              <Button icon={<FileTextOutlined />} disabled={!selectedTemplate} onClick={handleApplyTemplate}>
                套用
              </Button>
              <Button
                type="primary"
                icon={<SendOutlined />}
                disabled={!selectedTemplate}
                loading={templateReplying}
                onClick={handleTemplateReply}
              >
                一键回复
              </Button>
            </Space>
            <Form form={form} layout="vertical" initialValues={{ is_internal: false }} onFinish={handleReply}>
              <Form.Item
                name="content"
                rules={[
                  {
                    validator: async (_, value: string | undefined) => {
                      if (isRichTextEmpty(value)) throw new Error("请输入内容")
                      if (sanitizeRichText(value).length > 8000) throw new Error("内容过长")
                    },
                  },
                ]}
              >
                <RichTextEditor
                  placeholder="给用户回复处理结果，或添加内部备注。"
                  uploadImage={handleUploadImage}
                />
              </Form.Item>
              <Space>
                <Button type="primary" htmlType="submit" icon={<SendOutlined />} loading={replying}>
                  发送
                </Button>
                <Form.Item name="is_internal" valuePropName="checked" noStyle>
                  <Switch checkedChildren="内部备注" unCheckedChildren="公开回复" />
                </Form.Item>
              </Space>
            </Form>
          </Card>
        </Col>

        <Col xs={24} lg={8}>
          <Space orientation="vertical" size={16} style={{ width: "100%" }}>
            <Card variant="outlined" title="处理信息">
              <Space orientation="vertical" size={12} style={{ width: "100%" }}>
                <div>
                  <Text type="secondary">状态</Text>
                  <Select
                    value={ticket.status}
                    loading={saving}
                    onChange={(value) => handlePatch({ status: value })}
                    style={{ width: "100%", marginTop: 6 }}
                    options={Object.entries(TICKET_STATUS_META).map(([value, meta]) => ({ value, label: meta.label }))}
                  />
                </div>
                <div>
                  <Text type="secondary">优先级</Text>
                  <Select
                    value={ticket.priority}
                    loading={saving}
                    onChange={(value) => handlePatch({ priority: value })}
                    style={{ width: "100%", marginTop: 6 }}
                    options={Object.entries(TICKET_PRIORITY_META).map(([value, meta]) => ({ value, label: meta.label }))}
                  />
                </div>
                <div>
                  <Text type="secondary">部门</Text>
                  <Select
                    allowClear
                    value={ticket.department_id ?? undefined}
                    loading={saving}
                    onChange={(value) => handlePatch({ department_id: value ?? null })}
                    style={{ width: "100%", marginTop: 6 }}
                    options={departments.map((item) => ({ value: item.id, label: item.name }))}
                  />
                </div>
                <div>
                  <Text type="secondary">负责人</Text>
                  <Select
                    allowClear
                    value={ticket.assignee?.id ?? undefined}
                    loading={saving}
                    placeholder="未分派"
                    onChange={(value) => handlePatch({ assignee_id: value ?? null })}
                    style={{ width: "100%", marginTop: 6 }}
                    options={staff.map((item) => ({ value: item.id, label: item.nickname || item.username }))}
                  />
                </div>
                {!["closed", "resolved"].includes(ticket.status) ? (
                  <Popconfirm
                    title="关闭工单"
                    description="确认关闭该工单吗？"
                    okText="关闭"
                    cancelText="取消"
                    onConfirm={handleClose}
                  >
                    <Button icon={<CheckCircleOutlined />} loading={saving}>关闭工单</Button>
                  </Popconfirm>
                ) : (
                  <Button icon={<MessageOutlined />} loading={saving} onClick={handleReopen}>重新打开</Button>
                )}
              </Space>
            </Card>

            <Card variant="outlined" title="用户信息">
              {ticket.user ? (
                <Space orientation="vertical" size={6}>
                  <Text strong>{ticket.user.nickname || ticket.user.username}</Text>
                  <Text type="secondary">用户 ID：#{ticket.user.id}</Text>
                  <Text type="secondary">邮箱：{ticket.user.email || "-"}</Text>
                  <Text type="secondary">手机：{ticket.user.phone || "-"}</Text>
                </Space>
              ) : (
                <Text type="secondary">用户不存在或已删除。</Text>
              )}
            </Card>

            <Card variant="outlined" title={<Space><StarOutlined /> 服务评价</Space>}>
              {ticket.satisfaction ? (
                <Space orientation="vertical" size={8}>
                  <Rate disabled value={ticket.satisfaction.rating} />
                  <Text type="secondary">评价时间：{formatDate(ticket.satisfaction.rated_at)}</Text>
                  {ticket.satisfaction.comment ? (
                    <Text>{ticket.satisfaction.comment}</Text>
                  ) : (
                    <Text type="secondary">用户未填写文字反馈。</Text>
                  )}
                </Space>
              ) : (
                <Text type="secondary">用户尚未评价。</Text>
              )}
            </Card>

            <Card variant="outlined" title={<Space><CloudServerOutlined /> 关联实例</Space>}>
              {ticket.instance ? (
                <Space orientation="vertical" size={8}>
                  <Text strong>#{ticket.instance.id} {ticket.instance.hostname || "云服务器"}</Text>
                  <Text type="secondary">{ticket.instance.main_ip || "NAT 网络"}</Text>
                  <Space size={[4, 4]} wrap>
                    <Tag>CPU {ticket.instance.cpu ?? "-"} 核</Tag>
                    <Tag>内存 {formatMemory(ticket.instance.memory)}</Tag>
                    <Tag>带宽 {ticket.instance.in_bw ?? "-"} / {ticket.instance.out_bw ?? "-"} Mbps</Tag>
                  </Space>
                </Space>
              ) : (
                <Text type="secondary">未关联实例。</Text>
              )}
            </Card>

            <Card variant="outlined" title="处理记录">
              {ticket.events?.length ? (
                <Timeline
                  items={ticket.events.map((event) => ({
                    key: event.id,
                    color: event.event_type === "internal_note_added" ? "purple" : undefined,
                    children: (
                      <Space orientation="vertical" size={2}>
                        <Space size={6} wrap>
                          <Text>{ticketEventText(event.event_type, event.message)}</Text>
                          {event.event_type === "internal_note_added" && <Tag color="purple">内部</Tag>}
                        </Space>
                        {eventDetail(event.from_value, event.to_value) ? (
                          <Text type="secondary" style={{ fontSize: 12 }}>
                            {eventDetail(event.from_value, event.to_value)}
                          </Text>
                        ) : null}
                        <Text type="secondary" style={{ fontSize: 12 }}>
                          {event.actor_name || event.actor_type} · {formatDate(event.created_at)}
                        </Text>
                      </Space>
                    ),
                  }))}
                />
              ) : (
                <Text type="secondary">暂无处理记录。</Text>
              )}
            </Card>
          </Space>
        </Col>
      </Row>
    </Space>
  )
}
