import { IconRefresh, IconSearch } from '@douyinfe/semi-icons';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useDeferredValue, useEffect, useMemo, useState } from 'react';
import { api } from '../../api/client';
import type { ReconciliationIssue } from '../../api/types';
import { InlineError } from '../shared/AsyncState';
import { QUERY_MEMORY } from '../queryPolicy';

const PAGE_SIZE = 50;
const activeStatuses = new Set(['pending', 'confirmed_source_a', 'confirmed_source_b']);
const reviewStatuses = [
  { value: 'pending', label: '待处理' },
  { value: 'confirmed_source_a', label: '确认来源 A' },
  { value: 'confirmed_source_b', label: '确认来源 B' },
  { value: 'no_action', label: '无需处理' },
  { value: 'fixed', label: '已修复' }
];

function statusLabel(status: string) {
  return {
    pending: '待处理',
    confirmed_source_a: '确认来源 A',
    confirmed_source_b: '确认来源 B',
    no_action: '无需处理',
    fixed: '已修复',
    recovered: '已恢复'
  }[status] ?? status;
}

function severityLabel(severity: string) {
  return { critical: '严重', major: '重要', minor: '一般' }[severity] ?? severity;
}

function ruleLabel(rule: string) {
  return {
    DUPLICATE_PLATE: '重复车牌',
    DUPLICATE_PHONE: '重复终端',
    UNBOUND_SOURCE: '来源未绑定',
    SOURCE_MISSING: '主车无来源',
    POSITION_DRIFT: '位置漂移',
    MILEAGE_REVERSE: '里程倒退',
    MILEAGE_JUMP: '里程跳变',
    MILEAGE_SOURCE_DIVERGENCE: '里程来源差异',
    FLEET_COUNT_MISMATCH: '车辆总数不一致',
    BUSINESS_SCOPE_UNBOUND: '业务车辆未绑定',
    AUTH_SCOPE_BUSINESS_MISMATCH: '授权与业务范围不一致'
  }[rule] ?? rule;
}

function fmt(value?: string) {
  if (!value) return '—';
  const parsed = new Date(value.replace(' ', 'T'));
  return Number.isNaN(parsed.getTime()) ? value : parsed.toLocaleString('zh-CN', { hour12: false });
}

function evidenceValue(value: unknown) {
  if (value == null || value === '') return '—';
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return String(value);
  return JSON.stringify(value, null, 2);
}

function ReconciliationDetail({ issue, onClose }: { issue: ReconciliationIssue; onClose: () => void }) {
  const queryClient = useQueryClient();
  const [status, setStatus] = useState(issue.status === 'recovered' ? 'pending' : issue.status);
  const [note, setNote] = useState(issue.resolutionNote ?? '');
  useEffect(() => {
    setStatus(issue.status === 'recovered' ? 'pending' : issue.status);
    setNote(issue.resolutionNote ?? '');
  }, [issue.id, issue.resolutionNote, issue.status]);
  const save = useMutation({
    mutationFn: () => api.updateReconciliationIssue(issue.id, { version: issue.version, status, note: note.trim() }),
    onSuccess: async (updated) => {
      queryClient.setQueryData(['reconciliation-detail', issue.id], updated);
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: ['reconciliation-summary'] }),
        queryClient.invalidateQueries({ queryKey: ['reconciliation-issues'] })
      ]);
    }
  });
  const requiresNote = status !== 'pending';
  return <aside className="v2-reconcile-detail" aria-label="差异证据与处置">
    <header>
      <div><span className={`is-${issue.severity}`}>{severityLabel(issue.severity)}</span><strong>{issue.title}</strong><small>{ruleLabel(issue.ruleCode)}</small></div>
      <button type="button" onClick={onClose} aria-label="关闭差异详情">×</button>
    </header>
    <div className="v2-reconcile-detail-body">
      <section className="v2-reconcile-identity">
        <div><small>车辆</small><strong>{issue.plate || '未登记车牌'}</strong><span>{issue.vin || '非单车差异'}</span></div>
        <div><small>来源</small><strong>{[issue.protocolA, issue.protocolB].filter(Boolean).join(' ↔ ') || '平台口径'}</strong><span>累计发现 {issue.occurrenceCount.toLocaleString('zh-CN')} 次</span></div>
        <div><small>时间</small><strong>{fmt(issue.lastSeenAt)}</strong><span>首次 {fmt(issue.firstSeenAt)}</span></div>
      </section>
      <p className="v2-reconcile-summary">{issue.summary}</p>
      <section className="v2-reconcile-evidence">
        <header><strong>规则证据</strong><span>保留来源值、时间与影响对象；未知来源不自动判对错</span></header>
        <dl>{Object.entries(issue.evidence ?? {}).map(([key, value]) => <div key={key}><dt>{key}</dt><dd><pre>{evidenceValue(value)}</pre></dd></div>)}</dl>
      </section>
      <section className="v2-reconcile-review">
        <header><strong>复核结论</strong><span>版本 v{issue.version}</span></header>
        <label><span>处置状态</span><select value={status} onChange={(event) => setStatus(event.target.value)}>{reviewStatuses.map((item) => <option key={item.value} value={item.value}>{item.label}</option>)}</select></label>
        <label><span>说明{requiresNote ? '（必填）' : '（可选）'}</span><textarea value={note} maxLength={500} onChange={(event) => setNote(event.target.value)} placeholder="记录核对来源、原始值、责任人或修复结果" /></label>
        <button type="button" disabled={save.isPending || (requiresNote && !note.trim())} onClick={() => save.mutate()}>{save.isPending ? '正在保存…' : '保存复核结论'}</button>
        {save.isError ? <p role="alert">{save.error instanceof Error ? save.error.message : '保存失败'}</p> : null}
      </section>
      <section className="v2-reconcile-actions">
        <header><strong>处理履历</strong><span>{issue.actions?.length ?? 0} 条</span></header>
        {issue.actions?.length ? <ol>{issue.actions.map((action) => <li key={action.id}><i /><div><strong>{statusLabel(action.toStatus)}</strong><p>{action.note || action.action}</p><span>{action.actor} · {fmt(action.createdAt)}</span></div></li>)}</ol> : <p>暂无处理记录。</p>}
      </section>
    </div>
  </aside>;
}

