/* ===== pages-master.jsx — suppliers & customers ===== */
(function () {
  const { Icon, Button, IconBtn, Card, Badge, EmptyState, Input, Field, Textarea, Table,
    Tabs, useStore, navigate, useRoute, cls, fmtDate, fmtRel } = window;

  /* =========================================================
     Generic List Layout: search + filter sidebar + table
  ========================================================= */
  function ListShell({
    mobile, title, hint, items, columns, onRow, primaryAction,
    filters, searchPlaceholder, mobileItem, searchKeys, archivedKey = 'archived',
    rightPanel, defaultSort,
  }) {
    const [q, setQ] = React.useState('');
    const [showArchived, setShowArchived] = React.useState(false);
    const [filterValues, setFilterValues] = React.useState({});
    const [sort, setSort] = React.useState(defaultSort || null);
    const [showFilter, setShowFilter] = React.useState(!mobile);

    let rows = items;
    if (!showArchived) rows = rows.filter((r) => !r[archivedKey]);
    if (q) {
      const ql = q.toLowerCase();
      rows = rows.filter((r) => searchKeys.some((k) => (r[k] || '').toLowerCase().includes(ql)));
    }
    for (const f of filters || []) {
      const v = filterValues[f.id];
      if (v) rows = rows.filter((r) => f.predicate(r, v));
    }
    if (sort) rows = [...rows].sort((a, b) => {
      const av = a[sort.key], bv = b[sort.key];
      if (av == null) return 1; if (bv == null) return -1;
      return sort.dir === 'asc' ? (av > bv ? 1 : -1) : (av < bv ? 1 : -1);
    });

    return (
      <div className={cls('flex flex-col h-full', mobile ? '' : '')}>
        {/* Header */}
        <div className={cls('px-6 pt-6 pb-4 border-b border-ink-100 bg-white',
          mobile && 'px-3 pt-3 pb-2')}>
          <div className="flex items-start justify-between gap-3 mb-3">
            <div>
              <h1 className={cls('font-semibold tracking-tight text-ink-900',
                mobile ? 'text-lg' : 'text-xl')}>{title}</h1>
              {hint && <p className="text-xs text-ink-500 mt-0.5">{hint}</p>}
            </div>
            {primaryAction}
          </div>
          <div className="flex items-center gap-2">
            <div className="flex-1 max-w-md">
              <Input leadingIcon={Icon.search} value={q}
                onChange={(e) => setQ(e.target.value)}
                placeholder={searchPlaceholder || '搜索…'} />
            </div>
            {!mobile && filters && (
              <button onClick={() => setShowFilter((s) => !s)}
                className={cls('h-9 px-3 inline-flex items-center gap-1.5 text-sm rounded-lg ring-1 transition-colors',
                  showFilter ? 'bg-ink-900 text-white ring-ink-900' : 'text-ink-700 bg-white ring-ink-200 hover:bg-ink-50')}>
                <Icon.filter size={14} /> 筛选
                {Object.values(filterValues).filter(Boolean).length > 0 && (
                  <span className="bg-emerald-500 text-white text-[10px] rounded-full h-4 min-w-[16px] px-1 inline-flex items-center justify-center">{Object.values(filterValues).filter(Boolean).length}</span>
                )}
              </button>
            )}
            <label className="hidden md:flex items-center gap-1.5 text-xs text-ink-600 ml-2">
              <input type="checkbox" checked={showArchived}
                onChange={(e) => setShowArchived(e.target.checked)}
                className="rounded ring-1 ring-ink-300" />
              显示归档
            </label>
            {mobile && (
              <IconBtn icon={Icon.filter} label="筛选" variant="outline" onClick={() => setShowFilter(true)} />
            )}
          </div>
        </div>

        {/* Body */}
        <div className="flex-1 flex min-h-0 overflow-hidden">
          {/* Filter sidebar — desktop */}
          {!mobile && showFilter && filters && (
            <aside className="w-56 shrink-0 bg-ink-50/40 border-r border-ink-100 p-4 overflow-y-auto">
              <div className="text-[10px] uppercase tracking-wider text-ink-500 mb-3 flex items-center justify-between">
                筛选
                {Object.values(filterValues).filter(Boolean).length > 0 && (
                  <button className="normal-case tracking-normal text-[11px] text-ink-700 hover:text-ink-900"
                    onClick={() => setFilterValues({})}>清除</button>
                )}
              </div>
              <div className="flex flex-col gap-5">
                {filters.map((f) => (
                  <FilterGroup key={f.id} filter={f}
                    value={filterValues[f.id]}
                    onChange={(v) => setFilterValues({ ...filterValues, [f.id]: v })} />
                ))}
              </div>
            </aside>
          )}

          {/* List */}
          <div className="flex-1 min-w-0 overflow-y-auto">
            {rows.length === 0 ? (
              <EmptyState title="无匹配结果" hint={q ? `搜索 "${q}" 无结果` : '调整筛选或清除搜索条件'}
                action={q && <Button size="sm" variant="secondary" onClick={() => setQ('')}>清除搜索</Button>} />
            ) : mobile ? (
              <ul className="divide-y divide-ink-100 bg-white">
                {rows.map((r) => mobileItem ? mobileItem(r) :
                  <li key={r.id} onClick={() => onRow?.(r)}
                    className="px-3 py-3 flex items-center gap-3 active:bg-ink-50">
                    <div className="flex-1 min-w-0">
                      <div className="text-sm font-medium truncate">{r.name || r.label}</div>
                      <div className="text-xs text-ink-500 truncate">{r.sub || ''}</div>
                    </div>
                    <Icon.chevRight size={14} className="text-ink-300" />
                  </li>
                )}
              </ul>
            ) : (
              <Table columns={columns} rows={rows} onRow={onRow} />
            )}
          </div>

          {/* Right panel — optional */}
          {!mobile && rightPanel && (
            <aside className="w-72 shrink-0 border-l border-ink-100 bg-ink-50/30 overflow-y-auto">
              {rightPanel}
            </aside>
          )}
        </div>
      </div>
    );
  }

  function FilterGroup({ filter, value, onChange }) {
    return (
      <div>
        <div className="text-xs font-medium text-ink-800 mb-1.5">{filter.label}</div>
        <div className="flex flex-col gap-1">
          {filter.options.map((opt) => (
            <label key={opt.value}
              className={cls('flex items-center gap-2 text-sm px-2 py-1 rounded-md cursor-pointer hover:bg-ink-100',
                value === opt.value && 'bg-ink-100')}>
              <input type="radio" name={filter.id}
                checked={value === opt.value}
                onChange={() => onChange(value === opt.value ? null : opt.value)} />
              <span className="flex-1">{opt.label}</span>
              {opt.count != null && <span className="text-[10px] text-ink-400 font-mono">{opt.count}</span>}
            </label>
          ))}
        </div>
      </div>
    );
  }

  /* =========================================================
     Suppliers list
  ========================================================= */
  function SuppliersPage({ mobile }) {
    const store = useStore();
    const { suppliers, reagent_products, device_products } = store;

    // counts of products per supplier
    const counts = React.useMemo(() => {
      const m = new Map();
      for (const r of reagent_products) m.set(r.supplier_id, (m.get(r.supplier_id) || 0) + 1);
      for (const d of device_products) m.set(d.supplier_id, (m.get(d.supplier_id) || 0) + 1);
      return m;
    }, [reagent_products, device_products]);

    const columns = [
      { header: '供货商', cell: (r) => (
        <div className="flex items-center gap-3">
          <span className="h-8 w-8 rounded-md bg-ink-100 text-ink-700 inline-flex items-center justify-center font-medium text-xs">
            {r.short?.slice(0,2)}
          </span>
          <div className="min-w-0">
            <div className="text-sm font-medium text-ink-900 truncate">{r.name}</div>
            <div className="text-xs text-ink-500 truncate font-mono">{r.vat}</div>
          </div>
        </div>
      )},
      { header: '所在地',  cell: (r) => <span className="text-sm text-ink-700">{r.country} · {r.city}</span> },
      { header: '联系人',  cell: (r) => (
        <div className="min-w-0">
          <div className="text-sm">{r.contact}</div>
          <div className="text-xs text-ink-500 truncate">{r.email}</div>
        </div>
      )},
      { header: 'SKU 数', align: 'right', cell: (r) => (
        <span className="font-mono text-sm tabular-nums">{counts.get(r.id) || 0}</span>
      )},
      { header: '付款',   cell: (r) => <Badge tone="neutral">{r.payment_terms}</Badge> },
      { header: '标签',   cell: (r) => (
        <div className="flex flex-wrap gap-1">
          {(r.tags || []).map((t) => <Badge key={t} tone="neutral">{t}</Badge>)}
        </div>
      )},
      { header: '', width: 36, cell: (r) => r.archived ? <Badge tone="zinc" className="opacity-70">已归档</Badge> : <Icon.chevRight size={14} className="text-ink-300" /> },
    ];

    return (
      <ListShell
        mobile={mobile}
        title="供货商"
        hint={`${suppliers.filter(s=>!s.archived).length} 家活跃 · ${suppliers.filter(s=>s.archived).length} 家归档`}
        items={suppliers}
        searchPlaceholder="搜索供货商、VAT、联系人…"
        searchKeys={['name','short','contact','vat','city','email']}
        columns={columns}
        onRow={(r) => navigate(`#/suppliers/${r.id}`)}
        primaryAction={<Button size="sm" icon={Icon.plus} onClick={() => navigate('#/suppliers/new')}>新建供货商</Button>}
        mobileItem={(r) => (
          <li key={r.id} onClick={() => navigate(`#/suppliers/${r.id}`)}
            className="px-3 py-3 flex items-start gap-3 active:bg-ink-50">
            <span className="h-9 w-9 rounded-md bg-ink-100 text-ink-700 inline-flex items-center justify-center font-medium text-xs shrink-0">{r.short?.slice(0,2)}</span>
            <div className="flex-1 min-w-0 leading-tight">
              <div className="text-sm font-medium truncate">{r.name}</div>
              <div className="text-xs text-ink-500 truncate mt-0.5">{r.contact} · {r.city}</div>
              <div className="flex flex-wrap gap-1 mt-1">
                {(r.tags || []).map((t) => <Badge key={t} tone="neutral">{t}</Badge>)}
              </div>
            </div>
            <Icon.chevRight size={14} className="text-ink-300 shrink-0 mt-1" />
          </li>
        )}
        filters={[
          { id: 'country', label: '国家', options: [{ value: 'IT', label: 'Italia', count: suppliers.filter(s=>s.country==='IT').length }], predicate: (r,v) => r.country === v },
          { id: 'tag', label: '类型', options: [
            { value: 'reagent', label: '试剂', count: suppliers.filter(s=>s.tags?.includes('reagent')).length },
            { value: 'device',  label: '设备', count: suppliers.filter(s=>s.tags?.includes('device')).length },
          ], predicate: (r,v) => r.tags?.includes(v) },
        ]}
      />
    );
  }

  /* ---------- Supplier detail ---------- */
  function SupplierDetail({ id, mobile }) {
    const store = useStore();
    const r = store.suppliers.find((x) => x.id === id);
    const [tab, setTab] = React.useState('overview');
    if (!r) return <EmptyState title="未找到该供货商" />;

    const products = [
      ...store.reagent_products.filter((p) => p.supplier_id === id).map(p => ({ ...p, kind: 'reagent' })),
      ...store.device_products.filter((p) => p.supplier_id === id).map(p => ({ ...p, kind: 'device' })),
    ];

    return (
      <div className={cls(mobile ? 'p-3' : '')}>
        <div className={cls('bg-white border-b border-ink-100', mobile ? 'p-3 -mx-3 -mt-3 mb-3 px-3' : 'p-6')}>
          <div className="flex items-center gap-2 text-xs text-ink-500 mb-2">
            <button onClick={() => navigate('#/suppliers')} className="hover:text-ink-900">供货商</button>
            <Icon.chevRight size={11} />
            <span className="text-ink-900 truncate">{r.name}</span>
          </div>
          <div className={cls('flex items-start justify-between gap-3', mobile && 'flex-col')}>
            <div className="flex items-center gap-3 min-w-0">
              <span className="h-12 w-12 rounded-lg bg-ink-100 text-ink-800 inline-flex items-center justify-center font-semibold">
                {r.short?.slice(0,2)}
              </span>
              <div className="min-w-0">
                <h1 className="text-xl font-semibold tracking-tight truncate">{r.name}</h1>
                <div className="text-xs text-ink-500 mt-0.5 flex items-center flex-wrap gap-x-3 gap-y-0.5">
                  <span className="font-mono">{r.vat}</span>
                  <span>·</span><span>{r.country} {r.city}</span>
                  <span>·</span><span>{r.payment_terms}</span>
                  {r.archived && <Badge tone="zinc">已归档</Badge>}
                </div>
              </div>
            </div>
            <div className="flex items-center gap-2 shrink-0">
              <Button variant="secondary" size="sm" icon={Icon.edit}>编辑</Button>
              <Button variant="secondary" size="sm" icon={Icon.archive}>归档</Button>
            </div>
          </div>
          <div className="mt-4">
            <Tabs tabs={[
              { id: 'overview', label: '概览' },
              { id: 'products', label: '产品', count: products.length },
              { id: 'activity', label: '活动' },
            ]} active={tab} onChange={setTab} />
          </div>
        </div>

        <div className={cls(mobile ? '' : 'p-6')}>
          {tab === 'overview' && (
            <div className={cls('grid gap-4', mobile ? 'grid-cols-1' : 'grid-cols-3')}>
              <Card className="p-5 col-span-2">
                <h3 className="text-sm font-semibold mb-3">联系信息</h3>
                <dl className="grid grid-cols-2 gap-x-6 gap-y-3 text-sm">
                  <KV label="联系人" v={r.contact} />
                  <KV label="邮箱" v={<a className="text-blue-600 hover:underline">{r.email}</a>} />
                  <KV label="电话" v={<span className="font-mono">{r.phone}</span>} />
                  <KV label="付款条件" v={r.payment_terms} />
                  <KV label="国家 / 城市" v={`${r.country} · ${r.city}`} />
                  <KV label="增值税号" v={<span className="font-mono">{r.vat}</span>} />
                </dl>
                <div className="mt-5 pt-4 border-t border-ink-100">
                  <div className="text-[10px] uppercase tracking-wider text-ink-400 mb-1.5">标签</div>
                  <div className="flex flex-wrap gap-1.5">
                    {(r.tags || []).map((t) => <Badge key={t} tone="neutral">{t}</Badge>)}
                  </div>
                </div>
              </Card>
              <Card className="p-5">
                <h3 className="text-sm font-semibold mb-3">统计</h3>
                <div className="grid grid-cols-2 gap-3">
                  <Stat label="试剂 SKU" value={products.filter(p=>p.kind==='reagent').length} />
                  <Stat label="设备型号" value={products.filter(p=>p.kind==='device').length} />
                  <Stat label="在库批次" value={store.reagent_batches.filter(b => b.supplier_id === id).length} />
                  <Stat label="设备 SN" value={store.device_units.filter(u => products.some(p => p.id === u.product_id)).length} />
                </div>
                <div className="mt-5 pt-4 border-t border-ink-100 text-[11px] text-ink-500">
                  创建于 {fmtDate(r.created)} · {fmtRel(r.created)}
                </div>
              </Card>
            </div>
          )}

          {tab === 'products' && (
            <Card className="overflow-hidden">
              <Table
                columns={[
                  { header: '产品', cell: (p) => (
                    <div className="flex items-center gap-2">
                      <span className={cls('h-7 w-7 rounded-md inline-flex items-center justify-center',
                        p.kind === 'reagent' ? 'bg-amber-100 text-amber-700' : 'bg-sky-100 text-sky-700')}>
                        {p.kind === 'reagent' ? <Icon.flask size={13} /> : <Icon.cpu size={13} />}
                      </span>
                      <span className="text-sm font-medium">{p.name}</span>
                    </div>
                  )},
                  { header: '代码', cell: (p) => <span className="font-mono text-xs text-ink-500">{p.code || p.model}</span> },
                  { header: '类型', cell: (p) => <Badge tone={p.kind === 'reagent' ? 'amber' : 'sky'}>{p.kind === 'reagent' ? '试剂' : '设备'}</Badge> },
                ]}
                rows={products}
                onRow={(p) => navigate(p.kind === 'reagent' ? '#/reagents/products' : '#/devices/products')}
              />
            </Card>
          )}

          {tab === 'activity' && (
            <Card className="p-8 text-center text-sm text-ink-500">暂无活动</Card>
          )}
        </div>
      </div>
    );
  }

  function KV({ label, v }) {
    return (
      <div>
        <dt className="text-[11px] uppercase tracking-wider text-ink-400">{label}</dt>
        <dd className="text-ink-900 mt-0.5">{v || '—'}</dd>
      </div>
    );
  }
  function Stat({ label, value }) {
    return (
      <div>
        <div className="text-[11px] uppercase tracking-wider text-ink-400">{label}</div>
        <div className="text-2xl font-semibold mt-0.5 tabular-nums font-mono">{value}</div>
      </div>
    );
  }

  /* ---------- New supplier form ---------- */
  function SupplierNew({ mobile, presetName, onCreated, onCancel, isModal }) {
    const store = useStore();
    const [form, setForm] = React.useState({
      name: presetName || '', short: '', country: 'IT', city: '', contact: '', email: '', phone: '',
      vat: '', payment_terms: 'Net 30', tags: [], notes: ''
    });
    const [saveAndNew, setSaveAndNew] = React.useState(false);
    const ok = form.name && form.contact;
    const handle = (k) => (e) => setForm({ ...form, [k]: e.target.value });
    const submit = (next) => {
      if (!ok) return;
      const id = window.nextId('s');
      const row = { id, ...form, archived: false, created: '2026-05-28' };
      store.add('suppliers', row);
      store.toast(`已新建供货商「${form.name}」`);
      store.logActivity({ kind: 'edit', text: `新建供货商 ${form.name}`, ref: id });
      if (onCreated) onCreated(row);
      else if (next) setForm({ ...form, name: '', vat: '', contact: '', email: '', phone: '' });
      else navigate(`#/suppliers/${id}`);
    };

    return (
      <FormShell
        mobile={mobile}
        title={isModal ? '即时新建供货商' : '新建供货商'}
        hint={isModal ? '保存后将自动填入主表单' : '常用于试剂厂家与设备厂家维护'}
        crumb={isModal ? null : [{ label: '供货商', to: '#/suppliers' }, { label: '新建' }]}
        actions={!isModal && (
          <>
            <Button variant="ghost" size="sm" onClick={() => navigate('#/suppliers')}>取消</Button>
            <Button variant="secondary" size="sm" disabled={!ok} onClick={() => submit(true)}>保存并新建下一条</Button>
            <Button size="sm" disabled={!ok} onClick={() => submit(false)} icon={Icon.check}>保存</Button>
          </>
        )}>
        <div className={cls('grid gap-x-4 gap-y-4', mobile ? 'grid-cols-1' : 'grid-cols-2')}>
          <Field label="公司全名" required>
            <Input value={form.name} onChange={handle('name')} placeholder="例：Merck Italia (Sigma-Aldrich)" required={!form.name} />
          </Field>
          <Field label="简称" hint="用于标签 / 列表展示">
            <Input value={form.short} onChange={handle('short')} placeholder="Merck" />
          </Field>
          <Field label="国家">
            <Input value={form.country} onChange={handle('country')} placeholder="IT" />
          </Field>
          <Field label="城市">
            <Input value={form.city} onChange={handle('city')} placeholder="Milano" />
          </Field>
          <Field label="增值税号 (VAT)">
            <Input value={form.vat} onChange={handle('vat')} placeholder="ITxxxxxxxxxxx" />
          </Field>
          <Field label="付款条件">
            <Input value={form.payment_terms} onChange={handle('payment_terms')} placeholder="Net 30" />
          </Field>
          <Field label="联系人" required>
            <Input value={form.contact} onChange={handle('contact')} placeholder="Andrea Pellegrini" required={!form.contact} />
          </Field>
          <Field label="邮箱">
            <Input value={form.email} onChange={handle('email')} placeholder="a@merckgroup.com" />
          </Field>
          <Field label="电话">
            <Input value={form.phone} onChange={handle('phone')} placeholder="+39 ..." />
          </Field>
          <Field label="标签" hint="逗号分隔">
            <Input value={form.tags.join(',')} onChange={(e) => setForm({...form, tags: e.target.value.split(',').map(s=>s.trim()).filter(Boolean)})}
              placeholder="reagent, antibody" />
          </Field>
          <Field label="备注" className="col-span-2">
            <Textarea value={form.notes} onChange={handle('notes')} placeholder="可选 — 内部备注" rows={3} />
          </Field>
        </div>

        {isModal && (
          <div className="mt-5 pt-4 border-t border-ink-100 flex justify-end gap-2">
            <Button variant="ghost" size="sm" onClick={onCancel}>取消</Button>
            <Button size="sm" disabled={!ok} onClick={() => submit(false)} icon={Icon.check}>保存并填入</Button>
          </div>
        )}
      </FormShell>
    );
  }

  /* =========================================================
     Customers (mirrors suppliers)
  ========================================================= */
  function CustomersPage({ mobile }) {
    const store = useStore();
    const { customers } = store;

    const columns = [
      { header: '客户', cell: (r) => (
        <div className="flex items-center gap-3">
          <span className="h-8 w-8 rounded-md bg-emerald-50 text-emerald-700 inline-flex items-center justify-center font-medium text-xs">
            {r.short?.slice(0,2)}
          </span>
          <div className="min-w-0">
            <div className="text-sm font-medium truncate">{r.name}</div>
            <div className="text-xs text-ink-500 truncate font-mono">{r.vat}</div>
          </div>
        </div>
      )},
      { header: '所在地', cell: (r) => <span className="text-sm text-ink-700">{r.country} · {r.city}</span> },
      { header: '联系人', cell: (r) => (
        <div className="min-w-0">
          <div className="text-sm">{r.contact}</div>
          <div className="text-xs text-ink-500 truncate">{r.email}</div>
        </div>
      )},
      { header: '在借设备', align: 'right', cell: (r) => {
        const n = store.device_units.filter(u => u.cur_holder?.kind === 'customer' && u.cur_holder.id === r.id).length;
        return <span className="font-mono text-sm tabular-nums">{n}</span>;
      }},
      { header: '在借试剂', align: 'right', cell: (r) => {
        const n = store.reagent_outflows.filter(o => o.customer_id === r.id && !o.returned_at).length;
        return <span className="font-mono text-sm tabular-nums">{n}</span>;
      }},
      { header: '标签', cell: (r) => (
        <div className="flex flex-wrap gap-1">{(r.tags || []).map((t) => <Badge key={t} tone="neutral">{t}</Badge>)}</div>
      )},
      { header: '', width: 36, cell: (r) => r.archived ? <Badge tone="zinc">归档</Badge> : <Icon.chevRight size={14} className="text-ink-300" /> },
    ];

    return (
      <ListShell
        mobile={mobile}
        title="客户"
        hint={`${customers.filter(s=>!s.archived).length} 家活跃 · 实验室 / 医院 / 大学`}
        items={customers}
        searchPlaceholder="搜索客户、VAT、联系人…"
        searchKeys={['name','short','contact','vat','city','email']}
        columns={columns}
        onRow={(r) => navigate(`#/customers/${r.id}`)}
        primaryAction={<Button size="sm" icon={Icon.plus} onClick={() => navigate('#/customers/new')}>新建客户</Button>}
        mobileItem={(r) => (
          <li key={r.id} onClick={() => navigate(`#/customers/${r.id}`)}
            className="px-3 py-3 flex items-start gap-3 active:bg-ink-50">
            <span className="h-9 w-9 rounded-md bg-emerald-50 text-emerald-700 inline-flex items-center justify-center font-medium text-xs shrink-0">{r.short?.slice(0,2)}</span>
            <div className="flex-1 min-w-0 leading-tight">
              <div className="text-sm font-medium truncate">{r.name}</div>
              <div className="text-xs text-ink-500 truncate mt-0.5">{r.contact} · {r.city}</div>
            </div>
            <Icon.chevRight size={14} className="text-ink-300 shrink-0 mt-1" />
          </li>
        )}
        filters={[
          { id: 'tag', label: '类型', options: [
            { value: 'ospedale',    label: '医院',     count: customers.filter(c=>c.tags?.includes('ospedale')).length },
            { value: 'ricerca',     label: '研究所',   count: customers.filter(c=>c.tags?.includes('ricerca')).length },
            { value: 'università',  label: '大学',     count: customers.filter(c=>c.tags?.includes('università')).length },
            { value: 'privato',     label: '私立',     count: customers.filter(c=>c.tags?.includes('privato')).length },
            { value: 'diagnostica', label: '诊断中心', count: customers.filter(c=>c.tags?.includes('diagnostica')).length },
          ], predicate: (r,v) => r.tags?.includes(v) },
        ]}
      />
    );
  }

  function CustomerDetail({ id, mobile }) {
    const store = useStore();
    const c = store.customers.find((x) => x.id === id);
    const [tab, setTab] = React.useState('overview');
    if (!c) return <EmptyState title="未找到该客户" />;

    const devicesAtCustomer = store.device_units.filter(u => u.cur_holder?.kind === 'customer' && u.cur_holder.id === id);
    const activeOutflows = store.reagent_outflows.filter(o => o.customer_id === id && !o.returned_at);
    const allOutflows = store.reagent_outflows.filter(o => o.customer_id === id);

    return (
      <div className="">
        <div className={cls('bg-white border-b border-ink-100', mobile ? 'p-3' : 'p-6')}>
          <div className="flex items-center gap-2 text-xs text-ink-500 mb-2">
            <button onClick={() => navigate('#/customers')} className="hover:text-ink-900">客户</button>
            <Icon.chevRight size={11} />
            <span className="text-ink-900 truncate">{c.name}</span>
          </div>
          <div className={cls('flex items-start justify-between gap-3', mobile && 'flex-col')}>
            <div className="flex items-center gap-3 min-w-0">
              <span className="h-12 w-12 rounded-lg bg-emerald-100 text-emerald-700 inline-flex items-center justify-center font-semibold">
                {c.short?.slice(0,2)}
              </span>
              <div className="min-w-0">
                <h1 className="text-xl font-semibold tracking-tight truncate">{c.name}</h1>
                <div className="text-xs text-ink-500 mt-0.5 flex items-center flex-wrap gap-x-3 gap-y-0.5">
                  <span className="font-mono">{c.vat}</span>
                  <span>·</span><span>{c.country} {c.city}</span>
                  {c.tags?.map(t => <Badge key={t} tone="neutral">{t}</Badge>)}
                </div>
              </div>
            </div>
            <div className="flex items-center gap-2 shrink-0">
              <Button variant="secondary" size="sm" icon={Icon.truck} onClick={() => navigate('#/devices/transfer/new?to=' + id)}>转移设备至此</Button>
              <Button variant="secondary" size="sm" icon={Icon.arrowR} onClick={() => navigate('#/reagents/outflow/new?to=' + id)}>取货至此</Button>
              <Button variant="secondary" size="sm" icon={Icon.edit}>编辑</Button>
            </div>
          </div>
          <div className="mt-4">
            <Tabs tabs={[
              { id: 'overview', label: '概览' },
              { id: 'devices', label: '在借设备', count: devicesAtCustomer.length },
              { id: 'reagents', label: '试剂记录', count: allOutflows.length },
            ]} active={tab} onChange={setTab} />
          </div>
        </div>

        <div className={cls(mobile ? 'p-3' : 'p-6')}>
          {tab === 'overview' && (
            <div className={cls('grid gap-4', mobile ? 'grid-cols-1' : 'grid-cols-3')}>
              <Card className="p-5 col-span-2">
                <h3 className="text-sm font-semibold mb-3">联系信息</h3>
                <dl className="grid grid-cols-2 gap-x-6 gap-y-3 text-sm">
                  <KV label="联系人" v={c.contact} />
                  <KV label="邮箱" v={<a className="text-blue-600 hover:underline">{c.email}</a>} />
                  <KV label="电话" v={<span className="font-mono">{c.phone}</span>} />
                  <KV label="增值税号" v={<span className="font-mono">{c.vat}</span>} />
                </dl>
              </Card>
              <Card className="p-5">
                <h3 className="text-sm font-semibold mb-3">当前持有</h3>
                <div className="grid grid-cols-2 gap-3">
                  <Stat label="在借设备" value={devicesAtCustomer.length} />
                  <Stat label="未还试剂" value={activeOutflows.length} />
                </div>
              </Card>
            </div>
          )}
          {tab === 'devices' && (
            <Card className="overflow-hidden">
              {devicesAtCustomer.length === 0 ? <EmptyState title="此客户当前无在借设备" /> :
                <Table
                  columns={[
                    { header: 'SN', cell: (u) => <span className="font-mono text-sm">{u.sn || '(缺失)'}</span> },
                    { header: '设备型号', cell: (u) => store.device_products.find(p=>p.id===u.product_id)?.name },
                    { header: '状态', cell: (u) => <Badge tone={u.status === 'FAULT' ? 'rose' : 'neutral'}>{u.status}</Badge> },
                  ]}
                  rows={devicesAtCustomer}
                  onRow={(u) => navigate(`#/devices/units/${u.id}`)}
                />}
            </Card>
          )}
          {tab === 'reagents' && (
            <Card className="overflow-hidden">
              {allOutflows.length === 0 ? <EmptyState title="无取货记录" /> :
                <Table
                  columns={[
                    { header: '日期', cell: (o) => <span className="font-mono text-xs">{fmtDate(o.taken_at)}</span> },
                    { header: '产品', cell: (o) => {
                      const b = store.reagent_batches.find(b => b.id === o.batch_id);
                      const p = store.reagent_products.find(p => p.id === b?.product_id);
                      return <div><div className="text-sm">{p?.name}</div><div className="text-xs text-ink-500 font-mono">批 {b?.lot}</div></div>;
                    }},
                    { header: '取出', cell: (o) => <span className="text-sm">{window.fmtQty(o.taken_boxes, o.taken_atoms)}</span> },
                    { header: '应还 / 已还', cell: (o) => o.returned_at
                      ? <Badge tone="green">已归还 · {fmtDate(o.returned_at)}</Badge>
                      : <span className="text-xs">{fmtDate(o.due_at)} <span className="text-ink-400">({fmtRel(o.due_at)})</span></span>
                    },
                  ]}
                  rows={allOutflows}
                />}
            </Card>
          )}
        </div>
      </div>
    );
  }

  function CustomerNew({ mobile, presetName, onCreated, onCancel, isModal }) {
    const store = useStore();
    const [form, setForm] = React.useState({
      name: presetName || '', short: '', country: 'IT', city: '', contact: '', email: '', phone: '', vat: '', tags: [], notes: ''
    });
    const handle = (k) => (e) => setForm({ ...form, [k]: e.target.value });
    const ok = form.name && form.contact;
    const submit = (next) => {
      if (!ok) return;
      const id = window.nextId('c');
      const row = { id, ...form, archived: false, created: '2026-05-28' };
      store.add('customers', row);
      store.toast(`已新建客户「${form.name}」`);
      store.logActivity({ kind: 'edit', text: `新建客户 ${form.name}`, ref: id });
      if (onCreated) onCreated(row);
      else if (next) setForm({ name: '', short: '', country: 'IT', city: '', contact: '', email: '', phone: '', vat: '', tags: [], notes: '' });
      else navigate(`#/customers/${id}`);
    };

    return (
      <FormShell
        mobile={mobile}
        title={isModal ? '即时新建客户' : '新建客户'}
        crumb={isModal ? null : [{ label: '客户', to: '#/customers' }, { label: '新建' }]}
        actions={!isModal && (
          <>
            <Button variant="ghost" size="sm" onClick={() => navigate('#/customers')}>取消</Button>
            <Button variant="secondary" size="sm" disabled={!ok} onClick={() => submit(true)}>保存并新建下一条</Button>
            <Button size="sm" disabled={!ok} onClick={() => submit(false)} icon={Icon.check}>保存</Button>
          </>
        )}>
        <div className={cls('grid gap-x-4 gap-y-4', mobile ? 'grid-cols-1' : 'grid-cols-2')}>
          <Field label="客户全名" required>
            <Input value={form.name} onChange={handle('name')} required={!form.name} placeholder="例：Ospedale San Raffaele" />
          </Field>
          <Field label="简称">
            <Input value={form.short} onChange={handle('short')} placeholder="San Raffaele" />
          </Field>
          <Field label="国家"><Input value={form.country} onChange={handle('country')} /></Field>
          <Field label="城市"><Input value={form.city} onChange={handle('city')} placeholder="Milano" /></Field>
          <Field label="增值税号"><Input value={form.vat} onChange={handle('vat')} placeholder="ITxxx" /></Field>
          <Field label="标签" hint="逗号分隔"><Input value={form.tags.join(',')} onChange={(e) => setForm({...form, tags: e.target.value.split(',').map(s=>s.trim()).filter(Boolean)})} placeholder="ospedale, ricerca" /></Field>
          <Field label="联系人" required><Input value={form.contact} onChange={handle('contact')} required={!form.contact} /></Field>
          <Field label="邮箱"><Input value={form.email} onChange={handle('email')} /></Field>
          <Field label="电话"><Input value={form.phone} onChange={handle('phone')} /></Field>
          <Field label="备注" className="col-span-2"><Textarea value={form.notes} onChange={handle('notes')} rows={3} /></Field>
        </div>
        {isModal && (
          <div className="mt-5 pt-4 border-t border-ink-100 flex justify-end gap-2">
            <Button variant="ghost" size="sm" onClick={onCancel}>取消</Button>
            <Button size="sm" disabled={!ok} onClick={() => submit(false)} icon={Icon.check}>保存并填入</Button>
          </div>
        )}
      </FormShell>
    );
  }

  /* ---------- FormShell (shared) ---------- */
  function FormShell({ title, hint, crumb, actions, children, mobile }) {
    return (
      <div className="">
        {crumb && (
          <div className={cls('bg-white border-b border-ink-100', mobile ? 'p-3' : 'p-6 pb-4')}>
            <div className="flex items-center gap-2 text-xs text-ink-500 mb-2">
              {crumb.map((c, i) => (
                <React.Fragment key={i}>
                  {i > 0 && <Icon.chevRight size={11} />}
                  {c.to ? (
                    <button onClick={() => navigate(c.to)} className="hover:text-ink-900">{c.label}</button>
                  ) : (
                    <span className="text-ink-900">{c.label}</span>
                  )}
                </React.Fragment>
              ))}
            </div>
            <div className="flex items-start justify-between gap-3">
              <div>
                <h1 className={cls('font-semibold tracking-tight', mobile ? 'text-lg' : 'text-xl')}>{title}</h1>
                {hint && <p className="text-xs text-ink-500 mt-1">{hint}</p>}
              </div>
              <div className="flex items-center gap-2 shrink-0">{actions}</div>
            </div>
          </div>
        )}
        <div className={cls(mobile ? 'p-3' : 'p-6')}>
          {!crumb && (
            <div className="flex items-start justify-between gap-3 mb-4">
              <div>
                <h2 className="text-base font-semibold">{title}</h2>
                {hint && <p className="text-xs text-ink-500 mt-0.5">{hint}</p>}
              </div>
            </div>
          )}
          {!crumb || isPanelMode() ? children : (
            <Card className="p-6 max-w-4xl">{children}</Card>
          )}
        </div>
      </div>
    );
  }
  function isPanelMode() { return false; }

  Object.assign(window, { SuppliersPage, SupplierDetail, SupplierNew, CustomersPage, CustomerDetail, CustomerNew, ListShell, FormShell, KV, Stat });
})();
