'use client';

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

/**
 * PoolMatrix — 初选矩阵(8 潜在治疗 × 3 窗口温度)。
 *
 * 生产线的**第一环**:主管在这里点一格,就完成了「初选」,人群随即交给助手出确认单。
 * 矩阵是召回池的一个**视图模式**(tab 行「分配」浮层展开),⛔ 不新开路由 ——
 * 主管本质也是客服、也要执行,割裂成两个页面会把他劈成两个身份(T16)。
 *
 * ═══ 配色纪律(五之三 + 2026-08 产品走查)═══════════════════════════
 * ⭐ **整片矩阵共用一条横向渐变**(橙 → 琥珀 → 蓝),格子本身**没有**自己的底色。
 *   温度是**连续量**;给每格各刷一块色 = 把它退化成三个并列的分类,冷热轴的意思就没了。
 *   实现上渐变挂在**行容器**上,格子透明浮在上面 —— 于是列与列、行与行连成一整片。
 * ⛔ **数量不参与配色**(纪律没变):渐变只由**列的位置**决定,格子里的数字一个字都不参与。
 *   否则「这格橙是因为热、还是因为人多」分不清。
 * ⛔ **热不用红**:红太冲,是"出事了";橙才是"该动手了"。
 * ⛔ **别用 brand-***:品牌蓝比冷档深太多,混用会让「冷」看着像选中态。
 *
 * ⚠️ 渐变的色标位置(20% / 50% / 80%)是**对着三列的列心**定的:
 *   三列均分,列心在 16.7% / 50% / 83.3% —— 正好落在纯橙 / 纯琥珀 / 纯蓝上,数字对比度才够。
 *   改列数或列宽必须同步改色标,否则中间那列的字会糊在过渡色里。
 */

/**
 * 列定义。⚠️ 这里**只剩文字色** —— 底色统一由行容器的渐变给。
 * 想给某一列单独加底色前先看文件头:那会把"一条轴"重新切回"三个分类"。
 */
const COLUMNS = [
  { key: 'hot', icon: '🔥', zh: '热', text: 'text-white' },
  { key: 'warm', icon: '🌡', zh: '温', text: 'text-amber-900' },
  { key: 'cold', icon: '❄️', zh: '冷', text: 'text-blue-900' },
] as const;

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

/// 整片矩阵(以及列头那条刻度)共用的同一条渐变 —— 写两遍必然漂
const SCALE = 'bg-gradient-to-r from-orange-400 from-20% via-amber-100 via-50% to-blue-100 to-80%';
/// 行标签列宽。列头、刻度条、每一行都靠它对齐,别在某一处手改
const LABEL_W = 'w-[52px]';

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>
    );
  }

  const showUnknown = data.unknownTotal > 0;

  return (
    <div className="p-2">
      {/* 列头 + 温度计刻度 */}
      <div className="flex items-end">
        <div className={cn(LABEL_W, 'shrink-0 text-[11px] text-slate-400')}>潜在治疗</div>
        <div className="flex-1">
          <div className="flex">
            {COLUMNS.map((c) => (
              <div key={c.key} className="flex-1 text-center text-[12px] font-medium text-slate-600">
                {c.icon} {c.zh}
              </div>
            ))}
          </div>
          {/* 刻度与下面的格子是**同一条**渐变、首尾对齐 —— 它就是这片色块的图例 */}
          <div className={cn('mt-1 h-1.5 rounded-full', SCALE)} />
        </div>
        {showUnknown && <div className="w-11 shrink-0 text-center text-[11px] text-slate-400">待重算</div>}
      </div>

      {/* 矩阵本体:每行一条渐变、行行紧贴 → 整片连成一块 */}
      <div className="mt-1 overflow-hidden rounded">
        {data.rows.map((row) => (
          <MatrixRow
            key={row.key}
            row={row}
            showUnknown={showUnknown}
            selected={selected}
            onPick={onPick}
          />
        ))}
      </div>

      {data.note && (
        <p className="mt-1.5 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,别在组件里另写一张表 —— 改措辞要即时生效、且全站一处。
  //   用**项目名**(种植 / 早矫 / 拔牙)而不是卡片措辞(种植治疗):
  //   8×3 的表里每行都拖着「治疗」两个字纯属噪声,还挤掉列宽。
  const zh = potentialTreatmentItemName(row.key);
  return (
    <div className="flex items-stretch">
      <div className={cn(LABEL_W, 'shrink-0 self-center pr-1.5 text-right text-[11.5px] text-slate-600')}>
        {zh}
      </div>
      {/* ⭐ 渐变在这一层,三个格子透明浮在上面 —— 列间没有缝,整行是一条色带 */}
      <div className={cn('flex flex-1', SCALE)}>
        {COLUMNS.map((c) => {
          const n = row[c.key];
          const isSelected = selected?.treatment === row.key && selected.temperature === c.key;
          return (
            <button
              key={c.key}
              type="button"
              disabled={n === 0}
              onClick={() => onPick({ treatment: row.key, treatmentZh: zh, temperature: c.key, count: n })}
              // ⭐ hover 只给**天数区间**,不给解释:格子里已经有数字、列头已经写了热/温/冷,
              //   再叠一段说明就是噪声。区间是主管唯一看不出来的那个信息。
              title={temperatureWindowHint(row.key, c.key as TemperatureValue)}
              className={cn(
                'flex-1 py-1.5 text-[12px] tabular-nums transition-colors',
                // ⛔ 底色来自父层渐变;这里只管**文字色与交互态**(见文件头配色纪律)
                n === 0
                  ? 'cursor-default text-slate-400/70'
                  : cn(c.text, 'cursor-pointer font-medium hover:bg-white/30'),
                isSelected && 'bg-white/40 ring-2 ring-inset ring-slate-800',
              )}
            >
              {n || '—'}
            </button>
          );
        })}
      </div>
      {showUnknown && (
        <div
          className="flex w-11 shrink-0 items-center justify-center bg-slate-50 text-[11.5px] tabular-nums text-slate-400"
          title="温度待重算 —— 画像还没算出窗口边界"
        >
          {row.unknown || '—'}
        </div>
      )}
    </div>
  );
}
