/* screens-admin.jsx — /admin/warehouses, /admin/staff, /admin/config */

// ---------- Warehouses ----------
function WarehousesScreen({ country }) {
  const [q, setQ] = React.useState('');
  const [filterActive, setFilterActive] = React.useState('all');
  const [edit, setEdit] = React.useState(null);
  const [confirmDelete, setConfirmDelete] = React.useState(null);
  const { isMobile } = useViewport();

  let rows = WFP.WAREHOUSES.filter(w => w.countryCode === country);
  if (filterActive !== 'all') rows = rows.filter(w => filterActive === 'active' ? w.active : !w.active);
  if (q) rows = rows.filter(w => (w.code + w.name + w.city).toLowerCase().includes(q.toLowerCase()));

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
      <PageHeader
        breadcrumb={['Admin','Warehouses']}
        title="Warehouses"
        subtitle="Active warehouses, codes, and timezones. Changes here affect every plan and config scope."
        actions={
          <>
            <Button variant="outline" icon="download">Export CSV</Button>
            <Button variant="primary" icon="plus" onClick={() => setEdit({})}>New warehouse</Button>
          </>
        }
      />
      <div style={{ flex: 1, overflowY: 'auto', padding: 20 }}>
        <Card padding={0}>
          <div style={{ padding: '12px 14px', borderBottom: '1px solid var(--bx-border-muted)', display: 'flex', gap: 8, alignItems: 'center' }}>
            <div style={{ width: 280 }}>
              <Input icon="search" placeholder="Filter by code, name, city…" value={q} onChange={e => setQ(e.target.value)} size="sm"/>
            </div>
            <Tabs value={filterActive} onChange={setFilterActive} dense tabs={[
              { id: 'all',      label: 'All',      count: WFP.WAREHOUSES.filter(w => w.countryCode === country).length },
              { id: 'active',   label: 'Active',   count: WFP.WAREHOUSES.filter(w => w.countryCode === country && w.active).length },
              { id: 'inactive', label: 'Inactive', count: WFP.WAREHOUSES.filter(w => w.countryCode === country && !w.active).length },
            ]}/>
            <div style={{ flex: 1 }}/>
            <Button variant="ghost" size="sm" icon="filter">More filters</Button>
          </div>
          <Table columns={[
            { header: 'Code', width: 130, render: r => <span style={{ fontFamily: 'var(--bx-font-mono)', fontWeight: 600, color: 'var(--bx-text-dark)' }}>{r.code}</span> },
            { header: 'Name', render: r => (
              <div>
                <div style={{ fontWeight: 500, color: 'var(--bx-text-dark)' }}>{r.name}</div>
                <div style={{ fontSize: 11, color: 'var(--bx-text-muted)' }}>{r.city}</div>
              </div>
            )},
            { header: 'Timezone', mono: true, key: 'timezone', priority: 3 },
            { header: 'Active staff', align: 'right', numeric: true, priority: 2, render: r =>
              WFP.STAFF.filter(s => s.warehouseId === r.id && s.active).length
            },
            { header: 'Status', render: r => <Badge kind={r.active ? 'ACTIVE' : 'INACTIVE'}>{r.active ? 'Active' : 'Inactive'}</Badge> },
            { header: '', width: 100, render: r => (
              <div style={{ display: 'flex', gap: 4, justifyContent: 'flex-end' }}>
                <IconBtn name="edit" title="Edit" onClick={() => setEdit(r)}/>
                <IconBtn name="trash" title="Delete" onClick={() => setConfirmDelete(r)}/>
              </div>
            )},
          ]} rows={rows} getRowKey={r => r.id} emptyText="No warehouses match the filters"/>
        </Card>

        <Card title="Why this matters" subtitle="Read-only context for new admins" style={{ marginTop: 16 }}>
          <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'repeat(3, 1fr)', gap: 16 }}>
            <Hint icon="cube" title="Warehouse scope" body="Every config key can be scoped to one warehouse. Disable a warehouse here to retire its scoped values."/>
            <Hint icon="forecast" title="Forecast routing" body="The daily forecast worker writes one DailyForecast per active warehouse. Inactive warehouses are skipped silently."/>
            <Hint icon="shield" title="Labor law" body="Country code drives the labor-law caps applied to every shift plan run for that warehouse."/>
          </div>
        </Card>
      </div>

      {/* Edit dialog */}
      <WarehouseDialog open={!!edit} value={edit} onClose={() => setEdit(null)} onSave={() => setEdit(null)}/>
      <Dialog open={!!confirmDelete} onClose={() => setConfirmDelete(null)}
        title="Delete warehouse?" destructive
        subtitle={confirmDelete ? confirmDelete.code + ' · ' + confirmDelete.name : ''}
        footer={
          <>
            <Button variant="outline" onClick={() => setConfirmDelete(null)}>Cancel</Button>
            <Button variant="danger" icon="trash" onClick={() => setConfirmDelete(null)}>Delete warehouse</Button>
          </>
        }>
        <p style={{ margin: 0, fontSize: 13, color: 'var(--bx-text-body)' }}>
          This warehouse has <b>{confirmDelete ? WFP.STAFF.filter(s => s.warehouseId === confirmDelete.id).length : 0}</b> staff records and <b>warehouse-scoped config</b> tied to it.
          Soft-delete is recommended — toggle <i>Inactive</i> instead. Hard delete is irreversible.
        </p>
      </Dialog>
    </div>
  );
}

