'use client';

import { useEffect, useState } from 'react';
import { Loader2 } from 'lucide-react';
import { potentialTreatmentCardLabel } from '@pac/types';
import { cn } from '@/lib/utils';
import { plansApi, type PoolMatrix, type PoolMatrixRow } from './plans-api';

/**
 * PoolMatrix — 初选矩阵(8 潜在治疗 × 3 窗口温度)。
 *
 * 生产线的**第一环**:主管在这里点一格,就完成了「初选」,人群随即交给助手出确认单。
 * 矩阵是召回池的一个**视图模式**(列表 ⇄ 矩阵),⛔ 不新开路由 ——
 * 主管本质也是客服、也要执行,割裂成两个页面会把他劈成两个身份(T16)。
 *
 * ═══ 三条配色纪律(五之三)═══════════════════════════════════════
 * ⛔ **数量不参与配色**,底色**按列固定**。
 *   否则「这格橙是因为热、还是因为人多」分不清 —— 实现上列头决定 class,
 *   cell 一个字都不参与计算。⛔ 别写任何 `count > N ? ... : ...`。
 * ⛔ **热不用红**:红太冲,是"出事了";橙才是"该动手了"。
 * ⛔ **别用 brand-***:品牌蓝 #0032A0 比冷档的 blue-100 深太多,混用会让「冷」看着像选中态。
 *
 * ⚠️ 三档之外还有一列**「待重算」** —— 上线到全量重算跑完之间,老画像没有窗口边界。
 *   把它们并进「冷」能让行合计好看,但那是**假分布**(T14)。宁可多一列让主管问一句。
 */

/** 列定义:底色写死在这里,**与任何数字无关**(见文件头配色纪律) */
const COLUMNS = [
  { key: 'hot', icon: '🔥', zh: '热', cell: 'bg-orange-400 text-white hover:bg-orange-500', hint: '还在该治疗自己的黄金期内 —— 医生刚说过,患者还记得' },
  { key: 'warm', icon: '🌡', zh: '温', cell: 'bg-amber-100 text-amber-900 hover:bg-amber-200', hint: '过了黄金期但没出临床周期 —— 还来得及,话术要给个理由' },
  { key: 'cold', icon: '❄️', zh: '冷', cell: 'bg-blue-100 text-blue-900 hover:bg-blue-200', hint: '超出该治疗的临床周期 —— 情况可能已经变了,先问近况' },
] as const;

type TempKey = (typeof COLUMNS)[number]['key'];

export function PoolMatrix({
  clinicId,
  selected,
  onPick,
}: {
  clinicId?: string;
  /** 当前选中的格子(回显用) */
  selected?: { treatment: string; temperature: TempKey } | null;
  /** 点格子 → 初选完成,把这一格的人群交出去 */
  onPick: (cell: { treatment: string; treatmentZh: string; temperature: TempKey; count: number }) => void;
}) {
  const [data, setData] = useState<PoolMatrix | null>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    let alive = true;
    setError(null);
    plansApi
      .matrix(clinicId)
      .then((d) => alive && setData(d))
      .catch((e: unknown) => alive && setError(e instanceof Error ? e.message : String(e)));
    return () => {
      alive = false;
    };
  }, [clinicId]);

  if (error) {
    return <div className="p-3 text-[12px] text-rose-600">矩阵加载失败:{error}</div>;
  }
  if (!data) {
    return (
      <div className="flex items-center justify-center gap-2 p-6 text-[12px] text-slate-400">
        <Loader2 className="h-3.5 w-3.5 animate-spin" />
        正在数人…
      </div>
    );
  }

  return (
    <div className="flex-1 overflow-y-auto p-2">
      <table className="w-full border-separate border-spacing-[3px] text-[12px]">
        <thead>
          <tr>
            <th className="w-[66px] text-left font-normal text-slate-400">潜在治疗</th>
            {COLUMNS.map((c) => (
              <th key={c.key} title={c.hint} className="font-medium text-slate-600">
                {c.icon} {c.zh}
              </th>
            ))}
            {data.unknownTotal > 0 && (
              <th
                className="font-normal text-slate-400"
                title="画像还没算出窗口边界,温度待重算。⛔ 没有并进「冷」——并进去数字好看,但那是假分布。"
              >
                待重算
              </th>
            )}
          </tr>
        </thead>
        <tbody>
          {data.rows.map((row) => (
            <MatrixRow
              key={row.key}
              row={row}
              showUnknown={data.unknownTotal > 0}
              selected={selected}
              onPick={onPick}
            />
          ))}
        </tbody>
      </table>

      {/* ⚠️ 口径必须写在脸上:矩阵按**患者**去重,列表按 plan 分页。
          不写的话主管一对数就觉得系统在骗他(验证策略「口径对数」那一条)。 */}
      <p className="px-1 pt-2 text-[10.5px] leading-relaxed text-slate-400">
        数字是<span className="font-medium text-slate-500">位患者</span>(已去重),不是任务条数。
        点一格即把这批人交给助手出分配方案。
      </p>
      {data.note && (
        <p className="mt-1 rounded bg-amber-50 px-2 py-1.5 text-[10.5px] leading-relaxed text-amber-800">
          {data.note}
        </p>
      )}
    </div>
  );
}

function MatrixRow({
  row,
  showUnknown,
  selected,
  onPick,
}: {
  row: PoolMatrixRow;
  showUnknown: boolean;
  selected?: { treatment: string; temperature: TempKey } | null;
  onPick: (cell: { treatment: string; treatmentZh: string; temperature: TempKey; count: number }) => void;
}) {
  // ⛔ 中文一律查 labels.ts,别在组件里另写一张表 —— 改措辞要即时生效、且全站一处
  const zh = potentialTreatmentCardLabel(row.key);
  return (
    <tr>
      <th
        scope="row"
        title={row.hint}
        className="truncate text-left text-[11.5px] font-normal text-slate-600"
      >
        {zh}
      </th>
      {COLUMNS.map((c) => {
        const n = row[c.key];
        const isSelected = selected?.treatment === row.key && selected.temperature === c.key;
        return (
          <td key={c.key} className="p-0">
            <button
              type="button"
              disabled={n === 0}
              onClick={() => onPick({ treatment: row.key, treatmentZh: zh, temperature: c.key, count: n })}
              title={n === 0 ? `${zh}·${c.zh}:暂无人` : `${zh}·${c.zh}:${n} 位患者 —— 点击交给助手`}
              className={cn(
                'h-7 w-full rounded text-[12px] tabular-nums transition-colors',
                // ⭐ 底色只看列(c.cell),**不看 n** —— 见文件头配色纪律
                n === 0
                  ? 'cursor-default bg-slate-50 text-slate-300'
                  : cn(c.cell, 'cursor-pointer font-medium'),
                isSelected && 'ring-2 ring-slate-800 ring-offset-1',
              )}
            >
              {n}
            </button>
          </td>
        );
      })}
      {showUnknown && (
        <td className="p-0">
          <div
            className="flex h-7 items-center justify-center rounded bg-slate-50 text-[11.5px] tabular-nums text-slate-400"
            title="温度待重算 —— 画像还没算出窗口边界。这是重算进度,不是数据缺失。"
          >
            {row.unknown || '—'}
          </div>
        </td>
      )}
    </tr>
  );
}
