'use client';

import { useEffect, useState } from 'react';
import { toast } from 'sonner';
import type { MockOrgBrand, MockUser, UserRole } from '@pac/types';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { useAuthStore } from '@/stores/auth-store';
import { getMockOrgs, getMockUsers, mockLogin } from '@/lib/auth-api';
import { cn } from '@/lib/utils';

/**
 * MockLoginDialog — 试部署 / 演示用快速登录(只在 dev 启用)
 *
 * 主路径(有客服名册时):选「角色(权限)」+「具体客服」→ 以该客服真实身份 + 选定 RBAC 权限登录。
 *   - 客服名册来自 GET /auth/mock-users(派生自回访表 · 近 12 月在岗)。
 *   - 两种 role 解耦:客服是"人 + 职能"(都是一线 staff);这里的角色选择是 PAC **权限视角**(staff/leader/admin)。
 *
 * 降级路径(名册拉不到 / mock 关闭):回退到通用网格(2 brand × 3 role 预制身份),保证永远能登录。
 *
 * 不可关闭(open=true 强制保持):未鉴权用户**必须选一个身份**才能进列表页。
 *
 * 集团模型(2026-06):ruier/ruitai 是**品牌(source_unit)**,同属一个集团租户 `ruier-grp`。
 *   登录发的 slug 仍叫 `tenant`(后端 mock API 历史字段名),后端 MOCK_PRESETS 映射为
 *   { tenantId: 'ruier-grp', sourceUnit: '瑞尔'|'瑞泰', clinics, role }。
 *   正式 SSO 对外契约(host_id + group_id + user + org_scope)待 host 接入时实现。
 */

// 品牌 slug(= source_unit);同属集团 ruier-grp。API 字段名仍叫 tenant(后端契约,未改)。
type BrandSlug = 'ruier' | 'ruitai';

const TENANTS: { slug: BrandSlug; nameZh: string; tone: string }[] = [
  { slug: 'ruier', nameZh: '瑞尔', tone: 'border-brand-200 bg-brand-50/40' },
  { slug: 'ruitai', nameZh: '瑞泰', tone: 'border-sky-200 bg-sky-50/40' },
];

const ROLES: { key: UserRole; nameZh: string; desc: string }[] = [
  { key: 'staff', nameZh: '员工', desc: '执行 / 认领 · 工作台默认只看自己名下' },
  { key: 'leader', nameZh: '主管', desc: '可指派 / 回收 · 能看团队全部任务' },
  { key: 'admin', nameZh: '管理员', desc: '全部功能 · 含后台管理' },
];

// 降级网格的演示人名(需与后端 auth.service.MOCK_NAMES 一致)— 话术自报家门会用到
const MOCK_NAMES: Record<BrandSlug, Record<UserRole, string>> = {
  ruier: { staff: '小王', leader: '李莉', admin: '张敏' },
  ruitai: { staff: '小陈', leader: '周琳', admin: '刘洋' },
};

function roleNameZh(role: UserRole): string {
  return ROLES.find((r) => r.key === role)?.nameZh ?? role;
}

