'use client';

import { useCallback, useEffect, useState } from 'react';
import { TEMPERATURE_AXIS_ZH, TEMPERATURE_META, type TemperatureValue } from '@pac/types';
import { plansApi, type PoolMatrix as PoolMatrixData } from '@/components/plans/plans-api';
import { PoolMatrix } from '@/components/plans/pool-matrix';
import { useAssignmentSyncStore } from '@/stores/assignment-sync-store';
import { CohortPreview } from './cohort-preview';
import { useAssistantStore } from '@/stores/assistant-store';
import { cn } from '@/lib/utils';

/**
 * 「分一批新的」—— **常驻面板**，摆在「我分的批次」正上方。
 *
 * 🔴 2026-08-11 产品定：**不再由按钮触发、也不再有第二版**。
 *   在此之前有两版（设计稿 `newBatchMode`）：`window` 居中 modal、`arcade` 里世界打地鼠，
 *   由头部一个「样式1 / 样式2」开关切，点「＋ 分一批新的」才展开。
 *   ⇒ 现在只保留 `window` 那份的内容（矩阵本身），并且**直接摊开**：
 *   矩阵是主管进这一屏的**第一个动作**，藏在按钮后面等于每次都要多点一下才看得到池子。
 *   ⛔ 别再把它收回浮层里 —— 上下结构（挑格子 → 看这些格子分出去之后怎么样）
 *   本身就是这一栏要讲的因果，收起来这条线就断了。
 * ⛔ 里世界那版（传送门 / 锤子光标 / 数据粒子）连同 globals.css 的 `.pac-portal-*`
 *   一起删了 —— 需要考古去翻 git，⛔ 别凭印象重写一份。
 *
 * ⛔ 挑完格子走的仍是**同一条**移交路：`useAssistantStore.handoff()` ——
 *   发数据流 → 粒子飞到助手 → 落地后自动开大窗并说那句话。
 *   ⚠️ 这条链路是现成的，⛔ 别在这儿另写一套移交：移交的时序（动画多长、
 *   什么时候开窗）是舞台层的事，业务侧复制一份必然漂。
 */

type Picked = {
  treatment: string;
  treatmentZh: string;
  temperature: TemperatureValue;
  count: number;
  rect: { x: number; y: number; w: number; h: number };
};

/**
 * 移交只有一条自然语言通道(模型看不到界面),所以这句话必须**自己说清是哪一格**。
 *
 * ⚠️ 2026-08-13 之前这里还要补一个「(按末诊)」标记,因为档位有两版口径 ——
 *   现在只剩一版(距上次到诊多久),标记跟着 `AnchorMode` 一起删了。⛔ 别加回来。
 */
function handoff(c: Picked) {
  const tempZh = TEMPERATURE_META[c.temperature].zh;
  const cell = `${c.treatmentZh} · ${tempZh}`;
  useAssistantStore.getState().handoff({
    text: `帮我给「${cell}」这批患者出一份分配方案`,
    from: c.rect,
    count: c.count,
    treatment: c.treatmentZh,
    temperature: tempZh,
  });
}

/// 中间表要用的那一格(不含 rect —— 粒子起点改成「确定」按钮,见 CohortPreview)
type PickedCell = Omit<Picked, 'rect'>;

