'use client';

import * as React from 'react';
import {
  PERSONA_FEATURE_GROUP_LABEL,
  PERSONA_FEATURE_GROUP_ORDER,
  personaFeatureGroup,
  personaFeatureSortKey,
  type PersonaFeatureGroup,
} from '@pac/types';
import { cn } from '@/lib/utils';
import { tone } from './shared';
import { PersonaFeatureHover } from './persona-feature-hover';
import { factLabel } from './fact-label';
import type { PersonaFeature } from './mock-data';
import type { AdaptedFact } from './adapt-data';

/**
 * 画像标签详情列表(抽屉体)。
 *
 * 相对旧版改了三件事:
 *  ① **分组 + 定序**。原来 16 张卡等权重平铺,顺序来自 `orderBy createdAt`;而同一版的 feature
 *     行是一条 createMany 写进去的、createdAt 完全相同 → 排序实际未定义,生产上呈现为英文 key
 *     字母序:「急迫等级 = 紧急」排在最后一个,「性别」「获客渠道」排在最前。现按用途分三组。
 *  ② **给出依据**。后端一直存着 evidence.factIds(rfm + lifecycle 两个特征在生产就占 1 GB),
 *     但前端 adapt-data 把它写死成空数组 —— 客服只看得到结论、看不到出处。现在反查同一份 facts
 *     渲染最近几条,并给出总条数。
 *  ③ **`?` 改成真按钮**。原来是 16×16 的 `<span>`,无 tabindex 无 role、纯 hover —— 键盘、读屏、
 *     平板触屏都够不着。现在是 button(focus 可触发 hover 卡),热区放大到 24×24。
 */
const MAX_EVIDENCE_ROWS = 4;

/**
 * 折扣锚点超过这个年数就提示「已过时」。
 *
 * 生产上见过 2018 年的锚点(8 年前)照旧原样展示 —— 客服照着那个折扣去谈会出事。
 * 阈值取 3 年:口腔项目定价与集团政策的调整周期大致在这个量级。
 */
const DISCOUNT_ANCHOR_STALE_YEARS = 3;

/** 折扣锚点的过时提醒;非折扣锚点或日期缺失 → null */
function staleAnchorHint(feature: PersonaFeature): string | null {
  if (feature.key !== 'discount_anchor') return null;
  const at = (feature.data as { anchorDate?: unknown } | null | undefined)?.anchorDate;
  if (typeof at !== 'string') return null;
  const years = (Date.now() - new Date(at).getTime()) / (365.25 * 86400_000);
  if (!Number.isFinite(years) || years < DISCOUNT_ANCHOR_STALE_YEARS) return null;
  return `该折扣发生在 ${Math.floor(years)} 年前,当时的定价与政策未必仍适用 —— 报价前请先与主管确认`;
}

export function PersonaDetailList({
  features,
  facts,
}: {
  features: PersonaFeature[];
  facts: AdaptedFact[];
}) {
  const factById = React.useMemo(() => new Map(facts.map((f) => [f.id, f])), [facts]);

  const grouped = React.useMemo(() => {
    const sorted = [...features].sort((a, b) => {
      const [ga, oa] = personaFeatureSortKey(a.key);
      const [gb, ob] = personaFeatureSortKey(b.key);
      return ga - gb || oa - ob || a.key.localeCompare(b.key);
    });
    const buckets = new Map<PersonaFeatureGroup | 'other', PersonaFeature[]>();
    for (const f of sorted) {
      const g = personaFeatureGroup(f.key) ?? 'other';
      buckets.set(g, [...(buckets.get(g) ?? []), f]);
    }
    return buckets;
  }, [features]);

  const sections: Array<[string, PersonaFeature[]]> = [
    ...PERSONA_FEATURE_GROUP_ORDER.map(
      (g) => [PERSONA_FEATURE_GROUP_LABEL[g], grouped.get(g) ?? []] as [string, PersonaFeature[]],
    ),
    // 注册表里没登记的标签不吞掉,兜到最后一组(比"标签凭空消失"好排查)
    ['其他', grouped.get('other') ?? []],
  ];

  return (
    <div className="space-y-4">
      {sections
        .filter(([, items]) => items.length > 0)
        .map(([label, items]) => (
          <section key={label} className="space-y-2">
            <h3 className="text-[10.5px] font-semibold tracking-wide text-slate-400">
              {label}
              <span className="ml-1.5 font-normal text-slate-300">{items.length}</span>
            </h3>
            {items.map((f) => (
              <FeatureCard key={f.key} feature={f} factById={factById} />
            ))}
          </section>
        ))}
    </div>
  );
}