export default function ReconciliationCenter() {
  const [keyword, setKeyword] = useState('');
  const deferredKeyword = useDeferredValue(keyword.trim());
  const [status, setStatus] = useState('active');
  const [severity, setSeverity] = useState('all');
  const [ruleCode, setRuleCode] = useState('all');
  const [offset, setOffset] = useState(0);
  const [selectedID, setSelectedID] = useState('');
  useEffect(() => setOffset(0), [deferredKeyword, ruleCode, severity, status]);

  const summary = useQuery({
    queryKey: ['reconciliation-summary', 30],
    queryFn: ({ signal }) => api.reconciliationSummary(30, signal),
    staleTime: 60_000,
    gcTime: QUERY_MEMORY.summaryGcTime
  });
  const issues = useQuery({
    queryKey: ['reconciliation-issues', deferredKeyword, ruleCode, severity, status, offset],
    queryFn: ({ signal }) => api.reconciliationIssues({
      keyword: deferredKeyword, ruleCode, severity, status, limit: PAGE_SIZE, offset
    }, signal),
    staleTime: 20_000,
    gcTime: QUERY_MEMORY.highVolumeGcTime
  });
  const detail = useQuery({
    queryKey: ['reconciliation-detail', selectedID],
    queryFn: ({ signal }) => api.reconciliationIssue(selectedID, signal),
    enabled: Boolean(selectedID),
    staleTime: 10_000,
    gcTime: QUERY_MEMORY.optionGcTime
  });
  const maxTrend = useMemo(() => {
    let result = 1;
    for (const item of summary.data?.trend ?? []) result = Math.max(result, item.active, item.new, item.recovered);
    return result;
  }, [summary.data?.trend]);
  const refresh = () => Promise.all([summary.refetch(), issues.refetch(), selectedID ? detail.refetch() : Promise.resolve()]);
  const data = summary.data;
  const page = issues.data;
  const activeCount = page?.items.filter((item) => activeStatuses.has(item.status)).length ?? 0;

  return <section className="v2-reconcile-center">
    <header className="v2-reconcile-heading">
      <div><small>每日自动对账</small><strong>数据差异中心</strong><span>自动发现、相同问题去重、恢复后闭环；复核人员只确认证据，不凭空修改原始数据。</span></div>
      <button type="button" onClick={refresh} disabled={summary.isFetching || issues.isFetching}><IconRefresh />刷新结果</button>
    </header>
    {summary.isError ? <InlineError message={summary.error.message} onRetry={() => summary.refetch()} /> : null}
    <div className="v2-reconcile-kpis">
      <article className="is-active"><small>活跃差异</small><strong>{data?.active.toLocaleString('zh-CN') ?? '—'}</strong><span>待处理与已确认来源</span></article>
      <article><small>待复核</small><strong>{data?.pending.toLocaleString('zh-CN') ?? '—'}</strong><span>尚未形成结论</span></article>
      <article><small>已确认来源</small><strong>{data?.confirmed.toLocaleString('zh-CN') ?? '—'}</strong><span>保留为活跃差异</span></article>
      <article><small>自动恢复</small><strong>{data?.recovered.toLocaleString('zh-CN') ?? '—'}</strong><span>检测不再命中</span></article>
      <article className={data?.overSla ? 'is-overdue' : ''}><small>超过 24 小时</small><strong>{data?.overSla.toLocaleString('zh-CN') ?? '—'}</strong><span>需要优先跟进</span></article>
    </div>
    <div className="v2-reconcile-layout">
      <div className="v2-reconcile-main">
        <div className="v2-reconcile-toolbar">
          <label className="v2-reconcile-search"><IconSearch /><input aria-label="搜索差异车辆或规则" value={keyword} onChange={(event) => setKeyword(event.target.value)} placeholder="车牌、VIN、标题或说明" /></label>
          <select aria-label="筛选差异状态" value={status} onChange={(event) => setStatus(event.target.value)}>
            <option value="active">活跃差异</option><option value="pending">待处理</option><option value="confirmed_source_a">确认来源 A</option><option value="confirmed_source_b">确认来源 B</option><option value="recovered">已恢复</option><option value="fixed">已修复</option><option value="no_action">无需处理</option><option value="all">全部状态</option>
          </select>
          <select aria-label="筛选严重程度" value={severity} onChange={(event) => setSeverity(event.target.value)}>
            <option value="all">全部等级</option><option value="critical">严重</option><option value="major">重要</option><option value="minor">一般</option>
          </select>
          <select aria-label="筛选差异规则" value={ruleCode} onChange={(event) => setRuleCode(event.target.value)}>
            <option value="all">全部规则</option>{data?.byRule.map((item) => <option key={item.name} value={item.name}>{ruleLabel(item.name)} · {item.count}</option>)}
          </select>
        </div>
        {issues.isError ? <InlineError message={issues.error.message} onRetry={() => issues.refetch()} /> : null}
        <div className="v2-reconcile-table-wrap">
          <table className="v2-reconcile-table"><thead><tr><th>等级</th><th>差异 / 规则</th><th>车辆</th><th>来源</th><th>最近发现</th><th>状态</th></tr></thead>
            <tbody>{page?.items.map((item) => <tr key={item.id} role="button" tabIndex={0} className={selectedID === item.id ? 'is-selected' : ''} onClick={() => setSelectedID(item.id)} onKeyDown={(event) => { if (event.key === 'Enter' || event.key === ' ') setSelectedID(item.id); }}>
              <td><span className={`v2-reconcile-severity is-${item.severity}`}>{severityLabel(item.severity)}</span></td>
              <td><strong>{item.title}</strong><span>{ruleLabel(item.ruleCode)} · 命中 {item.occurrenceCount.toLocaleString('zh-CN')} 次</span></td>
              <td><strong>{item.plate || '非单车差异'}</strong><span>{item.vin || '平台级口径'}</span></td>
              <td><strong>{[item.protocolA, item.protocolB].filter(Boolean).join(' / ') || '平台口径'}</strong><span>{item.category}</span></td>
              <td><strong>{fmt(item.lastSeenAt)}</strong><span>首次 {fmt(item.firstSeenAt)}</span></td>
              <td><span className={`v2-reconcile-status is-${item.status}`}>{statusLabel(item.status)}</span></td>
            </tr>)}</tbody>
          </table>
          {issues.isPending ? <p className="v2-reconcile-empty">正在读取差异队列…</p> : null}
          {!issues.isPending && !page?.items.length ? <p className="v2-reconcile-empty">当前筛选条件下没有差异。</p> : null}
        </div>
        <footer className="v2-reconcile-pagination"><span>共 {(page?.total ?? 0).toLocaleString('zh-CN')} 条 · 本页 {activeCount} 条活跃</span><div><button type="button" disabled={offset === 0} onClick={() => setOffset(Math.max(0, offset - PAGE_SIZE))}>上一页</button><button type="button" disabled={offset + PAGE_SIZE >= (page?.total ?? 0)} onClick={() => setOffset(offset + PAGE_SIZE)}>下一页</button></div></footer>
      </div>
      <aside className="v2-reconcile-trend">
        <header><strong>近 30 天趋势</strong><span>最近运行 {fmt(data?.lastRunAt)}</span></header>
        <div>{data?.trend.slice(-14).map((item) => <article key={item.date}><time>{item.date.slice(5)}</time><div title={`存量 ${item.active}，新增 ${item.new}，恢复 ${item.recovered}`}><i className="is-active" style={{ width: `${Math.max(2, item.active / maxTrend * 100)}%` }} /><i className="is-new" style={{ width: `${Math.max(0, item.new / maxTrend * 100)}%` }} /><i className="is-recovered" style={{ width: `${Math.max(0, item.recovered / maxTrend * 100)}%` }} /></div><b>{item.active}</b></article>)}</div>
        {!data?.trend.length ? <p>完成首次每日检测后显示趋势。</p> : null}
        <footer><span><i className="is-active" />存量</span><span><i className="is-new" />新增</span><span><i className="is-recovered" />恢复</span></footer>
      </aside>
      {selectedID && detail.isPending ? <aside className="v2-reconcile-detail"><div className="v2-reconcile-empty">正在读取证据…</div></aside> : null}
      {selectedID && detail.isError ? <aside className="v2-reconcile-detail"><InlineError message={detail.error.message} onRetry={() => detail.refetch()} /></aside> : null}
      {detail.data ? <ReconciliationDetail issue={detail.data} onClose={() => setSelectedID('')} /> : null}
    </div>
  </section>;
}