export function NewBatchPanel({ clinicId }: { clinicId: string | null }) {
  const [matrix, setMatrix] = useState<PoolMatrixData | null>(null);
  const [error, setError] = useState<string | null>(null);

  /**
   * 换诊所先清空 —— ⛔ 不能让上一家的人数在新标题下面多留一帧
   * (那一帧里主管点下去,拿到的就是另一批人)。
   * ⚠️ 只挂 `clinicId`:下面那次「分完重拉」不走这里，否则每分一批矩阵都要闪一下骨架。
   */
  useEffect(() => {
    setMatrix(null);
    setError(null);
  }, [clinicId]);

  /**
   * 取矩阵。**助手那边确认/撤销之后也要重拉**（`syncSeq`）：
   * 刚分走的人就是从这些格子里出去的，不重拉的话主管会对着**已经分掉的数**再点一次。
   */
  const syncSeq = useAssignmentSyncStore((s) => s.seq);
  useEffect(() => {
    if (!clinicId) return;
    let alive = true;
    plansApi
      .matrix(clinicId)
      .then((r) => alive && setMatrix(r))
      .catch((e) => alive && setError(e instanceof Error ? e.message : '取矩阵失败'));
    return () => {
      alive = false;
    };
  }, [clinicId, syncSeq]);

  /**
   * 🔴 点格子**不再直接移交**(2026-08-11 产品定):先弹中间表,让主管看清这批人是谁,
   *   点「确定」才交给助手。
   * ⛔ 别为了"少一步"把它改回一点就走 —— 这一步换来的是主管对这批人**看过一眼**,
   *   而分配是他签字的动作。
   * ⚠️ 只存格子语义,⛔ 不存点击时的 rect:粒子起点已改成中间表上那个「确定」按钮
   *   (从一个已经被弹窗盖住的格子起飞,看起来像凭空出现)。
   */
  const [preview, setPreview] = useState<PickedCell | null>(null);
  const pick = useCallback((c: Picked) => {
    const { rect: _rect, ...cell } = c;
    setPreview(cell);
  }, []);

  return (
    <div className="flex w-full flex-col overflow-hidden rounded-lg border bg-white">
      <div className="flex flex-none flex-wrap items-center gap-x-2 gap-y-1 border-b px-3.5 py-2.5">
        <span className="text-[13.5px] font-semibold text-slate-900">分一批新的</span>
        {/*
          ⭐ 两句都是「这一屏怎么读」——**并到同一行**(2026-08-19 产品:「不用分那么散」)。
            「每一列 = …」原来挂在表格**下面**(见 `pool-matrix.tsx` 那段注释),
            一句在表上、一句在表下,同一类说明被表格劈成两半。
          ⚠️ 用 `·` 分隔:这一页别处也是这么并的(「1 个诊所 · 主管」「33 位在岗 · 在手 0 条」)。
          ⚠️ 两句**都不加粗**:它们是同一条灰色说明带,只加粗其中一句会读成"这句更要紧"。
          ⛔ 「每一列 = …」这句不许省(沿革见 `TEMPERATURE_AXIS_ZH`):列头写的是「三个月内」，
            而"什么的三个月"决定了它是哪批人;「患者」两个字尤其不能丢 —— 末诊是**患者级**的。
        */}
        <span className="text-[11px] text-slate-400">
          点一格 = 把这批人交给助手，助手出确认单 · 每一列 = {TEMPERATURE_AXIS_ZH}距今多久
        </span>
      </div>
      {/* ⚠️ 小屏兜底:矩阵有六列,窄了就横向滚,⛔ 别让它压缩到看不清数字 */}
      <div className="overflow-x-auto">
        {!clinicId ? (
          <p className="py-8 text-center text-[12px] text-slate-400">先选一家诊所</p>
        ) : error ? (
          <p className="py-8 text-center text-[12px] text-rose-600">{error}</p>
        ) : matrix ? (
          /* ⚠️ `w-full` 覆盖组件默认的 560px（那是当年给左栏 popover 的）——
             不覆盖的话这一栏有一千多像素宽而矩阵只占 560，右边一大片空白。
             `min-w-[34rem]` 保证再窄也不把数字挤糊，由外层横向滚兜住。 */
          <PoolMatrix
            data={matrix}
            selected={null}
            onPick={pick}
            className="w-full min-w-[34rem]"
          />
        ) : (
          <div className="space-y-2 p-3.5">
            {Array.from({ length: 6 }).map((_, i) => (
              <div key={i} className="h-6 animate-pulse rounded bg-slate-100" />
            ))}
          </div>
        )}
      </div>

      {preview && clinicId && (
        <CohortPreview
          clinicId={clinicId}
          cell={preview}
          onCancel={() => setPreview(null)}
          onConfirm={(from) => {
            setPreview(null);
            handoff({ ...preview, rect: from });
          }}
        />
      )}
    </div>
  );
}
