/* Clients List — saved views, search, RBAC-scoped table, bulk actions.
   Spec: monolith-docs/clients/clients-list-view.md */
const { useState: useStateCL, useMemo: useMemoCL, useEffect: useEffectCL } = React;

const BIZ_CFG = {
  prospect:        { label: 'Prospect',        cls: 'bs-prospect', icon: 'circle-dashed' },
  customer:        { label: 'Customer',        cls: 'bs-customer', icon: 'badge-check' },
  former_customer: { label: 'Former customer', cls: 'bs-former',   icon: 'circle-minus' },
};
function BizStatusChip({ status, size = 'md', onClick }) {
  const c = BIZ_CFG[status] || BIZ_CFG.prospect;
  const cls = ['mn-chip', `mn-chip--${size}`, `mn-chip--${c.cls}`];
  if (onClick) cls.push('mn-chip--btn');
  return (
    <span className={cls.join(' ')} onClick={onClick}>
      <Icon name={c.icon} size="xs" stroke="2" /> {c.label}
      {onClick ? <Icon name="chevron-down" size="xs" stroke="2" /> : null}
    </span>
  );
}
function ActStatusChip({ status, size = 'md' }) {
  const active = status === 'active';
  return (
    <span className={`mn-chip mn-chip--${size} mn-chip--${active ? 'as-active' : 'as-inactive'}`}>
      <Icon name={active ? 'zap' : 'moon'} size="xs" stroke="2" /> {active ? 'Active' : 'Inactive'}
    </span>
  );
}
function clientTime(tzOffset) {
  const d = new Date(window.MonolitData.NOW.getTime() + tzOffset * 3600000);
  return `${String(d.getUTCHours()).padStart(2, '0')}:${String(d.getUTCMinutes()).padStart(2, '0')}`;
}

// Shared filter pattern config for Clients (kinds + predicates; options/counts built per render).
const CLIENT_CREATED_PRESETS = [{ label: 'Today', days: 1 }, { label: 'Last 7 days', days: 7 }, { label: 'Last 30 days', days: 30 }, { label: 'Last 90 days', days: 90 }];
const CLIENT_SECTIONS = [
  { key: 'biz', label: 'Business status', kind: 'pills', match: (c, v) => v.includes(c.businessStatus) },
  { key: 'activity', label: 'Activity status', kind: 'pills', match: (c, v) => v.includes(c.activityStatus) },
  { key: 'owner', label: 'Owner', kind: 'people', match: (c, v) => v.includes(c.owner ? c.owner.id : 'none') },
  { key: 'account', label: 'Account', kind: 'pills', match: (c, v) => v.includes(c.account || '—') },
  { key: 'source', label: 'Source', kind: 'pills', match: (c, v) => v.includes(c.source ? c.source.type : '—') },
  { key: 'tags', label: 'Tags', kind: 'pills', match: (c, v) => (c.tags || []).some(t => v.includes(t)) },
  { key: 'created', label: 'Created', kind: 'daterange', presets: CLIENT_CREATED_PRESETS, match: (c, r) => { const t = new Date(c.createdAt).getTime(); const f = r.from ? new Date(r.from).getTime() : -Infinity; const to = r.to ? new Date(r.to).getTime() + 86400000 : Infinity; return t >= f && t < to; } },
];