function Hint({ icon, title, body }) {
  return (
    <div style={{ display: 'flex', gap: 12 }}>
      <div style={{ width: 32, height: 32, borderRadius: 8, background: 'var(--bx-surface-2)', color: 'var(--bx-primary)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
        <Icon name={icon} size={14}/>
      </div>
      <div>
        <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--bx-text-heading)' }}>{title}</div>
        <div style={{ fontSize: 12.5, color: 'var(--bx-text-body)', marginTop: 4, lineHeight: 1.5 }}>{body}</div>
      </div>
    </div>
  );
}

function WarehouseDialog({ open, value, onClose, onSave }) {
  const [code, setCode] = React.useState('');
  const [name, setName] = React.useState('');
  const [city, setCity] = React.useState('');
  const [country, setCountry] = React.useState('VN');
  const [tz, setTz] = React.useState('Asia/Ho_Chi_Minh');
  const [active, setActive] = React.useState(true);
  React.useEffect(() => {
    if (open && value) {
      setCode(value.code || ''); setName(value.name || ''); setCity(value.city || '');
      setCountry(value.countryCode || 'VN'); setTz(value.timezone || 'Asia/Ho_Chi_Minh');
      setActive(value.active !== false);
    }
  }, [open, value]);
  const errors = {};
  if (!code) errors.code = 'Required';
  else if (!/^[A-Z]{2}-[A-Z]{2,5}-\d{2}$/.test(code)) errors.code = 'Format: CC-CITY-NN (e.g. VN-HN-01)';
  if (!name) errors.name = 'Required';
  const valid = Object.keys(errors).length === 0;

  return (
    <Dialog open={open} onClose={onClose}
      title={value && value.id ? 'Edit warehouse' : 'New warehouse'}
      subtitle="Code must match the org-wide CC-CITY-NN convention."
      footer={
        <>
          <Button variant="outline" onClick={onClose}>Cancel</Button>
          <Button variant="primary" disabled={!valid} onClick={onSave}>{value && value.id ? 'Save' : 'Create'}</Button>
        </>
      }>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
        <Field label="Code" required error={errors.code} hint="e.g. VN-HN-01">
          <Input value={code} onChange={e => setCode(e.target.value.toUpperCase())} placeholder="VN-HN-01" error={errors.code}/>
        </Field>
        <Field label="Country" required>
          <Select value={country} onChange={e => setCountry(e.target.value)}
            options={WFP.COUNTRIES.map(c => ({ value: c.code, label: c.code + ' · ' + c.name }))}/>
        </Field>
        <Field label="Name" required error={errors.name} style={{ gridColumn: '1 / span 2' }}>
          <Input value={name} onChange={e => setName(e.target.value)} placeholder="Hanoi North" error={errors.name}/>
        </Field>
        <Field label="City">
          <Input value={city} onChange={e => setCity(e.target.value)} placeholder="Hanoi"/>
        </Field>
        <Field label="Timezone" required>
          <Select value={tz} onChange={e => setTz(e.target.value)}
            options={['Asia/Ho_Chi_Minh','Asia/Bangkok','Asia/Manila']}/>
        </Field>
        <Field label="Status" style={{ gridColumn: '1 / span 2' }}>
          <label style={{ display: 'inline-flex', gap: 8, alignItems: 'center', cursor: 'pointer', fontSize: 13 }}>
            <input type="checkbox" checked={active} onChange={e => setActive(e.target.checked)} style={{ accentColor: 'var(--bx-primary)' }}/>
            <span>Active · receives forecasts and is plan-eligible</span>
          </label>
        </Field>
      </div>
    </Dialog>
  );
}

// ---------- Staff ----------
function StaffScreen({ warehouseId }) {
  const [q, setQ] = React.useState('');
  const [role, setRole] = React.useState('all');
  const [stype, setStype] = React.useState('all');
  const [level, setLevel] = React.useState('all');
  const { isMobile, vw } = useViewport();

  let rows = WFP.STAFF.filter(s => s.warehouseId === warehouseId);
  if (role !== 'all') rows = rows.filter(s => s.role === role);
  if (stype !== 'all') rows = rows.filter(s => s.staffType === stype);
  if (level !== 'all') rows = rows.filter(s => s.level === level);
  if (q) rows = rows.filter(s => (s.fullName + s.code).toLowerCase().includes(q.toLowerCase()));

  const totals = WFP.STAFF.filter(s => s.warehouseId === warehouseId);
  const byRole = ['PICKER','PACKER','CHECKER','LEAD'].map(r => ({ role: r, count: totals.filter(s => s.role === r).length }));
  const byType = ['OFFICIAL','TEMP'].map(t => ({ t, count: totals.filter(s => s.staffType === t).length }));

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
      <PageHeader
        breadcrumb={['Admin','Staff']}
        title="Staff"
        subtitle={'Roster for current warehouse · ' + totals.length + ' people · ' + totals.filter(s => s.active).length + ' active'}
        actions={
          <>
            <Button variant="outline" icon="download">Export</Button>
            <Button variant="outline" icon="upload">Import CSV</Button>
            <Button variant="primary" icon="plus">Add staff</Button>
          </>
        }
      />
      <div style={{ flex: 1, overflowY: 'auto', padding: isMobile ? 14 : 20 }}>
        {/* mini KPIs */}
        <div style={{
          display: 'grid',
          gridTemplateColumns: vw < 560 ? 'repeat(2, 1fr)' : vw < 900 ? 'repeat(3, 1fr)' : 'repeat(6, 1fr)',
          gap: isMobile ? 8 : 12, marginBottom: isMobile ? 12 : 16,
        }}>
          {byRole.map(r => (
            <Metric key={r.role} label={r.role.toLowerCase()} value={r.count} sublabel="people"/>
          ))}
          {byType.map(t => (
            <Metric key={t.t} label={t.t === 'OFFICIAL' ? 'Official' : 'Temp · agency'} value={t.count} sublabel="people"/>
          ))}
        </div>

        <Card padding={0}>
          <div style={{ padding: '12px 14px', borderBottom: '1px solid var(--bx-border-muted)', display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
            <div style={{ width: 280 }}>
              <Input icon="search" placeholder="Search by name or employee code…" value={q} onChange={e => setQ(e.target.value)} size="sm"/>
            </div>
            <div style={{ width: 130 }}>
              <Select value={role} onChange={e => setRole(e.target.value)} size="sm"
                options={[{ value: 'all', label: 'All roles' }, { value: 'PICKER', label: 'Picker' }, { value: 'PACKER', label: 'Packer' }, { value: 'CHECKER', label: 'Checker' }, { value: 'LEAD', label: 'Lead' }]}/>
            </div>
            <div style={{ width: 130 }}>
              <Select value={stype} onChange={e => setStype(e.target.value)} size="sm"
                options={[{ value: 'all', label: 'All types' }, { value: 'OFFICIAL', label: 'Official' }, { value: 'TEMP', label: 'Temp · agency' }]}/>
            </div>
            <div style={{ width: 110 }}>
              <Select value={level} onChange={e => setLevel(e.target.value)} size="sm"
                options={[{ value: 'all', label: 'All levels' }, { value: 'L1', label: 'L1' }, { value: 'L2', label: 'L2' }, { value: 'L3', label: 'L3' }]}/>
            </div>
            <div style={{ flex: 1 }}/>
            <span style={{ fontSize: 12, color: 'var(--bx-text-muted)' }}>{rows.length} of {totals.length}</span>
          </div>
          <Table
            columns={[
              { header: 'Employee', render: r => (
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <Avatar name={r.fullName}/>
                  <div style={{ minWidth: 0 }}>
                    <div style={{ fontWeight: 600, fontSize: 13, color: 'var(--bx-text-dark)' }}>{r.fullName}</div>
                    <div style={{ fontSize: 11.5, color: 'var(--bx-text-muted)', fontFamily: 'var(--bx-font-mono)' }}>{r.code} · {r.role.toLowerCase()} · {r.level}</div>
                  </div>
                </div>
              )},
              { header: 'Role',  priority: 2, key: 'role',  render: r => <span style={{ textTransform: 'capitalize' }}>{r.role.toLowerCase()} · {r.level}</span> },
              { header: 'Type', priority: 2, render: r => <Badge kind={r.staffType === 'OFFICIAL' ? 'APPROVED' : 'WARNING'}>{r.staffType === 'OFFICIAL' ? 'Official' : 'Temp'}</Badge> },
              { header: 'Joined', priority: 3, mono: true, render: r => fmt.date(r.joinedAt) },
              { header: 'Status', render: r => <Badge kind={r.active ? 'ACTIVE' : 'INACTIVE'}>{r.active ? 'Active' : 'Inactive'}</Badge> },
              { header: '', width: 80, render: r => (
                <div style={{ display: 'flex', gap: 4, justifyContent: 'flex-end' }}>
                  <IconBtn name="edit" title="Edit"/>
                  <IconBtn name="ellipsis" title="More"/>
                </div>
              )},
            ]}
            rows={rows.slice(0, 80)} getRowKey={r => r.id}
            emptyText="No staff match the filters"
          />
        </Card>
      </div>
    </div>
  );
}

// ---------- Config (the most complex admin page) ----------
function ConfigScreen() {
  const [group, setGroup] = React.useState('All');
  const [scope, setScope] = React.useState('all');
  const [q, setQ] = React.useState('');
  const [selectedKey, setSelectedKey] = React.useState(WFP.CONFIG_KEYS[0]);
  const [editing, setEditing] = React.useState(null);
  const { isMobile, vw } = useViewport();
  const stacked = vw < 900;
  // mobile: when a key is picked, show detail; back button returns to list
  const [mobileShowDetail, setMobileShowDetail] = React.useState(false);

  const groups = ['All', ...Array.from(new Set(WFP.CONFIG_KEYS.map(c => c.group)))];

  let rows = WFP.CONFIG_KEYS.slice();
  if (group !== 'All') rows = rows.filter(r => r.group === group);
  if (scope !== 'all') rows = rows.filter(r => r.scope === scope);
  if (q) rows = rows.filter(r => (r.key + ' ' + r.label).toLowerCase().includes(q.toLowerCase()));

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>
      <PageHeader
        breadcrumb={['Admin','Config registry']}
        title="Config registry"
        subtitle="Versioned hyperparameters · resolved by ConfigService.getConfig(key, scope, asOf)"
        actions={
          <>
            <Button variant="outline" icon="history">Log</Button>
            <Button variant="outline" icon="download">Export</Button>
            <Button variant="primary" icon="plus" onClick={() => setEditing({ isNew: true, key: '', scope: 'global', current: '', label: '' })}>New key</Button>
          </>
        }
      />
      <div style={{ flex: 1, minHeight: 0, display: 'grid', gridTemplateColumns: stacked ? '1fr' : '380px 1fr', gap: 0 }}>
        {/* List */}
        <div style={{
          display: (stacked && mobileShowDetail) ? 'none' : 'flex',
          flexDirection: 'column',
          borderRight: stacked ? 'none' : '1px solid var(--bx-border-muted)',
          background: '#fff', minHeight: 0,
        }}>
          <div style={{ padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 8, borderBottom: '1px solid var(--bx-border-muted)' }}>
            <Input icon="search" placeholder="Search keys (e.g. engine.uph)" value={q} onChange={e => setQ(e.target.value)} size="sm"/>
            <div style={{ display: 'flex', gap: 6 }}>
              <div style={{ flex: 1 }}>
                <Select value={group} onChange={e => setGroup(e.target.value)} size="sm" options={groups}/>
              </div>
              <div style={{ width: 130 }}>
                <Select value={scope} onChange={e => setScope(e.target.value)} size="sm"
                  options={[{ value: 'all', label: 'All scopes' }, { value: 'global', label: 'Global' }, { value: 'warehouse', label: 'Warehouse' }]}/>
              </div>
            </div>
          </div>
          <div style={{ flex: 1, overflowY: 'auto' }}>
            {rows.map(r => {
              const active = selectedKey && r.key === selectedKey.key && (r.warehouseId || null) === (selectedKey.warehouseId || null);
              return (
                <button key={r.key + '-' + (r.warehouseId || 'g')}
                  onClick={() => { setSelectedKey(r); if (stacked) setMobileShowDetail(true); }} style={{
                  width: '100%', textAlign: 'left', border: 'none', cursor: 'pointer',
                  background: active ? '#eef2ff' : 'transparent',
                  padding: '10px 14px', borderBottom: '1px solid var(--bx-border-muted)',
                  display: 'flex', flexDirection: 'column', gap: 4,
                }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'center' }}>
                    <span style={{ fontFamily: 'var(--bx-font-mono)', fontSize: 11.5, color: active ? 'var(--bx-primary)' : 'var(--bx-text-dark)', fontWeight: 600 }}>
                      {r.key}
                    </span>
                    <Badge kind={r.scope === 'global' ? 'APPROVED' : 'WARNING'} size="sm">
                      {r.scope === 'global' ? 'global' : 'wh'}
                    </Badge>
                  </div>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 8 }}>
                    <span style={{ fontSize: 11.5, color: 'var(--bx-text-muted)' }}>{r.group}</span>
                    <span style={{ fontFamily: 'var(--bx-font-mono)', fontSize: 12, fontWeight: 600, color: 'var(--bx-text-dark)' }}>
                      {formatVal(r.current, r.unit)}
                    </span>
                  </div>
                </button>
              );
            })}
            {rows.length === 0 && <Empty icon="search" title="No keys match" subtitle="Try clearing the group or scope filters."/>}
          </div>
        </div>

        {/* Detail */}
        <div style={{
          display: (stacked && !mobileShowDetail) ? 'none' : 'block',
          overflowY: 'auto', padding: isMobile ? 14 : 20, background: 'var(--bx-page-bg)',
        }}>
          {stacked && (
            <Button variant="ghost" icon="chevron-left" size="sm" onClick={() => setMobileShowDetail(false)} style={{ marginBottom: 12 }}>Back to keys</Button>
          )}
          {selectedKey ? <ConfigDetail entry={selectedKey} onEdit={() => setEditing(selectedKey)}/> : <Empty icon="sliders" title="Select a key" subtitle="Pick a config key from the list to see its current value, scope, and version history."/>}
        </div>
      </div>

      <ConfigEditDialog open={!!editing} entry={editing} onClose={() => setEditing(null)}/>
    </div>
  );
}

