'use client';

import { useEffect, useRef, useState } from 'react';
import { useAuthStore, visibleClinics } from '@/stores/auth-store';
import { AssistantWidget } from '@/components/assistant/assistant-widget';
import { SupervisorHeader } from './supervisor-header';
import { BatchTracking } from './batch-tracking';
import { TeamStatus } from './team-status';
import { NewBatchOverlay, type NewBatchMode } from './new-batch';
import { cn } from '@/lib/utils';

/**
 * 主管工作台 —— 左「我分的批次」/ 右「团队现在什么状态」。
 *
 * ⚠️ 设计稿是 1440×1000 的固定框，这里做**自适应**（2026-08-07 产品定，与现有页面一致）：
 *   右栏固定 34rem、左栏吃剩下的；<1280px 时右栏落到下面（⛔ 别横向滚 ——
 *   这页会嵌在宿主 iframe 里，横条比换行难受得多）。
 *   ⚠️ 34rem 比设计稿的 470px 宽 —— 那个宽度装不下退回率的两个分母（见下方注释）。
 *
 * ⚠️ 诊所是这一屏**所有查询的前提**（批次、团队都按诊所）。没有诊所就什么都不查，
 *   ⛔ 别用「全部诊所」兜底：那会把别家的负载混进来，而主管管的是自己这一家。
 */
export function SupervisorWorkbench() {
  const user = useAuthStore((s) => s.user);
  const clinics = visibleClinics(user);
  const [clinicId, setClinicId] = useState<string | null>(null);

  /**
   * 默认落到第一个可见诊所。
   *
   * 🔴 **必须校验"当前选的还在不在列表里"**，⛔ 不能只判 `clinicId == null`
   *   （2026-08-07 实测踩过）：`visibleClinics` 在 session 加载**之前**会回落到
   *   「字典里的全部诊所」（`user.clinicIds` 还是空的），于是第一帧就把一个
   *   **别家诊所**锁进了 state；session 回来后列表缩成他自己那一家，
   *   而 clinicId 已经指向别处 —— 界面表现是：头部显示「选择诊所」，
   *   左边批次是自己的、右边团队是别家的人，**两栏对不上却都不报错**。
   * ⚠️ 只在"不在列表里"时才纠正 —— 用户手动切过的选择不能被后续 render 冲掉。
   */
  useEffect(() => {
    if (clinics.length === 0) return;
    if (clinicId != null && clinics.some((c) => c.id === clinicId)) return;
    setClinicId(clinics[0]!.id);
  }, [clinics, clinicId]);

  /**
   * 「分一批新的」两版并存（设计稿 `newBatchMode`，产品要求都实现）。
   * ⚠️ 记在 localStorage：这是**个人偏好**不是业务配置 —— 主管挑顺手的那个用，
   *   ⛔ 别做成后台开关（那意味着全院统一，而这两版本来就是给人选的）。
   */
  const [mode, setMode] = useState<NewBatchMode>('window');
  useEffect(() => {
    const v = localStorage.getItem('pac.newBatchMode');
    if (v === 'arcade' || v === 'window') setMode(v);
  }, []);
  const pickMode = (m: NewBatchMode) => {
    setMode(m);
    localStorage.setItem('pac.newBatchMode', m);
  };

  const [overlay, setOverlay] = useState(false);
  /// 传送门的圆心 = 按钮中心的视口坐标；⛔ 必须在点击那一刻取，浮层开了就量不到了
  const originRef = useRef<{ x: number; y: number } | null>(null);

  return (
    <div className="flex h-screen flex-col overflow-hidden bg-slate-50">
      <SupervisorHeader clinicId={clinicId} onClinicChange={setClinicId} />

      {/* ⚠️ 工具行**靠右** —— 左边那两块面板才是主管进来要看的东西；
          「分一批新的」是他看完之后的动作，摆在左上角会跟「我分的批次」标题抢第一眼。 */}
      <div className="flex flex-none items-center justify-end gap-2 px-3 pt-3 xl:px-4">
        {/* 两版切换 —— 挨着入口放，主管点之前就知道会进哪一版 */}
        <span className="inline-flex rounded-lg bg-slate-100 p-0.5">
          {(
            [
              { m: 'window', label: '样式1' },
              { m: 'arcade', label: '样式2' },
            ] as const
          ).map((o) => (
            <button
              key={o.m}
              type="button"
              onClick={() => pickMode(o.m)}
              className={cn(
                'rounded-md px-2.5 py-1 text-[11.5px] transition-colors',
                mode === o.m
                  ? 'bg-white text-slate-900 shadow-sm'
                  : 'text-slate-500 hover:text-slate-700',
              )}
            >
              {o.label}
            </button>
          ))}
        </span>
        <button
          type="button"
          disabled={!clinicId}
          onClick={(e) => {
            /**
             * 圆心 = **按钮中心**（2026-08-07 产品定：「改成从按钮扩散也行」）。
             *
             * ⚠️ 之前试过用鼠标落点 `clientX/Y`，产品那边连着两轮都说"不在点击处"。
             *   真正的病根不在这儿（是幕布的定位方式，见 new-batch.tsx 的长注释），
             *   但按钮中心**本来就够用**：按钮才 100 出头，误差顶天 50px，
             *   而它是确定的、跟键盘触发也是同一个值 —— 少一条会静默走偏的分支。
             * ⛔ 别再改回 `clientX/Y`：键盘触发时那两个值是 0，
             *   一旦哪天漏了兜底，传送门就从屏幕左上角炸开。
             */
            const r = e.currentTarget.getBoundingClientRect();
            originRef.current = { x: r.left + r.width / 2, y: r.top + r.height / 2 };
            setOverlay(true);
          }}
          className="rounded-lg bg-brand-600 px-3 py-1.5 text-[12.5px] font-medium text-white hover:bg-brand-700 disabled:opacity-40"
        >
          ＋ 分一批新的
        </button>
      </div>

      <div className="flex min-h-0 flex-1 flex-col gap-3 overflow-auto p-3 xl:flex-row xl:overflow-hidden xl:p-4">
        <section className="flex min-h-[26rem] min-w-0 flex-1 xl:min-h-0">
          <BatchTracking clinicId={clinicId} />
        </section>
        {/* ⚠️ 470px（设计稿宽度）装不下「退回率」那一列:
            百分比下面还有「退回 3 / 已处置 3 = 100.0%,另有 65 条没动」——
            两个分母都得给（那是定死的口径），整行就被切掉右半截（实测）。
            ⇒ 放宽到 34rem;⛔ 别为了塞进 470 去砍分母。 */}
        <section className="flex min-h-[24rem] flex-none xl:min-h-0 xl:w-[34rem]">
          <TeamStatus clinicId={clinicId} />
        </section>
      </div>

      {overlay && (
        <NewBatchOverlay
          mode={mode}
          clinicId={clinicId}
          origin={originRef.current}
          onClose={() => setOverlay(false)}
        />
      )}

      {/* 🔴 助手必须挂在这一页上 —— 挑完格子走 `handoff()`，落点就是它。
          ⚠️ 它原本只挂在 `plans/layout`；工作台是**另一条路由**（T16 已改写），
          ⛔ 不挂的话点完格子什么都不会发生，而且不报任何错。 */}
      <AssistantWidget />
    </div>
  );
}