function FeatureCard({
  feature: f,
  factById,
}: {
  feature: PersonaFeature;
  factById: Map<string, AdaptedFact>;
}) {
  const [showAll, setShowAll] = React.useState(false);
  const T = tone(f.tone);
  const staleHint = staleAnchorHint(f);

  // 多值特征(治疗史 / 潜在治疗 / 时间偏好…)后端给结构化 data.labels —— 详情里全部展开,
  // 不像卡片那样截成 "+N"。单值特征直接显示后端那句完整 description。
  const labels = (f.data as { labels?: unknown } | null | undefined)?.labels;
  const valueLabels =
    Array.isArray(labels) && labels.every((x) => typeof x === 'string') ? (labels as string[]) : null;

  // 证据:只渲染能在本次响应的 facts 里找到的(跨版本的旧 fact 可能已被 supersede,查不到就不显)
  const resolved = f.evidence
    .map((id) => factById.get(id))
    .filter((x): x is AdaptedFact => !!x)
    .sort((a, b) => (b.occurredAt ?? '').localeCompare(a.occurredAt ?? ''));
  const shown = showAll ? resolved : resolved.slice(0, MAX_EVIDENCE_ROWS);

  return (
    <div className="relative rounded-md border border-slate-100 p-3 pr-9">
      {/* 右上角 ? —— 真 button:可 Tab 聚焦,focus 也能唤出说明卡(触屏/键盘可达) */}
      <PersonaFeatureHover featureKey={f.key} value={f.value}>
        <button
          type="button"
          className="absolute top-1.5 right-1.5 inline-flex h-6 w-6 items-center justify-center rounded-full text-slate-400 hover:bg-slate-100 hover:text-slate-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-teal-500"
          aria-label={`${f.label} 怎么算的`}
        >
          <svg viewBox="0 0 24 24" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="2">
            <circle cx="12" cy="12" r="10" />
            <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3M12 17h.01" strokeLinecap="round" strokeLinejoin="round" />
          </svg>
        </button>
      </PersonaFeatureHover>

      {/* 属性名 */}
      <div className={cn('inline-flex items-center gap-1.5 text-[11px] font-semibold', T.text)}>
        <span className={cn('h-1.5 w-1.5 rounded-full', T.dot)} />
        {f.label}
      </div>

      {/* 取值条目 — 多值展开为 chip,单值显示文本 */}
      {valueLabels && valueLabels.length > 0 ? (
        <div className="mt-1.5 flex flex-wrap gap-1">
          {valueLabels.map((l, i) => (
            <span
              key={i}
              className="inline-flex items-center rounded bg-slate-50 px-1.5 py-0.5 text-[12px] font-medium text-slate-800 ring-1 ring-slate-100"
            >
              {l}
            </span>
          ))}
        </div>
      ) : (
        f.value && <div className="mt-1 text-[13px] font-medium text-slate-900">{f.value}</div>
      )}

      {/* 过时提醒 —— 目前只有折扣锚点会触发(见 staleAnchorHint) */}
      {staleHint && (
        <p className="mt-1.5 flex gap-1 rounded bg-amber-50 px-1.5 py-1 text-[10.5px] leading-relaxed text-amber-800">
          <span aria-hidden>⚠️</span>
          <span>{staleHint}</span>
        </p>
      )}

      {/* 依据 —— 这个标签是被哪些事实推出来的 */}
      {resolved.length > 0 && (
        <div className="mt-2 border-t border-slate-100 pt-2">
          <div className="mb-1 flex items-baseline gap-2">
            <span className="text-[10.5px] text-slate-400">依据 · {resolved.length} 条</span>
            {resolved.length > MAX_EVIDENCE_ROWS && (
              <button
                type="button"
                onClick={() => setShowAll((v) => !v)}
                className="text-[10.5px] text-teal-700 hover:underline"
              >
                {showAll ? '收起' : `展开全部`}
              </button>
            )}
          </div>
          <ul className="space-y-0.5">
            {shown.map((fact) => {
              const { badge, badgeTone, text: label, hover } = factLabel(fact);
              return (
                <li key={fact.id} className="flex items-baseline gap-1.5 text-[11px] leading-relaxed">
                  {/* 日期不折行 —— 定宽 68px 装不下 `2026-03-27`(11px 字号)会断成两行;
                      改为按内容撑开 + nowrap,tabular-nums 保证各行等宽自然对齐 */}
                  <span className="flex-none whitespace-nowrap tabular-nums text-slate-400">
                    {(fact.occurredAt ?? fact.plannedFor ?? '').slice(0, 10) || '—'}
                  </span>
                  <span className={cn('flex-none rounded px-1 text-[10px]', badgeTone)}>{badge}</span>
                  <span className="min-w-0 flex-1 truncate text-slate-700" title={hover ?? label}>
                    {label}
                  </span>
                </li>
              );
            })}
          </ul>
        </div>
      )}
    </div>
  );
}