export function MockLoginDialog({ open }: { open: boolean }) {
  const setTokens = useAuthStore((s) => s.setTokens);
  const [busy, setBusy] = useState<string | null>(null);
  const [csUsers, setCsUsers] = useState<MockUser[]>([]);
  const [role, setRole] = useState<UserRole>('staff'); // 登录用的 RBAC 权限(默认员工)
  const [tenantFilter, setTenantFilter] = useState<'all' | BrandSlug>('all');
  const [query, setQuery] = useState('');
  /// 宿主 tab —— 两宿主数据完全分开,互不影响(jvs-dw 有客服花名册;friday 只有真实品牌/诊所)
  const [hostTab, setHostTab] = useState<'jvs-dw' | 'friday'>('jvs-dw');
  const [fridayBrands, setFridayBrands] = useState<MockOrgBrand[]>([]);
  const [brandQuery, setBrandQuery] = useState('');

  useEffect(() => {
    getMockUsers()
      .then((r) => setCsUsers(r.users))
      .catch(() => {}); // mock 关闭 / 无文件 → 空 → 走降级网格
  }, []);

  // FRIDAY 真实组织结构(品牌→诊所,派生自摄入数据);切到该 tab 时按需拉
  useEffect(() => {
    if (hostTab !== 'friday' || fridayBrands.length > 0) return;
    getMockOrgs('friday')
      .then((r) => setFridayBrands(r.brands))
      .catch(() => {});
  }, [hostTab, fridayBrands.length]);

  const applyTokens = (r: { accessToken: string; refreshToken: string; expiresIn: number }) =>
    setTokens({ accessToken: r.accessToken, refreshToken: r.refreshToken, expiresIn: r.expiresIn });

  // 主路径:以具体客服真实身份 + 选定角色登录
  const pickCs = async (cs: MockUser) => {
    const key = `cs:${cs.tenant}:${cs.externalId}`;
    if (busy) return;
    setBusy(key);
    try {
      const r = await mockLogin({ tenant: cs.tenant, role, userExternalId: cs.externalId });
      applyTokens(r);
      // 登录成功不弹 toast —— applyTokens 后直接进入应用,页面切换本身即反馈
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error('登录失败', { description: msg.slice(0, 120) });
      setBusy(null);
    }
  };

  // 降级路径:通用预制身份(无名册时)= 品牌级(整个 tenant 品牌全部诊所)
  const pickGeneric = async (tenant: BrandSlug, roleKey: UserRole) => {
    const key = `${tenant}:${roleKey}`;
    if (busy) return;
    setBusy(key);
    try {
      const r = await mockLogin({ tenant, role: roleKey });
      applyTokens(r);
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error('登录失败', { description: msg.slice(0, 120) });
      setBusy(null);
    }
  };

  // 集团级登录:看全部品牌全部诊所(sourceUnits=[] 不限)— 验证数据权限最上一层
  const pickGroup = async (roleKey: UserRole) => {
    const key = `group:${roleKey}`;
    if (busy) return;
    setBusy(key);
    try {
      const r = await mockLogin({ tenant: 'ruier', role: roleKey, orgLevel: 'group' });
      applyTokens(r);
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error('登录失败', { description: msg.slice(0, 120) });
      setBusy(null);
    }
  };

  // 第二宿主 FRIDAY 市场:身份是造的(无花名册),但数据范围落在**真实**品牌/诊所上。
  // orgId 不传 = 集团级(全部品牌全部诊所)。
  const pickFriday = async (roleKey: UserRole, orgId?: string) => {
    const key = `friday:${orgId ?? 'group'}:${roleKey}`;
    if (busy) return;
    setBusy(key);
    try {
      const r = await mockLogin({ tenant: 'friday', role: roleKey, ...(orgId ? { orgId } : {}) });
      applyTokens(r);
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error('登录失败', { description: msg.slice(0, 120) });
      setBusy(null);
    }
  };

  const q = query.trim();
  const filteredCs = csUsers
    .filter((u) => (tenantFilter === 'all' ? true : u.tenant === tenantFilter))
    .filter((u) => (q ? u.name.includes(q) : true))
    .slice(0, 80);

  return (
    <Dialog open={open}>
      <DialogContent
        onEscapeKeyDown={(e) => e.preventDefault()}
        onPointerDownOutside={(e) => e.preventDefault()}
        className="max-w-2xl [&>button[aria-label='Close']]:hidden"
      >
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2">
            <span className="inline-flex h-7 w-7 items-center justify-center rounded-md bg-brand-600 text-[12px] font-bold text-white">
              PAC
            </span>
            <span>快速登录</span>
            <span className="rounded-md bg-amber-100 px-1.5 py-0.5 text-[10.5px] font-medium text-amber-700">
              模拟身份 · 试部署
            </span>
          </DialogTitle>
          <DialogDescription className="text-[12px]">
            生产环境会接宿主 SSO,这里是<strong>开发 / 试部署</strong>的快速通道。
            <br />
            <span className="text-slate-500">
              两件事分开选:<strong>① 角色</strong>=能做什么操作(功能权限);
              <strong>② 选谁 / 哪级</strong>=能看哪些诊所品牌(数据权限,跟角色无关)。
            </span>
          </DialogDescription>
        </DialogHeader>

        {/* 宿主 tab —— 两宿主数据完全隔离(不同 host/tenant/诊所),切换互不影响 */}
        <div className="flex gap-1 border-b">
          {([
            { key: 'jvs-dw' as const, label: '瑞尔集团', sub: 'jvs-dw · 客服花名册' },
            { key: 'friday' as const, label: 'FRIDAY 市场', sub: 'friday · 多品牌 SaaS' },
          ]).map((t) => (
            <button
              key={t.key}
              type="button"
              onClick={() => setHostTab(t.key)}
              className={cn(
                'flex flex-col items-start rounded-t-md px-3 py-1.5 text-left transition-colors',
                hostTab === t.key
                  ? 'border-b-2 border-brand-600 font-semibold text-brand-700'
                  : 'text-slate-500 hover:text-slate-800',
              )}
            >
              <span className="text-[12.5px]">{t.label}</span>
              <span className="text-[10px] font-normal text-slate-400">{t.sub}</span>
            </button>
          ))}
        </div>

        {hostTab === 'friday' ? (
          <FridayPanel
            role={role}
            setRole={setRole}
            brands={fridayBrands}
            query={brandQuery}
            setQuery={setBrandQuery}
            busy={busy}
            onPick={pickFriday}
          />
        ) : csUsers.length > 0 ? (
          <div className="grid gap-3 pt-1">
            {/* ① 登录权限(角色)*/}
            <div>
              <div className="mb-1.5 text-[12px] font-medium text-slate-600">
                ① 角色 · 能做什么(功能权限)
              </div>
              <div className="grid grid-cols-3 gap-2">
                {ROLES.map((r) => (
                  <button
                    key={r.key}
                    type="button"
                    onClick={() => setRole(r.key)}
                    className={cn(
                      'flex flex-col items-start gap-0.5 rounded-md border px-2.5 py-1.5 text-left transition-all',
                      role === r.key
                        ? 'border-brand-400 bg-brand-50/60 ring-1 ring-brand-200'
                        : 'hover:border-brand-300',
                    )}
                  >
                    <span className="text-[12.5px] font-semibold text-slate-800">{r.nameZh}</span>
                    <span className="text-[10px] leading-tight text-slate-500">{r.desc}</span>
                  </button>
                ))}
              </div>
              {/* 数据范围·集团级:全部品牌全部诊所(sourceUnits=[] 不限);角色沿用①所选 */}
              <button
                type="button"
                onClick={() => pickGroup(role)}
                disabled={!!busy}
                className="mt-2 w-full rounded-md border border-dashed border-amber-300 bg-amber-50/40 px-2.5 py-1.5 text-left text-[11.5px] text-amber-800 transition-colors hover:border-amber-400 disabled:opacity-50"
              >
                数据范围 · <strong>集团级</strong> —— 看<strong>全部品牌全部诊所</strong>(跨品牌,最上一层)。角色沿用上方「{roleNameZh(role)}」。
              </button>
            </div>

            {/* ② 选客服 */}
            <div className="rounded-lg border p-3">
              <div className="mb-2 flex items-center justify-between">
                <div className="text-[12px] font-medium text-slate-600">
                  ② 数据范围 · 选客服 = <strong>该客服的诊所</strong>(诊所级)+ 上方「{roleNameZh(role)}」角色
                </div>
                <span className="text-[10.5px] text-slate-500">{csUsers.length} 位在岗 · 近 12 月</span>
              </div>

              <div className="mb-2 flex items-center gap-1.5">
                {([
                  { k: 'all', n: '全部' },
                  { k: 'ruier', n: '瑞尔' },
                  { k: 'ruitai', n: '瑞泰' },
                ] as const).map((t) => (
                  <button
                    key={t.k}
                    type="button"
                    onClick={() => setTenantFilter(t.k)}
                    className={cn(
                      'rounded-full border px-2.5 py-0.5 text-[11px] transition-colors',
                      tenantFilter === t.k
                        ? 'border-brand-400 bg-brand-50 text-brand-700'
                        : 'text-slate-500 hover:border-brand-300',
                    )}
                  >
                    {t.n}
                  </button>
                ))}
                <input
                  value={query}
                  onChange={(e) => setQuery(e.target.value)}
                  placeholder="搜客服姓名…"
                  className="ml-auto w-40 rounded-md border px-2.5 py-1 text-[12px] outline-none focus:border-brand-400"
                />
              </div>

              <div className="max-h-56 space-y-1 overflow-y-auto pr-0.5">
                {filteredCs.map((cs) => {
                  const key = `cs:${cs.tenant}:${cs.externalId}`;
                  const loading = busy === key;
                  const tName = cs.tenant === 'ruier' ? '瑞尔' : '瑞泰';
                  const clinics = cs.clinics.map((c) => c.name).join(' / ');
                  return (
                    <button
                      key={key}
                      type="button"
                      disabled={!!busy}
                      onClick={() => pickCs(cs)}
                      className={cn(
                        'flex w-full items-center justify-between gap-2 rounded-md border px-2.5 py-1.5 text-left transition-all',
                        loading
                          ? 'border-brand-400 ring-2 ring-brand-200'
                          : 'hover:border-brand-400 hover:bg-brand-50/40',
                        busy && !loading && 'opacity-50',
                      )}
                    >
                      <span className="flex shrink-0 items-center gap-1.5">
                        <span className="text-[12.5px] font-semibold text-slate-800">
                          {loading ? '登录中…' : cs.name}
                        </span>
                        <span className="text-[10.5px] text-slate-500">{tName}</span>
                      </span>
                      <span className="truncate text-[10.5px] text-slate-400">{clinics}</span>
                    </button>
                  );
                })}
                {filteredCs.length === 0 && (
                  <div className="px-1 py-2 text-[11px] text-slate-400">无匹配客服</div>
                )}
              </div>
            </div>
          </div>
        ) : (
          // 降级:无客服名册 → 通用网格(保证可登录)
          <div className="grid gap-3 pt-2">
            {TENANTS.map((t) => (
              <div key={t.slug} className={cn('rounded-lg border p-3', t.tone)}>
                <div className="mb-2 flex items-center gap-2 text-[13px] font-semibold text-slate-800">
                  <span>{t.nameZh}</span>
                  <span className="text-[10.5px] font-normal text-slate-500">
                    {t.slug === 'ruier'
                      ? '3 家诊所(杭州大厦/高德 · 北京朝阳)'
                      : '2 家诊所(通善学前街 · 上海世纪公园)'}
                  </span>
                </div>
                <div className="grid gap-2 sm:grid-cols-3">
                  {ROLES.map((r) => {
                    const key = `${t.slug}:${r.key}`;
                    const loading = busy === key;
                    return (
                      <button
                        key={key}
                        type="button"
                        onClick={() => pickGeneric(t.slug, r.key)}
                        disabled={!!busy}
                        className={cn(
                          'group flex flex-col items-start gap-1 rounded-md border bg-white px-3 py-2 text-left transition-all',
                          loading
                            ? 'border-brand-400 ring-2 ring-brand-200'
                            : 'hover:border-brand-400 hover:bg-brand-50/40',
                          busy && !loading && 'opacity-50',
                        )}
                      >
                        <div className="text-[12.5px] font-semibold text-slate-800">
                          {loading ? '登录中…' : `${r.nameZh} · ${MOCK_NAMES[t.slug][r.key]}`}
                        </div>
                        <div className="text-[10.5px] leading-tight text-slate-500">{r.desc}</div>
                      </button>
                    );
                  })}
                </div>
              </div>
            ))}
          </div>
        )}

        <p className="pt-1 text-[10.5px] leading-relaxed text-slate-400">
          提示:登录后 token 写入浏览器 localStorage(2h 有效 · 自动 refresh),
          清浏览器数据或换浏览器会重新弹此对话框。
        </p>
      </DialogContent>
    </Dialog>
  );
}