function formatVal(v, unit) {
  if (typeof v === 'boolean') return v ? 'true' : 'false';
  if (Array.isArray(v)) return v.length + ' items';
  if (typeof v === 'number') {
    if (unit === '%') return v + '%';
    if (unit) return v + ' ' + unit;
    return String(v);
  }
  return String(v);
}

function ConfigDetail({ entry, onEdit }) {
  const versions = entry.versions;
  const trendValues = versions.slice().reverse().map(v => typeof v.value === 'number' ? v.value : 0).slice(-7);
  const { isMobile, vw } = useViewport();
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <Card title={entry.label} subtitle={<span style={{ fontFamily: 'var(--bx-font-mono)' }}>{entry.key}</span>}
        actions={
          <>
            {!isMobile && <Button variant="outline" icon="copy" size="sm" title="Copy key">Copy key</Button>}
            <Button variant="primary" icon="edit" size="sm" onClick={onEdit}>Edit{!isMobile ? ' · creates v' + ((versions[0]?.version || 0) + 1) : ''}</Button>
          </>
        }>
        <div style={{
          display: 'grid',
          gridTemplateColumns: vw < 560 ? 'repeat(2, 1fr)' : 'repeat(4, 1fr)',
          gap: 14,
        }}>
          <DetailField label="Current value" value={
            <span style={{ fontFamily: 'var(--bx-font-mono)', fontSize: 22, fontWeight: 700, color: 'var(--bx-text-heading)' }}>
              {formatVal(entry.current, entry.unit)}
            </span>
          }/>
          <DetailField label="Scope" value={
            <Badge kind={entry.scope === 'global' ? 'APPROVED' : 'WARNING'}>
              {entry.scope === 'global' ? 'Global' : 'Warehouse: ' + (WFP.WAREHOUSES.find(w => w.id === entry.warehouseId)?.code || '—')}
            </Badge>
          }/>
          <DetailField label="Version" value={
            <span style={{ fontFamily: 'var(--bx-font-mono)', fontSize: 14, fontWeight: 600 }}>
              v{versions[0].version}
              <span style={{ fontSize: 11, fontWeight: 400, color: 'var(--bx-text-muted)', marginLeft: 6 }}>· {versions.length} total</span>
            </span>
          }/>
          <DetailField label="Trend" value={
            typeof entry.current === 'number' ? <Sparkline data={trendValues}/> : <span style={{ fontSize: 12, color: 'var(--bx-text-muted)' }}>n/a</span>
          }/>
        </div>

        <div style={{ marginTop: 16, padding: 12, background: 'var(--bx-surface-2)', borderRadius: 8, fontSize: 12, color: 'var(--bx-text-body)', display: 'flex', alignItems: 'flex-start', gap: 10 }}>
          <Icon name="info" size={13} style={{ color: 'var(--bx-primary)', marginTop: 2 }}/>
          <div>
            <b>Resolution:</b> ConfigService picks the warehouse-scoped value if present and effective at the resolution time;
            otherwise it falls back to the global value. Auto-tune writes new versions; manual edits do the same. No in-place updates.
          </div>
        </div>
      </Card>

      <Card title="Version history" padding={0}>
        <Table dense columns={[
          { header: 'v', mono: true, align: 'right', width: 60, render: r => 'v' + r.version },
          { header: 'Value', mono: true, render: r => formatVal(r.value, entry.unit) },
          { header: 'Δ from prev', mono: true, priority: 2, render: (r, i) => {
            const prev = versions[i + 1];
            if (!prev || typeof r.value !== 'number' || typeof prev.value !== 'number') return <span style={{ color: 'var(--bx-text-muted)' }}>—</span>;
            const d = r.value - prev.value;
            const pct = (d / prev.value) * 100;
            return (
              <span style={{ color: d > 0 ? 'var(--bx-success)' : d < 0 ? 'var(--bx-error)' : 'var(--bx-text-muted)', fontWeight: 600 }}>
                {fmt.signed(d)} <span style={{ fontWeight: 400 }}>({pct > 0 ? '+' : ''}{pct.toFixed(1)}%)</span>
              </span>
            );
          }},
          { header: 'Valid from', mono: true, priority: 2, render: r => fmt.dateTime(r.validFrom) },
          { header: 'By', priority: 2, render: r => (
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
              {r.updatedBy === 'autotune'
                ? <Badge kind="INFO" size="sm">autotune</Badge>
                : r.updatedBy === 'seed'
                  ? <Badge kind="INACTIVE" size="sm">seed</Badge>
                  : <span style={{ fontSize: 11.5 }}>{r.updatedBy}</span>}
            </span>
          )},
          { header: 'Reason', wrap: true, priority: 3, render: r => <span style={{ color: 'var(--bx-text-body)', fontSize: 12 }}>{r.reason}</span> },
          { header: '', width: 50, render: () => <IconBtn name="ellipsis"/> },
        ]} rows={versions} getRowKey={(r, i) => 'v' + r.version + '-' + i}/>
      </Card>

      <Card title="Where this is used" subtitle="Code references and runtime consumers">
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {[
            { module: 'engine/orchestrator.ts', line: 142, kind: 'read' },
            { module: 'engine/layer2-hours.ts', line: 38,  kind: 'read' },
            { module: 'autotune/uph-update.ts', line: 91,  kind: 'write' },
          ].map((u, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: 8, borderRadius: 6, background: i % 2 === 0 ? 'var(--bx-surface-2)' : 'transparent' }}>
              <Icon name="link" size={11} style={{ color: 'var(--bx-text-muted)' }}/>
              <span style={{ fontFamily: 'var(--bx-font-mono)', fontSize: 11.5, color: 'var(--bx-text-dark)' }}>{u.module}</span>
              <span style={{ fontFamily: 'var(--bx-font-mono)', fontSize: 11, color: 'var(--bx-text-muted)' }}>:{u.line}</span>
              <Badge kind={u.kind === 'write' ? 'WARNING' : 'APPROVED'} size="sm">{u.kind}</Badge>
              <div style={{ flex: 1 }}/>
              <IconBtn name="external" size={26}/>
            </div>
          ))}
        </div>
      </Card>
    </div>
  );
}

