import { useEffect, useState } from 'react';
import {
  Button,
  Card,
  Checkbox,
  Drawer,
  Form,
  Image,
  Input,
  Modal,
  Radio,
  Select,
  Space,
  Table,
  Tag,
  Timeline,
  Typography,
  message,
} from 'antd';
import {
  CheckCircleFilled,
  CloseCircleFilled,
  ClockCircleFilled,
  MinusCircleOutlined,
  PlusOutlined,
  SyncOutlined,
} from '@ant-design/icons';
import type { ColumnsType } from 'antd/es/table';
import {
  DEV_PLAN_TASK_TYPE_LABELS,
  SUPPORT_TICKET_STATUS_LABELS,
  SUPPORT_TICKET_TYPE_LABELS,
  SUPPORT_TICKET_PRIORITY_LABELS,
  mapSupportTicketTypeToDevPlanTask,
  type BatchReviewPreviewItem,
  type BatchReviewPreviewResponse,
  type DevPlanTaskTypeDto,
  type DevPlanVersionDto,
  type SupportTicketDto,
  type SupportTicketLinkedTaskDto,
  type SupportTicketPriorityDto,
  type SupportTicketStatusDto,
  type SupportTicketTypeDto,
} from '@dukang/shared-types';
import { request, type HqProfile } from '../lib/api';
import { fmtTime } from '../lib/constants';
import { useAdminList } from '../lib/useAdminList';
import OssUpload from '../components/OssUpload';

const DISPATCH_WECOM_STORAGE_KEY = 'support_ticket_dispatch_wecom';
const DEFAULT_DISPATCH_SUPPLEMENT = '请按以下任务进入开发流程';

const STATUS_COLOR: Record<SupportTicketStatusDto, string> = {
  PENDING_REVIEW: 'orange',
  REJECTED: 'red',
  DEVELOPING: 'blue',
  TESTING: 'purple',
  PASSED: 'green',
  PUBLISHED: 'cyan',
};

const TYPE_OPTIONS = (Object.keys(SUPPORT_TICKET_TYPE_LABELS) as SupportTicketTypeDto[]).map(
  (value) => ({ value, label: SUPPORT_TICKET_TYPE_LABELS[value] }),
);

const STATUS_OPTIONS = (Object.keys(SUPPORT_TICKET_STATUS_LABELS) as SupportTicketStatusDto[]).map(
  (value) => ({ value, label: SUPPORT_TICKET_STATUS_LABELS[value] }),
);

const PRIORITY_COLOR: Record<SupportTicketPriorityDto, string> = {
  LOW: 'default',
  NORMAL: 'blue',
  HIGH: 'orange',
  URGENT: 'red',
};

const PRIORITY_OPTIONS = (Object.keys(SUPPORT_TICKET_PRIORITY_LABELS) as SupportTicketPriorityDto[]).map(
  (value) => ({ value, label: SUPPORT_TICKET_PRIORITY_LABELS[value] }),
);

const TASK_TYPE_OPTIONS = (Object.keys(DEV_PLAN_TASK_TYPE_LABELS) as DevPlanTaskTypeDto[]).map(
  (v) => ({ value: v, label: DEV_PLAN_TASK_TYPE_LABELS[v] }),
);

type TicketRow = SupportTicketDto & { linkedTasks?: SupportTicketLinkedTaskDto[] };