// ──────────────────────────────────────────────
// FridayPanel — 第二宿主(FRIDAY 市场)登录面板
//
// 与瑞尔集团面板**数据完全隔离**:不同 host / tenant / 品牌 / 诊所,互不影响。
// 身份:FRIDAY 无客服花名册 → 用造的通用身份(FRIDAY 员工/主管/管理员);
// 数据范围:**必须真实** —— 品牌与诊所来自 GET /auth/mock-orgs(org 树派生自摄入数据,
//   名字来自 host.sourceUnitNames / clinicNames,同样派生自摄入源)。
// ──────────────────────────────────────────────
function FridayPanel({
  role,
  setRole,
  brands,
  query,
  setQuery,
  busy,
  onPick,
}: {
  role: UserRole;
  setRole: (r: UserRole) => void;
  brands: MockOrgBrand[];
  query: string;
  setQuery: (v: string) => void;
  busy: string | null;
  onPick: (role: UserRole, orgId?: string) => void;
}) {
  const q = query.trim();
  const filtered = q
    ? brands
        .map((b) => ({
          ...b,
          clinics: b.clinics.filter((c) => c.name.includes(q)),
        }))
        .filter((b) => b.name.includes(q) || b.clinics.length > 0)
    : brands;
  const totalClinics = brands.reduce((n, b) => n + b.clinics.length, 0);

  return (
    <div className="grid gap-3 pt-1">
      {/* ① 角色(功能权限)*/}
      <div>
        <div className="mb-1.5 text-[12px] font-medium text-slate-600">
          ① 角色 · 能做什么(功能权限)
          <span className="ml-1 text-[10.5px] font-normal text-slate-400">
            FRIDAY 无客服花名册,身份用造的;数据范围下方选真实品牌/诊所
          </span>
        </div>
        <div className="grid grid-cols-3 gap-2">
          {ROLES.map((r) => (
            <button
              key={r.key}
              type="button"
              onClick={() => setRole(r.key)}
              className={cn(
                'flex flex-col items-start gap-0.5 rounded-md border px-2.5 py-1.5 text-left transition-all',
                role === r.key
                  ? 'border-brand-400 bg-brand-50/60 ring-1 ring-brand-200'
                  : 'hover:border-brand-300',
              )}
            >
              <span className="text-[12.5px] font-semibold text-slate-800">{r.nameZh}</span>
              <span className="text-[10px] leading-tight text-slate-500">{r.desc}</span>
            </button>
          ))}
        </div>
        {/* 集团级:全部品牌全部诊所 */}
        <button
          type="button"
          onClick={() => onPick(role)}
          disabled={!!busy}
          className="mt-2 w-full rounded-md border border-dashed border-amber-300 bg-amber-50/40 px-2.5 py-1.5 text-left text-[11.5px] text-amber-800 transition-colors hover:border-amber-400 disabled:opacity-50"
        >
          数据范围 · <strong>市场级</strong> —— 看<strong>全部品牌全部诊所</strong>(最上一层)。角色沿用上方「
          {roleNameZh(role)}」。
        </button>
      </div>

      {/* ② 真实品牌 / 诊所 */}
      <div className="rounded-lg border p-3">
        <div className="mb-2 flex items-center justify-between">
          <div className="text-[12px] font-medium text-slate-600">
            ② 数据范围 · 选<strong>品牌</strong>或<strong>诊所</strong>(真实摄入数据)+ 上方「
            {roleNameZh(role)}」角色
          </div>
          <span className="text-[10.5px] text-slate-500">
            {brands.length} 品牌 · {totalClinics} 诊所
          </span>
        </div>
        <input
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="搜品牌 / 诊所名…"
          className="mb-2 h-7 w-full rounded-md border bg-slate-50 px-2 text-[12px] outline-none placeholder:text-slate-400 focus:border-brand-300 focus:bg-white"
        />
        <div className="max-h-[280px] space-y-2 overflow-y-auto">
          {filtered.length === 0 && (
            <div className="py-6 text-center text-[11.5px] text-slate-400">
              {brands.length === 0 ? '组织结构加载中 / 无摄入数据' : '没有匹配的品牌或诊所'}
            </div>
          )}
          {filtered.map((b) => (
            <div key={b.brandId} className="rounded-md border">
              {/* 品牌级:该品牌全部诊所 */}
              <button
                type="button"
                onClick={() => onPick(role, b.brandId)}
                disabled={!!busy}
                className="flex w-full items-center justify-between gap-2 rounded-t-md bg-slate-50/60 px-2.5 py-1.5 text-left transition-colors hover:bg-brand-50/60 disabled:opacity-50"
              >
                <span className="truncate text-[12.5px] font-semibold text-slate-800">{b.name}</span>
                <span className="flex-none text-[10.5px] text-slate-500">
                  品牌级 · {b.clinics.length} 诊所
                </span>
              </button>
              {/* 诊所级 */}
              <div className="flex flex-wrap gap-1 px-2.5 py-1.5">
                {b.clinics.map((c) => (
                  <button
                    key={c.clinicId}
                    type="button"
                    onClick={() => onPick(role, c.clinicId)}
                    disabled={!!busy}
                    className="rounded-full border px-2 py-0.5 text-[11px] text-slate-600 transition-colors hover:border-brand-300 hover:bg-brand-50 hover:text-brand-700 disabled:opacity-50"
                  >
                    {c.name}
                  </button>
                ))}
                {b.clinics.length === 0 && (
                  <span className="text-[10.5px] text-slate-400">该品牌暂无诊所数据</span>
                )}
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}