function DetailField({ label, value }) {
  return (
    <div>
      <div style={{ fontSize: 11, color: 'var(--bx-text-muted)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600, marginBottom: 6 }}>{label}</div>
      <div>{value}</div>
    </div>
  );
}

function ConfigEditDialog({ open, entry, onClose }) {
  const [value, setValue] = React.useState('');
  const [reason, setReason] = React.useState('');
  const [validFrom, setValidFrom] = React.useState('2026-05-19T00:00');
  React.useEffect(() => { if (open && entry) {
    setValue(typeof entry.current === 'object' ? JSON.stringify(entry.current) : String(entry.current ?? ''));
    setReason(''); setValidFrom('2026-05-19T00:00');
  }}, [open, entry]);
  if (!entry) return null;
  const errors = {};
  if (entry.type === 'number' || entry.type === 'percent') {
    if (value === '') errors.value = 'Required';
    else if (isNaN(Number(value))) errors.value = 'Must be a number';
    else if (entry.type === 'percent' && (Number(value) < 0 || Number(value) > 100)) errors.value = 'Must be 0–100';
  }
  if (!reason || reason.length < 8) errors.reason = 'Provide a short reason (min 8 chars)';

  const valid = Object.keys(errors).length === 0;
  const nextV = (entry.versions?.[0]?.version || 0) + 1;
  return (
    <Dialog open={open} onClose={onClose} width={620}
      title={'Edit · ' + entry.label}
      subtitle="Creates a new version. The previous version remains as audit trail."
      footer={
        <>
          <Button variant="outline" onClick={onClose}>Cancel</Button>
          <Button variant="primary" disabled={!valid} icon="check" onClick={onClose}>Save as v{nextV}</Button>
        </>
      }>
      <div style={{ marginBottom: 12, padding: 10, background: 'var(--bx-surface-2)', borderRadius: 8, display: 'flex', alignItems: 'center', gap: 12 }}>
        <span style={{ fontSize: 11, color: 'var(--bx-text-muted)' }}>Key</span>
        <span style={{ fontFamily: 'var(--bx-font-mono)', fontSize: 12, fontWeight: 600 }}>{entry.key}</span>
        <span style={{ flex: 1 }}/>
        <Badge kind={entry.scope === 'global' ? 'APPROVED' : 'WARNING'} size="sm">{entry.scope}</Badge>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
        <Field label="Current" hint={'v' + (entry.versions?.[0]?.version || 0) + ' · ' + fmt.dateTime(entry.versions?.[0]?.validFrom)}>
          <Input value={String(entry.current ?? '')} disabled/>
        </Field>
        <Field label={'New value (v' + nextV + ')'} required error={errors.value} hint={entry.unit ? 'Unit: ' + entry.unit : undefined}>
          <Input value={value} onChange={e => setValue(e.target.value)} error={errors.value}/>
        </Field>
        <Field label="Valid from" required hint="ISO datetime. Applies to plans run after this time.">
          <Input type="datetime-local" value={validFrom} onChange={e => setValidFrom(e.target.value)}/>
        </Field>
        <Field label="Author" hint="Auto-filled from your session">
          <Input value="linh.tran@boxme.tech" disabled/>
        </Field>
        <Field label="Reason" required error={errors.reason} style={{ gridColumn: '1 / span 2' }}
          hint="Free text. Shown in audit and ConfigValue.reason.">
          <Input value={reason} onChange={e => setReason(e.target.value)} placeholder="e.g. manual recalibration after WMS migration"/>
        </Field>
      </div>

      <div style={{ marginTop: 14, padding: 10, background: '#fef2f2', borderRadius: 8, fontSize: 12, color: '#b91c1c', display: 'flex', gap: 8, alignItems: 'flex-start' }}>
        <Icon name="warning" size={13} style={{ marginTop: 2 }}/>
        <div>
          Plans generated <b>before</b> {validFrom || 'now'} continue to use v{entry.versions?.[0]?.version}.
          Changing this key affects all plans generated after that time.
        </div>
      </div>
    </Dialog>
  );
}

Object.assign(window, { WarehousesScreen, StaffScreen, ConfigScreen, ConfigDetail });