export default function SupportTicketsPage() {
  const [profile, setProfile] = useState<HqProfile | null>(null);
  const [filters, setFilters] = useState<Record<string, string>>({});
  const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
  const { data, loading, page, pageSize, setPage, setPageSize, reload } = useAdminList<TicketRow>(
    '/admin/support-tickets',
    () => {
      const qs = new URLSearchParams();
      if (filters.ticketType) qs.set('ticketType', filters.ticketType);
      if (filters.status) qs.set('status', filters.status);
      if (filters.priority) qs.set('priority', filters.priority);
      return qs;
    },
    [filters],
  );

  const [detail, setDetail] = useState<TicketRow | null>(null);
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [createOpen, setCreateOpen] = useState(false);
  const [creating, setCreating] = useState(false);
  const [acting, setActing] = useState(false);
  const [reviewOpen, setReviewOpen] = useState(false);
  const [createTasksOpen, setCreateTasksOpen] = useState(false);
  const [batchPreviewOpen, setBatchPreviewOpen] = useState(false);
  const [batchPreview, setBatchPreview] = useState<BatchReviewPreviewItem[]>([]);
  const [batchConfirming, setBatchConfirming] = useState(false);
  const [batchStatusOpen, setBatchStatusOpen] = useState(false);
  const [batchStatusSaving, setBatchStatusSaving] = useState(false);
  const [batchCreateSaving, setBatchCreateSaving] = useState(false);
  const [batchPublishOpen, setBatchPublishOpen] = useState(false);
  const [batchPublishSaving, setBatchPublishSaving] = useState(false);
  const [versions, setVersions] = useState<DevPlanVersionDto[]>([]);
  const [editOpen, setEditOpen] = useState(false);
  const [editSaving, setEditSaving] = useState(false);
  const [reviewDecision, setReviewDecision] = useState<'APPROVE' | 'REJECT'>('APPROVE');

  const [createForm] = Form.useForm();
  const [editForm] = Form.useForm();
  const [reviewForm] = Form.useForm<{ decision: 'APPROVE' | 'REJECT'; rejectReason?: string; note?: string }>();
  const [tasksForm] = Form.useForm<{
    tasks: Array<{ content: string; type: DevPlanTaskTypeDto }>;
    dispatchToWecom?: boolean;
    dispatchSupplement?: string;
  }>();
  const [batchForm] = Form.useForm<{ items: BatchReviewPreviewItem[] }>();
  const [batchStatusForm] = Form.useForm<{
    status: SupportTicketStatusDto;
    rejectReason?: string;
    note?: string;
  }>();
  const [batchPublishForm] = Form.useForm<{
    versionId: string;
    dispatchToWecom?: boolean;
    dispatchSupplement?: string;
  }>();

  const isSuperAdmin = profile?.adminRole === 'SUPER_ADMIN';

  useEffect(() => {
    if (!batchPublishOpen) return;
    request<{ items: DevPlanVersionDto[] }>('/admin/dev-plan/versions?pageSize=100')
      .then((res) => setVersions(res.items ?? []))
      .catch(() => setVersions([]));
  }, [batchPublishOpen]);

  useEffect(() => {
    request<HqProfile>('/admin/auth/me').then(setProfile).catch(() => {});
  }, []);

  async function openDetail(id: string) {
    setDetail(await request<TicketRow>(`/admin/support-tickets/${id}`));
    setDrawerOpen(true);
  }

  async function submitCreate() {
    const values = await createForm.validateFields();
    setCreating(true);
    try {
      await request('/admin/support-tickets', {
        method: 'POST',
        body: JSON.stringify({
          ticketType: values.ticketType,
          title: values.title.trim(),
          content: values.content?.trim() || undefined,
          remark: values.remark?.trim() || undefined,
          priority: values.priority,
          attachmentUrls: (values.attachmentUrls ?? []).map((u: string) => u?.trim()).filter(Boolean),
        }),
      });
      message.success('技术支持工单已创建，等待最高管理员评审');
      setCreateOpen(false);
      createForm.resetFields();
      reload();
    } catch (e) {
      message.error(e instanceof Error ? e.message : '创建失败');
    } finally {
      setCreating(false);
    }
  }

  function openReview() {
    if (!detail) return;
    reviewForm.setFieldsValue({ decision: 'APPROVE', note: '', rejectReason: '' });
    setReviewDecision('APPROVE');
    setReviewOpen(true);
  }

  async function submitReviewStep1() {
    const values = await reviewForm.validateFields();
    if (values.decision === 'REJECT') {
      if (!values.rejectReason?.trim()) {
        message.error('请填写驳回理由');
        return;
      }
      setActing(true);
      try {
        await request(`/admin/support-tickets/${detail!.id}/review`, {
          method: 'POST',
          body: JSON.stringify({ decision: 'REJECT', rejectReason: values.rejectReason.trim() }),
        });
        message.success('已驳回');
        setReviewOpen(false);
        setDrawerOpen(false);
        reload();
      } catch (e) {
        message.error(e instanceof Error ? e.message : '操作失败');
      } finally {
        setActing(false);
      }
      return;
    }

    setReviewOpen(false);
    const summary = [detail!.title, detail!.content].filter(Boolean).join('\n').slice(0, 500);
    tasksForm.setFieldsValue({
      tasks: [{ content: summary || detail!.title, type: mapSupportTicketTypeToDevPlanTask(detail!.ticketType) }],
      dispatchToWecom: localStorage.getItem(DISPATCH_WECOM_STORAGE_KEY) !== 'false',
      dispatchSupplement: DEFAULT_DISPATCH_SUPPLEMENT,
    });
    setCreateTasksOpen(true);
  }

  function openEdit() {
    if (!detail) return;
    editForm.setFieldsValue({
      ticketType: detail.ticketType,
      title: detail.title,
      content: detail.content || '',
      remark: detail.remark || '',
      priority: detail.priority ?? 'NORMAL',
      attachmentUrls: detail.attachmentUrls?.length ? detail.attachmentUrls : [''],
    });
    setEditOpen(true);
  }

  async function submitEdit() {
    const values = await editForm.validateFields();
    setEditSaving(true);
    try {
      await request(`/admin/support-tickets/${detail!.id}`, {
        method: 'PATCH',
        body: JSON.stringify({
          ticketType: values.ticketType,
          title: values.title.trim(),
          content: values.content?.trim() || undefined,
          remark: values.remark?.trim() || undefined,
          priority: values.priority,
          attachmentUrls: (values.attachmentUrls ?? []).map((u: string) => u?.trim()).filter(Boolean),
        }),
      });
      message.success('已保存');
      setEditOpen(false);
      await openDetail(String(detail!.id));
      reload();
    } catch (e) {
      message.error(e instanceof Error ? e.message : '保存失败');
    } finally {
      setEditSaving(false);
    }
  }

  async function submitBatchStatus() {
    const values = await batchStatusForm.validateFields();
    setBatchStatusSaving(true);
    try {
      const res = await request<{ successCount: number; failCount: number }>(
        '/admin/support-tickets/batch-update-status',
        {
          method: 'POST',
          body: JSON.stringify({
            ticketIds: selectedRowKeys,
            status: values.status,
            rejectReason: values.rejectReason?.trim() || undefined,
            note: values.note?.trim() || undefined,
          }),
        },
      );
      message.success(`成功 ${res.successCount} 条，失败 ${res.failCount} 条`);
      setBatchStatusOpen(false);
      setSelectedRowKeys([]);
      reload();
    } catch (e) {
      message.error(e instanceof Error ? e.message : '批量更新失败');
    } finally {
      setBatchStatusSaving(false);
    }
  }

  async function submitBatchCreateTasks() {
    if (!selectedRowKeys.length) return;
    setBatchCreateSaving(true);
    try {
      const res = await request<{ successCount: number; failCount: number }>(
        '/admin/support-tickets/batch-create-tasks',
        {
          method: 'POST',
          body: JSON.stringify({ ticketIds: selectedRowKeys }),
        },
      );
      message.success(`已创建 ${res.successCount} 条任务，跳过/失败 ${res.failCount} 条`);
      setSelectedRowKeys([]);
      reload();
    } catch (e) {
      message.error(e instanceof Error ? e.message : '批量创建任务失败');
    } finally {
      setBatchCreateSaving(false);
    }
  }

  function openBatchPublish() {
    batchPublishForm.setFieldsValue({
      versionId: undefined,
      dispatchToWecom: localStorage.getItem(DISPATCH_WECOM_STORAGE_KEY) !== 'false',
      dispatchSupplement: DEFAULT_DISPATCH_SUPPLEMENT,
    });
    setBatchPublishOpen(true);
  }

  async function submitBatchPublish() {
    const values = await batchPublishForm.validateFields();
    localStorage.setItem(DISPATCH_WECOM_STORAGE_KEY, values.dispatchToWecom ? 'true' : 'false');
    setBatchPublishSaving(true);
    try {
      const res = await request<{
        successCount: number;
        failCount: number;
        linkedTaskCount: number;
      }>('/admin/support-tickets/batch-publish', {
        method: 'POST',
        body: JSON.stringify({
          ticketIds: selectedRowKeys,
          versionId: values.versionId,
          dispatchToWecom: !!values.dispatchToWecom,
          dispatchSupplement: values.dispatchSupplement?.trim() || undefined,
        }),
      });
      message.success(
        `已关联 ${res.linkedTaskCount} 条任务到版本，工单成功 ${res.successCount} 条，失败 ${res.failCount} 条`,
      );
      setBatchPublishOpen(false);
      setSelectedRowKeys([]);
      reload();
    } catch (e) {
      message.error(e instanceof Error ? e.message : '批量发布失败');
    } finally {
      setBatchPublishSaving(false);
    }
  }

  async function submitCreateTasks() {
    const values = await tasksForm.validateFields();
    const note = reviewForm.getFieldValue('note') as string | undefined;
    localStorage.setItem(DISPATCH_WECOM_STORAGE_KEY, values.dispatchToWecom ? 'true' : 'false');
    setActing(true);
    try {
      await request(`/admin/support-tickets/${detail!.id}/review`, {
        method: 'POST',
        body: JSON.stringify({
          decision: 'APPROVE',
          note: note?.trim() || undefined,
          tasks: values.tasks.map((t) => ({ content: t.content.trim(), type: t.type })),
          dispatchToWecom: !!values.dispatchToWecom,
          dispatchSupplement: values.dispatchSupplement?.trim() || undefined,
        }),
      });
      message.success(values.dispatchToWecom ? '审批通过，已创建任务并派发企微' : '审批通过，已创建开发任务');
      setCreateTasksOpen(false);
      setDrawerOpen(false);
      reload();
    } catch (e) {
      message.error(e instanceof Error ? e.message : '操作失败');
    } finally {
      setActing(false);
    }
  }

  async function startBatchPreview() {
    if (!selectedRowKeys.length) return;
    setActing(true);
    try {
      const res = await request<BatchReviewPreviewResponse>('/admin/support-tickets/batch-review/preview', {
        method: 'POST',
        body: JSON.stringify({ ticketIds: selectedRowKeys }),
      });
      setBatchPreview(res.items);
      batchForm.setFieldsValue({ items: res.items });
      setBatchPreviewOpen(true);
    } catch (e) {
      message.error(e instanceof Error ? e.message : 'AI 预审失败');
    } finally {
      setActing(false);
    }
  }

  async function submitBatchConfirm() {
    const values = await batchForm.validateFields();
    setBatchConfirming(true);
    try {
      await request('/admin/support-tickets/batch-review/confirm', {
        method: 'POST',
        body: JSON.stringify({
          items: values.items.map((item) => ({
            ticketId: item.ticketId,
            decision: item.decision,
            rejectReason: item.rejectReason,
            note: item.note,
            tasks: item.decision === 'APPROVE' ? item.suggestedTasks : undefined,
          })),
        }),
      });
      message.success('批量审批已完成');
      setBatchPreviewOpen(false);
      setSelectedRowKeys([]);
      reload();
    } catch (e) {
      message.error(e instanceof Error ? e.message : '批量确认失败');
    } finally {
      setBatchConfirming(false);
    }
  }

  async function startTesting() {
    if (!detail) return;
    setActing(true);
    try {
      await request(`/admin/support-tickets/${detail.id}/start-testing`, {
        method: 'POST',
        body: JSON.stringify({}),
      });
      message.success('已转入测试');
      setDrawerOpen(false);
      reload();
    } catch (e) {
      message.error(e instanceof Error ? e.message : '操作失败');
    } finally {
      setActing(false);
    }
  }

  async function pass() {
    if (!detail) return;
    setActing(true);
    try {
      await request(`/admin/support-tickets/${detail.id}/pass`, {
        method: 'POST',
        body: JSON.stringify({}),
      });
      message.success('测试通过');
      setDrawerOpen(false);
      reload();
    } catch (e) {
      message.error(e instanceof Error ? e.message : '操作失败');
    } finally {
      setActing(false);
    }
  }

  const columns: ColumnsType<TicketRow> = [
    { title: '工单号', dataIndex: 'ticketNo', width: 180 },
    {
      title: '类型',
      dataIndex: 'ticketType',
      width: 90,
      render: (t: SupportTicketTypeDto) => SUPPORT_TICKET_TYPE_LABELS[t] ?? t,
    },
    {
      title: '优先级',
      dataIndex: 'priority',
      width: 90,
      render: (p: SupportTicketPriorityDto) => (
        <Tag color={PRIORITY_COLOR[p] ?? 'default'}>
          {SUPPORT_TICKET_PRIORITY_LABELS[p] ?? p ?? '普通'}
        </Tag>
      ),
    },
    {
      title: '状态',
      dataIndex: 'status',
      width: 100,
      render: (s: SupportTicketStatusDto, row) => (
        <Space size={4} direction="vertical" style={{ lineHeight: 1.2 }}>
          <Tag color={STATUS_COLOR[s]}>{SUPPORT_TICKET_STATUS_LABELS[s] ?? s}</Tag>
          {row.releasedVersionNo ? (
            <Typography.Text type="secondary" style={{ fontSize: 11 }}>
              {row.releasedVersionNo}
            </Typography.Text>
          ) : null}
        </Space>
      ),
    },
    { title: '标题', dataIndex: 'title', ellipsis: true },
    { title: '创建人', dataIndex: 'creatorName', width: 100 },
    { title: '时间', dataIndex: 'createdAt', width: 160, render: fmtTime },
    {
      title: '操作',
      width: 80,
      render: (_, row) => (
        <Button type="link" size="small" onClick={() => void openDetail(String(row.id))}>
          详情
        </Button>
      ),
    },
  ];

  const drawerExtra = (() => {
    if (!detail) return null;
    if (detail.status === 'PENDING_REVIEW' && isSuperAdmin) {
      return (
        <Space>
          <Button onClick={openEdit}>编辑</Button>
          <Button type="primary" loading={acting} onClick={openReview}>
            审批
          </Button>
        </Space>
      );
    }
    if (detail.status === 'DEVELOPING') {
      return (
        <Button type="primary" loading={acting} onClick={() => void startTesting()}>
          开发完成 · 转入测试
        </Button>
      );
    }
    if (detail.status === 'TESTING') {
      return (
        <Button type="primary" loading={acting} onClick={() => void pass()}>
          测试通过
        </Button>
      );
    }
    return null;
  })();

  return (
    <div>
      <div
        style={{
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
          marginBottom: 16,
        }}
      >
        <Typography.Title level={4} style={{ margin: 0 }}>
          技术支持
        </Typography.Title>
        <Space>
          {isSuperAdmin ? (
            <>
              <Button
                disabled={!selectedRowKeys.length}
                loading={batchCreateSaving}
                onClick={() => void submitBatchCreateTasks()}
              >
                一键创建任务
              </Button>
              <Button disabled={!selectedRowKeys.length} onClick={openBatchPublish}>
                一键发布
              </Button>
              <Button disabled={!selectedRowKeys.length} loading={acting} onClick={() => void startBatchPreview()}>
                批量审核
              </Button>
              <Button
                disabled={!selectedRowKeys.length}
                onClick={() => {
                  batchStatusForm.setFieldsValue({ status: 'TESTING', rejectReason: '', note: '' });
                  setBatchStatusOpen(true);
                }}
              >
                批量改状态
              </Button>
            </>
          ) : null}
          <Button type="primary" onClick={() => setCreateOpen(true)}>
            创建工单
          </Button>
        </Space>
      </div>

      <Form
        layout="inline"
        style={{ marginBottom: 16 }}
        onFinish={(v) => {
          setFilters(v);
          setPage(1);
        }}
      >
        <Form.Item name="ticketType" label="类型">
          <Select allowClear style={{ width: 120 }} options={TYPE_OPTIONS} />
        </Form.Item>
        <Form.Item name="status" label="状态">
          <Select allowClear style={{ width: 120 }} options={STATUS_OPTIONS} />
        </Form.Item>
        <Form.Item name="priority" label="优先级">
          <Select allowClear style={{ width: 120 }} options={PRIORITY_OPTIONS} />
        </Form.Item>
        <Button type="primary" htmlType="submit">
          筛选
        </Button>
      </Form>

      <Table
        rowKey="id"
        loading={loading}
        columns={columns}
        dataSource={data?.items ?? []}
        scroll={{ x: 900 }}
        rowSelection={
          isSuperAdmin
            ? {
                selectedRowKeys,
                onChange: (keys) => setSelectedRowKeys(keys as string[]),
              }
            : undefined
        }
        pagination={{
          current: page,
          pageSize,
          total: data?.total ?? 0,
          showSizeChanger: true,
          onChange: (p, ps) => {
            setPage(p);
            setPageSize(ps);
          },
        }}
      />

      <Drawer
        title={
          <Space>
            <span>技术支持详情</span>
            {detail && (
              <>
                <Typography.Text type="secondary" style={{ fontSize: 13 }}>
                  {detail.ticketNo}
                </Typography.Text>
                <Tag>{SUPPORT_TICKET_TYPE_LABELS[detail.ticketType] ?? detail.ticketType}</Tag>
                <Tag color={PRIORITY_COLOR[detail.priority ?? 'NORMAL']}>
                  {SUPPORT_TICKET_PRIORITY_LABELS[detail.priority ?? 'NORMAL']}
                </Tag>
              </>
            )}
          </Space>
        }
        width={680}
        open={drawerOpen}
        onClose={() => setDrawerOpen(false)}
        extra={drawerExtra}
      >
        {detail && (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
            {/* 状态 + 标签 */}
            <Card
              size="small"
              styles={{ body: { padding: 16 } }}
            >
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                <Space size={12}>
                  <Tag
                    color={STATUS_COLOR[detail.status]}
                    style={{ fontSize: 14, padding: '2px 12px', lineHeight: '26px', borderRadius: 6 }}
                  >
                    {SUPPORT_TICKET_STATUS_LABELS[detail.status] ?? detail.status}
                  </Tag>
                  {detail.status === 'REJECTED' && (
                    <Typography.Text type="danger">此工单已被驳回</Typography.Text>
                  )}
                  {detail.status === 'PASSED' && (
                    <Typography.Text type="success">此工单已测试通过</Typography.Text>
                  )}
                  {detail.status === 'PUBLISHED' && (
                    <Typography.Text type="success">
                      已发布{detail.releasedVersionNo ? ` · ${detail.releasedVersionNo}` : ''}
                    </Typography.Text>
                  )}
                </Space>
                <Typography.Text type="secondary" style={{ fontSize: 12 }}>
                  创建于 {fmtTime(detail.createdAt)}
                </Typography.Text>
              </div>
            </Card>

            {/* 状态流转时间线 */}
            <Card
              size="small"
              title={<Typography.Text strong style={{ fontSize: 14 }}>状态流转</Typography.Text>}
              styles={{ body: { padding: '12px 16px' } }}
            >
              <Timeline
                items={(() => {
                  const isRejected = detail.status === 'REJECTED';
                  const flowSteps: Array<{ key: SupportTicketStatusDto; time?: string | null; label: string }> = [
                    { key: 'PENDING_REVIEW', label: '待评审', time: detail.createdAt },
                    ...(!isRejected
                      ? [
                          { key: 'DEVELOPING' as SupportTicketStatusDto, label: '开发中', time: detail.reviewedAt },
                          { key: 'TESTING' as SupportTicketStatusDto, label: '测试中', time: null },
                          { key: 'PASSED' as SupportTicketStatusDto, label: '已通过', time: detail.completedAt },
                          { key: 'PUBLISHED' as SupportTicketStatusDto, label: '已发布', time: detail.publishedAt },
                        ]
                      : [{ key: 'REJECTED' as SupportTicketStatusDto, label: '已驳回', time: detail.reviewedAt }]),
                  ];

                  const statusIdx = flowSteps.findIndex((s) => s.key === detail.status);

                  return flowSteps.map((step, idx) => {
                    const isCurrent = step.key === detail.status;
                    const isPast = !isRejected
                      ? idx < statusIdx
                      : step.key === 'PENDING_REVIEW' && statusIdx >= 1;
                    const isRejectedStep = step.key === 'REJECTED';

                    let dot: React.ReactNode;
                    let color: string | undefined;
                    if (isRejectedStep) {
                      dot = <CloseCircleFilled style={{ color: '#ff4d4f', fontSize: 14 }} />;
                      color = 'red';
                    } else if (isCurrent) {
                      if (step.key === 'TESTING') {
                        dot = <SyncOutlined style={{ color: '#722ed1', fontSize: 14 }} />;
                      } else {
                        dot = <ClockCircleFilled style={{ color: STATUS_COLOR[step.key], fontSize: 14 }} />;
                      }
                    } else if (isPast) {
                      dot = <CheckCircleFilled style={{ color: '#52c41a', fontSize: 14 }} />;
                      color = 'green';
                    }

                    return {
                      dot,
                      color,
                      children: (
                        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                          <span
                            style={{
                              fontWeight: isCurrent ? 600 : 400,
                              color: isPast || isCurrent ? undefined : '#bbb',
                            }}
                          >
                            {step.label}
                          </span>
                          {step.time && (
                            <Typography.Text type="secondary" style={{ fontSize: 12 }}>
                              {fmtTime(step.time)}
                            </Typography.Text>
                          )}
                        </div>
                      ),
                    };
                  });
                })()}
              />
            </Card>

            {/* 标题 & 内容 */}
            <Card
              size="small"
              styles={{ body: { padding: 16 } }}
            >
              <Typography.Title level={5} style={{ marginTop: 0, marginBottom: 12 }}>
                {detail.title}
              </Typography.Title>
              <div
                style={{
                  background: '#fafafa',
                  border: '1px solid #f0f0f0',
                  borderRadius: 8,
                  padding: '12px 16px',
                  whiteSpace: 'pre-wrap',
                  fontSize: 14,
                  lineHeight: 1.8,
                  color: '#333',
                  minHeight: detail.content ? undefined : 40,
                }}
              >
                {detail.content || (
                  <Typography.Text type="secondary">暂无详细说明</Typography.Text>
                )}
              </div>
            </Card>

            {/* 基本信息 */}
            <Card
              size="small"
              title={<Typography.Text strong style={{ fontSize: 14 }}>基本信息</Typography.Text>}
              styles={{ body: { padding: '12px 16px' } }}
            >
              <div
                style={{
                  display: 'grid',
                  gridTemplateColumns: '1fr 1fr',
                  gap: '12px 24px',
                  fontSize: 13,
                }}
              >
                <div>
                  <Typography.Text type="secondary">创建人</Typography.Text>
                  <div style={{ marginTop: 2 }}>{detail.creatorName}</div>
                </div>
                <div>
                  <Typography.Text type="secondary">创建时间</Typography.Text>
                  <div style={{ marginTop: 2 }}>{fmtTime(detail.createdAt)}</div>
                </div>
                <div>
                  <Typography.Text type="secondary">评审人</Typography.Text>
                  <div style={{ marginTop: 2 }}>{detail.reviewerName || '—'}</div>
                </div>
                <div>
                  <Typography.Text type="secondary">评审时间</Typography.Text>
                  <div style={{ marginTop: 2 }}>{detail.reviewedAt ? fmtTime(detail.reviewedAt) : '—'}</div>
                </div>
              </div>
              {detail.rejectReason && (
                <div style={{ marginTop: 16 }}>
                  <Typography.Text type="danger" strong style={{ fontSize: 13 }}>
                    驳回理由
                  </Typography.Text>
                  <div
                    style={{
                      marginTop: 6,
                      background: '#fff2f0',
                      border: '1px solid #ffccc7',
                      borderRadius: 6,
                      padding: '10px 14px',
                      fontSize: 13,
                      color: '#a8071a',
                      lineHeight: 1.7,
                    }}
                  >
                    {detail.rejectReason}
                  </div>
                </div>
              )}
              {detail.remark && (
                <div style={{ marginTop: 16 }}>
                  <Typography.Text type="secondary" style={{ fontSize: 13 }}>
                    备注
                  </Typography.Text>
                  <div style={{ marginTop: 4, color: '#555', fontSize: 13, lineHeight: 1.6 }}>
                    {detail.remark}
                  </div>
                </div>
              )}
              {detail.attachmentUrls?.length ? (
                <div style={{ marginTop: 16 }}>
                  <Typography.Text type="secondary" style={{ fontSize: 13 }}>
                    附件
                  </Typography.Text>
                  <Space wrap style={{ marginTop: 8 }}>
                    {detail.attachmentUrls.map((url) => (
                      <Image key={url} src={url} width={80} height={80} style={{ objectFit: 'cover', borderRadius: 4 }} />
                    ))}
                  </Space>
                </div>
              ) : null}
            </Card>

            {/* 关联开发任务 */}
            {detail.linkedTasks?.length ? (
              <Card
                size="small"
                title={
                  <Typography.Text strong style={{ fontSize: 14 }}>
                    关联开发任务
                    <Typography.Text type="secondary" style={{ marginLeft: 8, fontWeight: 400 }}>
                      {detail.linkedTasks.length}
                    </Typography.Text>
                  </Typography.Text>
                }
                styles={{ body: { padding: 0 } }}
              >
                {detail.linkedTasks.map((t, idx) => (
                  <div
                    key={t.id}
                    style={{
                      display: 'flex',
                      alignItems: 'center',
                      padding: '10px 16px',
                      borderBottom: idx < detail.linkedTasks!.length - 1 ? '1px solid #f0f0f0' : 'none',
                      gap: 12,
                    }}
                  >
                    <Typography.Text
                      code
                      style={{ fontSize: 12, flexShrink: 0 }}
                    >
                      {t.taskNo}
                    </Typography.Text>
                    <Typography.Text
                      style={{ flex: 1, fontSize: 13 }}
                      ellipsis={{ tooltip: t.content }}
                    >
                      {t.content}
                    </Typography.Text>
                    <Tag style={{ margin: 0, flexShrink: 0 }}>{t.status}</Tag>
                  </div>
                ))}
              </Card>
            ) : null}
          </div>
        )}
      </Drawer>

      <Modal title="创建技术支持工单" open={createOpen} onCancel={() => setCreateOpen(false)} onOk={() => void submitCreate()} confirmLoading={creating} destroyOnClose okText="提交">
        <Form form={createForm} layout="vertical" initialValues={{ ticketType: 'BUG', priority: 'NORMAL', attachmentUrls: [''] }}>
          <Form.Item name="ticketType" label="类型" rules={[{ required: true }]}>
            <Select options={TYPE_OPTIONS} />
          </Form.Item>
          <Form.Item name="priority" label="优先级" rules={[{ required: true }]}>
            <Select options={PRIORITY_OPTIONS} />
          </Form.Item>
          <Form.Item name="title" label="标题" rules={[{ required: true }]}>
            <Input maxLength={128} showCount />
          </Form.Item>
          <Form.Item name="content" label="详细说明">
            <Input.TextArea rows={5} maxLength={4000} showCount />
          </Form.Item>
          <Form.Item name="remark" label="备注">
            <Input.TextArea rows={2} maxLength={512} showCount />
          </Form.Item>
          <Form.Item label="附件图片">
            <Form.List name="attachmentUrls">
              {(fields, { add, remove }) => (
                <>
                  {fields.map((field) => (
                    <Space key={field.key} align="start" style={{ display: 'flex', marginBottom: 8 }}>
                      <Form.Item {...field} style={{ flex: 1, marginBottom: 0 }}>
                        <OssUpload bizType="SUPPORT_TICKET_ATTACHMENT" mediaType="IMAGE" />
                      </Form.Item>
                      {fields.length > 1 ? (
                        <MinusCircleOutlined onClick={() => remove(field.name)} style={{ marginTop: 8 }} />
                      ) : null}
                    </Space>
                  ))}
                  <Button type="dashed" onClick={() => add('')} block icon={<PlusOutlined />}>
                    添加附件
                  </Button>
                </>
              )}
            </Form.List>
          </Form.Item>
        </Form>
      </Modal>

      <Modal title="审批" open={reviewOpen} onCancel={() => setReviewOpen(false)} onOk={() => void submitReviewStep1()} confirmLoading={acting} destroyOnClose>
        <Form form={reviewForm} layout="vertical">
          <Form.Item name="decision" label="审批结果" rules={[{ required: true }]}>
            <Radio.Group
              onChange={(e) => setReviewDecision(e.target.value as 'APPROVE' | 'REJECT')}
              options={[
                { value: 'APPROVE', label: '通过' },
                { value: 'REJECT', label: '驳回' },
              ]}
            />
          </Form.Item>
          {reviewDecision === 'REJECT' ? (
            <Form.Item name="rejectReason" label="驳回理由" rules={[{ required: true }]}>
              <Input.TextArea rows={3} maxLength={512} showCount />
            </Form.Item>
          ) : (
            <Form.Item name="note" label="附注">
              <Input.TextArea rows={2} maxLength={512} showCount />
            </Form.Item>
          )}
        </Form>
      </Modal>

      <Modal title="创建开发任务" open={createTasksOpen} onCancel={() => setCreateTasksOpen(false)} onOk={() => void submitCreateTasks()} confirmLoading={acting} destroyOnClose width={640}>
        <Typography.Paragraph type="secondary">审批通过需至少创建 1 条开发计划任务。</Typography.Paragraph>
        <Form form={tasksForm} layout="vertical">
          <Form.List name="tasks">
            {(fields, { add, remove }) => (
              <>
                {fields.map(({ key, name, ...rest }) => (
                  <Space key={key} align="baseline" style={{ display: 'flex', marginBottom: 8 }}>
                    <Form.Item {...rest} name={[name, 'content']} rules={[{ required: true }]} style={{ flex: 1 }}>
                      <Input.TextArea rows={2} placeholder="任务内容" />
                    </Form.Item>
                    <Form.Item {...rest} name={[name, 'type']} rules={[{ required: true }]}>
                      <Select style={{ width: 100 }} options={TASK_TYPE_OPTIONS} />
                    </Form.Item>
                    {fields.length > 1 ? (
                      <MinusCircleOutlined onClick={() => remove(name)} />
                    ) : null}
                  </Space>
                ))}
                <Button type="dashed" onClick={() => add({ content: '', type: 'BUG' })} block icon={<PlusOutlined />}>
                  添加任务
                </Button>
              </>
            )}
          </Form.List>
          <Form.Item name="dispatchToWecom" valuePropName="checked" style={{ marginTop: 16 }}>
            <Checkbox>审批通过后发送到企微开发助手</Checkbox>
          </Form.Item>
          <Form.Item name="dispatchSupplement" label="派发补充说明">
            <Input.TextArea rows={2} placeholder={DEFAULT_DISPATCH_SUPPLEMENT} />
          </Form.Item>
        </Form>
      </Modal>

      <Modal
        title="编辑工单"
        open={editOpen}
        onCancel={() => setEditOpen(false)}
        onOk={() => void submitEdit()}
        confirmLoading={editSaving}
        destroyOnClose
        width={640}
      >
        <Form form={editForm} layout="vertical">
          <Form.Item name="ticketType" label="类型" rules={[{ required: true }]}>
            <Select options={TYPE_OPTIONS} />
          </Form.Item>
          <Form.Item name="priority" label="优先级" rules={[{ required: true }]}>
            <Select options={PRIORITY_OPTIONS} />
          </Form.Item>
          <Form.Item name="title" label="标题" rules={[{ required: true }]}>
            <Input maxLength={128} showCount />
          </Form.Item>
          <Form.Item name="content" label="详细说明">
            <Input.TextArea rows={5} maxLength={4000} showCount />
          </Form.Item>
          <Form.Item name="remark" label="备注">
            <Input.TextArea rows={2} maxLength={512} showCount />
          </Form.Item>
          <Form.Item label="附件图片">
            <Form.List name="attachmentUrls">
              {(fields, { add, remove }) => (
                <>
                  {fields.map((field) => (
                    <Space key={field.key} align="start" style={{ display: 'flex', marginBottom: 8 }}>
                      <Form.Item {...field} style={{ flex: 1, marginBottom: 0 }}>
                        <OssUpload bizType="SUPPORT_TICKET_ATTACHMENT" mediaType="IMAGE" />
                      </Form.Item>
                      {fields.length > 1 ? (
                        <MinusCircleOutlined onClick={() => remove(field.name)} style={{ marginTop: 8 }} />
                      ) : null}
                    </Space>
                  ))}
                  <Button type="dashed" onClick={() => add('')} block icon={<PlusOutlined />}>
                    添加附件
                  </Button>
                </>
              )}
            </Form.List>
          </Form.Item>
        </Form>
      </Modal>

      <Modal
        title="批量改状态"
        open={batchStatusOpen}
        onCancel={() => setBatchStatusOpen(false)}
        onOk={() => void submitBatchStatus()}
        confirmLoading={batchStatusSaving}
        destroyOnClose
      >
        <Typography.Paragraph type="secondary">已选 {selectedRowKeys.length} 条工单</Typography.Paragraph>
        <Form form={batchStatusForm} layout="vertical">
          <Form.Item name="status" label="目标状态" rules={[{ required: true }]}>
            <Select options={STATUS_OPTIONS.filter((o) => o.value !== 'PENDING_REVIEW')} />
          </Form.Item>
          <Form.Item noStyle shouldUpdate={(prev, cur) => prev.status !== cur.status}>
            {({ getFieldValue }) =>
              getFieldValue('status') === 'REJECTED' ? (
                <Form.Item name="rejectReason" label="驳回理由" rules={[{ required: true }]}>
                  <Input.TextArea rows={2} maxLength={512} showCount />
                </Form.Item>
              ) : null
            }
          </Form.Item>
          <Form.Item name="note" label="备注">
            <Input.TextArea rows={2} maxLength={512} showCount />
          </Form.Item>
        </Form>
      </Modal>

      <Modal
        title="一键发布"
        open={batchPublishOpen}
        onCancel={() => setBatchPublishOpen(false)}
        onOk={() => void submitBatchPublish()}
        confirmLoading={batchPublishSaving}
        destroyOnClose
      >
        <Typography.Paragraph type="secondary">
          已选 {selectedRowKeys.length} 条工单。将把各工单关联的开发任务追加到所选版本；无任务的工单将跳过。
        </Typography.Paragraph>
        <Form form={batchPublishForm} layout="vertical">
          <Form.Item name="versionId" label="开发版本" rules={[{ required: true, message: '请选择开发版本' }]}>
            <Select
              placeholder="选择版本"
              options={versions.map((v) => ({ value: v.id, label: v.versionNo }))}
            />
          </Form.Item>
          <Form.Item name="dispatchToWecom" valuePropName="checked">
            <Checkbox>同时发送到企微开发助手</Checkbox>
          </Form.Item>
          <Form.Item name="dispatchSupplement" label="派发补充说明">
            <Input.TextArea rows={2} placeholder={DEFAULT_DISPATCH_SUPPLEMENT} />
          </Form.Item>
        </Form>
      </Modal>

      <Modal
        title="批量 AI 审核确认"
        open={batchPreviewOpen}
        onCancel={() => setBatchPreviewOpen(false)}
        onOk={() => void submitBatchConfirm()}
        confirmLoading={batchConfirming}
        width={900}
        destroyOnClose
      >
        <Form form={batchForm} layout="vertical">
          <Form.List name="items">
            {(fields) => (
              <>
                {fields.map(({ key, name }) => {
                  const item = batchPreview[name];
                  if (!item) return null;
                  return (
                    <div key={key} style={{ marginBottom: 24, borderBottom: '1px solid #f0f0f0', paddingBottom: 16 }}>
                      <Typography.Text strong>
                        {item.ticketNo} · {item.title}
                      </Typography.Text>
                      <Form.Item name={[name, 'decision']} label="AI 建议">
                        <Radio.Group
                          options={[
                            { value: 'APPROVE', label: '通过' },
                            { value: 'REJECT', label: '驳回' },
                          ]}
                        />
                      </Form.Item>
                      <Form.Item name={[name, 'rejectReason']} label="驳回理由">
                        <Input.TextArea rows={2} />
                      </Form.Item>
                      <Form.Item name={[name, 'note']} label="附注">
                        <Input.TextArea rows={2} />
                      </Form.Item>
                      <Typography.Paragraph type="secondary" style={{ whiteSpace: 'pre-wrap' }}>
                        {item.reportMarkdown}
                      </Typography.Paragraph>
                      <Form.List name={[name, 'suggestedTasks']}>
                        {(taskFields, { add, remove }) => (
                          <>
                            <Typography.Text>建议任务</Typography.Text>
                            {taskFields.map(({ key: tk, name: tn, ...rest }) => (
                              <Space key={tk} align="baseline" style={{ display: 'flex' }}>
                                <Form.Item {...rest} name={[tn, 'content']} rules={[{ required: true }]}>
                                  <Input.TextArea rows={2} style={{ width: 400 }} />
                                </Form.Item>
                                <Form.Item {...rest} name={[tn, 'type']} rules={[{ required: true }]}>
                                  <Select style={{ width: 100 }} options={TASK_TYPE_OPTIONS} />
                                </Form.Item>
                                <MinusCircleOutlined onClick={() => remove(tn)} />
                              </Space>
                            ))}
                            <Button type="dashed" size="small" onClick={() => add({ content: '', type: 'BUG' })}>
                              添加任务
                            </Button>
                          </>
                        )}
                      </Form.List>
                    </div>
                  );
                })}
              </>
            )}
          </Form.List>
        </Form>
      </Modal>
    </div>
  );
}