function ClientsList({ clients, role, onOpenClient, onCreate }) {
  const RB = window.MonolitRBAC;
  const scoped = useMemoCL(() => RB.scopeClients(role, clients), [clients, role]);
  const saved = useMemoCL(() => { try { return JSON.parse(localStorage.getItem('mn_clients_view') || '{}'); } catch (e) { return {}; } }, []);
  const [view, setView] = useStateCL(saved.view || 'all');
  const [selected, setSelected] = useStateCL(new Set());
  const [query, setQuery] = useStateCL(saved.query || '');
  const [sortKey, setSortKey] = useStateCL(saved.sortKey || 'createdAt');
  const [sortDir, setSortDir] = useStateCL(saved.sortDir || 'desc');
  const [fstate, setFstate] = useStateCL(saved.fstate || filterEmpty(CLIENT_SECTIONS));
  const [filterOpen, setFilterOpen] = useStateCL(false);
  const [page, setPage] = useStateCL(1);
  const [pageSize, setPageSize] = useStateCL(25);
  useEffectCL(() => { try { localStorage.setItem('mn_clients_view', JSON.stringify({ view, query, sortKey, sortDir, fstate })); } catch (e) {} }, [view, query, sortKey, sortDir, fstate]);
  useEffectCL(() => { setPage(1); }, [view, query, fstate, sortKey, sortDir, pageSize]);
  const setFilter = (k, v) => setFstate(s => ({ ...s, [k]: v }));
  const activeFilters = filterCount(CLIENT_SECTIONS, fstate);

  const views = [
    { id: 'all',       label: 'All clients',  filter: c => c.systemStatus !== 'archived' },
    { id: 'my',        label: 'My clients',   filter: c => c.systemStatus !== 'archived' && c.owner && c.owner.id === RB.ME },
    { id: 'active',    label: 'Active',       filter: c => c.systemStatus !== 'archived' && c.activityStatus === 'active' },
    { id: 'inactive',  label: 'Inactive',     filter: c => c.systemStatus !== 'archived' && c.activityStatus === 'inactive' },
    { id: 'prospects', label: 'Prospects',    filter: c => c.systemStatus !== 'archived' && c.businessStatus === 'prospect' },
    { id: 'customers', label: 'Customers',    filter: c => c.systemStatus !== 'archived' && c.businessStatus === 'customer' },
    { id: 'attention', label: 'Needs attention', filter: c => c.systemStatus !== 'archived' && (c.activityStatus === 'inactive' || !c.owner || (c.businessStatus === 'customer' && c.activeDeals === 0)) },
    { id: 'archived',  label: 'Archived',     filter: c => c.systemStatus === 'archived' },
  ];

  const viewScoped = useMemoCL(() => { const vv = views.find(x => x.id === view); return vv ? scoped.filter(vv.filter) : scoped; }, [scoped, view]);
  // Faceted options (with live counts over the current view) for the shared FilterDrawer/Bar.
  const sections = useMemoCL(() => {
    const cnt = (pred) => viewScoped.reduce((a, c) => a + (pred(c) ? 1 : 0), 0);
    const uniq = (arr) => Array.from(new Set(arr));
    const ownerOpts = (() => { const seen = {}; const o = [{ value: 'none', label: 'Unassigned', count: cnt(c => !c.owner) }]; viewScoped.forEach(c => { if (c.owner && !seen[c.owner.id]) { seen[c.owner.id] = 1; o.push({ value: c.owner.id, label: c.owner.name, user: c.owner, count: cnt(x => x.owner && x.owner.id === c.owner.id) }); } }); return o; })();
    const byKey = {
      biz: Object.keys(BIZ_CFG).map(k => ({ value: k, label: BIZ_CFG[k].label, node: <BizStatusChip status={k} />, count: cnt(c => c.businessStatus === k) })),
      activity: ['active', 'inactive'].map(k => ({ value: k, label: k === 'active' ? 'Active' : 'Inactive', node: <ActStatusChip status={k} />, count: cnt(c => c.activityStatus === k) })),
      owner: ownerOpts,
      account: uniq(viewScoped.map(c => c.account || '—')).map(a => ({ value: a, label: a, count: cnt(c => (c.account || '—') === a) })),
      source: uniq(viewScoped.map(c => c.source ? c.source.type : '—')).map(s => ({ value: s, label: s, count: cnt(c => (c.source ? c.source.type : '—') === s) })),
      tags: uniq(viewScoped.flatMap(c => c.tags || [])).map(t => ({ value: t, label: t, count: cnt(c => (c.tags || []).includes(t)) })),
    };
    return CLIENT_SECTIONS.map(sec => ({ ...sec, options: byKey[sec.key] }));
  }, [viewScoped]);

  const filtered = useMemoCL(() => {
    let r = applyFilters(viewScoped, CLIENT_SECTIONS, fstate);
    if (query) {
      const q = query.toLowerCase();
      r = r.filter(c => (c.id + c.name + (c.email || '') + (c.account || '') + (c.phone || '')).toLowerCase().includes(q));
    }
    r = r.slice().sort((a, b) => {
      let va, vb;
      if (sortKey === 'createdAt') { va = a.createdAt; vb = b.createdAt; }
      else if (sortKey === 'name') { va = a.name; vb = b.name; }
      else if (sortKey === 'lastActivity') { va = a.lastActivity || 0; vb = b.lastActivity || 0; }
      else if (sortKey === 'businessStatus') { va = a.businessStatus; vb = b.businessStatus; }
      else if (sortKey === 'activeDeals') { va = a.activeDeals; vb = b.activeDeals; }
      const cmp = va < vb ? -1 : va > vb ? 1 : 0;
      return sortDir === 'asc' ? cmp : -cmp;
    });
    return r;
  }, [viewScoped, fstate, query, sortKey, sortDir]);

  function toggleSort(k) {
    if (sortKey === k) setSortDir(sortDir === 'asc' ? 'desc' : 'asc');
    else { setSortKey(k); setSortDir(k === 'name' ? 'asc' : 'desc'); }
  }
  function toggleSel(id) { const n = new Set(selected); n.has(id) ? n.delete(id) : n.add(id); setSelected(n); }
  function toggleAll() {
    if (selected.size === filtered.length) setSelected(new Set());
    else setSelected(new Set(filtered.map(c => c.id)));
  }
  const viewCount = (v) => scoped.filter(v.filter).length;
  const canBulk = RB.can(role, 'clients.bulk');
  const isViewer = role === 'Viewer';

  return (
    <React.Fragment>
      <div className="mn-page-h">
        <div className="mn-page-title">
          <h1 className="title-1">Clients</h1>
          <span className="mn-page-count">{filtered.length} of {scoped.length}</span>
        </div>
        <div className="mn-page-actions">
          {RB.can(role, 'clients.import') ? <Button variant="ghost" size="md" icon="upload">Import</Button> : null}
          {RB.can(role, 'clients.export') ? <Button variant="ghost" size="md" icon="download">Export</Button> : null}
          {RB.can(role, 'clients.create') ? <Button variant="primary" size="md" icon="plus" onClick={onCreate}>Add client</Button> : null}
        </div>
      </div>

      {isViewer ? (
        <div className="mn-robanner"><Icon name="eye" size="sm" />Read-only access — your role is Viewer.</div>
      ) : null}

      <div className="mn-presets">
        {views.map((v) => (
          <button key={v.id} type="button"
                  className={'mn-preset' + (view === v.id ? ' mn-preset--active' : '')}
                  onClick={() => { setView(v.id); setSelected(new Set()); }}>
            <span>{v.label}</span>
            <span className="mn-preset-c">{viewCount(v)}</span>
          </button>
        ))}
      </div>

      <div className="mn-toolbar">
        <div style={{ width: 320 }}>
          <Input fullWidth icon="search" placeholder="Search by ID, name, email, account…" value={query} onChange={setQuery} />
        </div>
        <Button variant={activeFilters ? 'secondary' : 'ghost'} size="md" icon="filter" onClick={() => setFilterOpen(true)}>Filters{activeFilters ? ' · ' + activeFilters : ''}</Button>
        <div className="mn-toolbar-spacer" />
        {selected.size > 0 && canBulk ? (
          <React.Fragment>
            <span className="mn-mono mn-muted" style={{ marginRight: 4 }}>{selected.size} selected</span>
            <Button variant="ghost" size="md" icon="user-plus">Assign owner</Button>
            <Button variant="ghost" size="md" icon="tag">Add tags</Button>
            <Button variant="ghost" size="md" icon="archive">Archive</Button>
          </React.Fragment>
        ) : null}
      </div>

      <FilterBar sections={sections} state={fstate} onChange={setFilter} onReset={() => setFstate(filterEmpty(CLIENT_SECTIONS))} />

      <div className="mn-table-wrap">
        <table className="mn-table">
          <thead>
            <tr>
              {canBulk ? (
              <th style={{ width: 36 }}>
                <input className="mn-checkbox" type="checkbox"
                       checked={selected.size > 0 && selected.size === filtered.length}
                       ref={(el) => { if (el) el.indeterminate = selected.size > 0 && selected.size < filtered.length; }}
                       onChange={toggleAll} />
              </th>
              ) : null}
              <th style={{ width: 120 }}>ID</th>
              <SortableTh label="Client" k="name" sortKey={sortKey} sortDir={sortDir} onClick={toggleSort} />
              <th>Account</th>
              <th style={{ width: 170 }}>Owner</th>
              <SortableTh label="Business" k="businessStatus" sortKey={sortKey} sortDir={sortDir} onClick={toggleSort} style={{ width: 150 }} />
              <th style={{ width: 110 }}>Activity</th>
              <SortableTh label="Last activity" k="lastActivity" sortKey={sortKey} sortDir={sortDir} onClick={toggleSort} style={{ width: 120 }} />
              <SortableTh label="Active deals" k="activeDeals" sortKey={sortKey} sortDir={sortDir} onClick={toggleSort} style={{ width: 110 }} />
              <th style={{ width: 100 }}>Local time</th>
              <SortableTh label="Created" k="createdAt" sortKey={sortKey} sortDir={sortDir} onClick={toggleSort} style={{ width: 95 }} />
              <th style={{ width: 36 }}></th>
            </tr>
          </thead>
          <tbody>
            {filtered.slice((page - 1) * pageSize, page * pageSize).map((c) => {
              const rowCls = [];
              if (!isViewer) rowCls.push('mn-row--clickable');
              if (selected.has(c.id)) rowCls.push('mn-row--selected');
              return (
                <tr key={c.id} className={rowCls.join(' ')} onClick={(e) => {
                  if (e.target.closest('button, input, .mn-chip--btn')) return;
                  onOpenClient(c.id);
                }}>
                  {canBulk ? (
                  <td onClick={(e) => e.stopPropagation()}>
                    <input className="mn-checkbox" type="checkbox" checked={selected.has(c.id)} onChange={() => toggleSel(c.id)} />
                  </td>
                  ) : null}
                  <td className="mn-cell-id">{c.id}</td>
                  <td>
                    <div className="mn-cell-name">
                      <div className="mn-cell-name-text">
                        <strong>{c.name}{c.createdFromLead ? <span className="mn-chip mn-chip--fromlead" style={{ marginLeft: 6 }}>from lead</span> : null}</strong>
                        <span>{c.email}</span>
                      </div>
                    </div>
                  </td>
                  <td>
                    {c.account
                      ? <span style={{ font: 'var(--font-weight-medium) 13px/16px var(--font-sans)' }}>{c.account}</span>
                      : <span className="mn-chip mn-chip--nonext">No account</span>}
                  </td>
                  <td>
                    {c.owner ? (
                      <div className="mn-cell-owner"><Avatar user={c.owner} size={22} /><span>{c.owner.name}</span></div>
                    ) : (
                      <span className="mn-chip mn-chip--noowner"><Icon name="user-x" size="xs" stroke="2" />No owner</span>
                    )}
                  </td>
                  <td><BizStatusChip status={c.businessStatus} onClick={RB.can(role, 'clients.status.business') ? () => {} : undefined} /></td>
                  <td><ActStatusChip status={c.activityStatus} /></td>
                  <td><span style={{ font: 'var(--font-weight-medium) 12px/16px var(--font-sans)', color: c.activityStatus === 'inactive' ? 'var(--text-3)' : 'var(--text-2)' }}>{relTime(new Date(c.lastActivity))}</span></td>
                  <td>
                    {c.activeDeals > 0
                      ? <span className="mn-row" style={{ gap: 6 }}><span className="mn-mono" style={{ fontSize: 13 }}>{c.activeDeals}</span><span className="mn-mono mn-muted" style={{ fontSize: 11 }}>€{(c.openDealsValue / 1000).toFixed(0)}k</span></span>
                      : <span className="mn-mono mn-muted" style={{ fontSize: 12 }}>—</span>}
                  </td>
                  <td><span className="mn-mono" style={{ fontSize: 12, color: 'var(--text-2)' }}>{clientTime(c.tzOffset)}</span></td>
                  <td><span className="mn-mono" style={{ fontSize: 12, color: 'var(--text-3)' }}>{new Date(c.createdAt).toLocaleDateString('en-GB', { day: '2-digit', month: 'short' })}</span></td>
                  <td onClick={(e) => e.stopPropagation()}>
                    <IconButton icon="more-horizontal" size="sm" title="Row actions" />
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
        {filtered.length === 0 ? (
          <div className="mn-empty">
            <Icon name={view === 'archived' ? 'archive' : 'search-x'} size="lg" />
            <div className="mn-empty-msg">
              {view === 'archived' ? 'No archived clients.' : query ? 'No matches. Reset search or filters.' : 'No clients in this view.'}
            </div>
            {query || activeFilters ? <Button variant="ghost" size="sm" onClick={() => { setQuery(''); setFstate(filterEmpty(CLIENT_SECTIONS)); }}>Reset</Button> : null}
          </div>
        ) : null}
      </div>
      {filtered.length > 0 ? <Pagination total={filtered.length} page={page} pageSize={pageSize} onPage={setPage} onPageSize={(n) => { setPageSize(n); setPage(1); }} /> : null}

      {filterOpen ? <FilterDrawer eyebrow="Clients" title="Filters" sections={sections} state={fstate} onApply={setFstate} onClose={() => setFilterOpen(false)} /> : null}
    </React.Fragment>
  );
}

Object.assign(window, { ClientsList, BizStatusChip, ActStatusChip, clientTime });
