// MCP Hero — user dashboard (role-adaptive: personal / org-admin / org-editor)
const { useState: useDashState } = React;

const DASH_NAV = [
  { path: '/dashboard', label: 'Overview', icon: 'grid' },
  { path: '/dashboard/mcps', label: 'Installed MCPs', icon: 'box' },
  { path: '/dashboard/usage', label: 'Usage', icon: 'clock' },
  { path: '/dashboard/credits', label: 'Credits', icon: 'wallet', roles: ['personal', 'org-admin'] },
  { path: '/dashboard/keys', label: 'API keys', icon: 'key' },
  { path: '/dashboard/team', label: 'Team', icon: 'users', roles: ['org-admin'] },
  { path: '/dashboard/profile', label: 'Account settings', icon: 'settings' },
];

function BalanceCard({ balance, canTopUp, nav, compact }) {
  const low = balance < 20;
  return (
    <Card style={{
      padding: compact ? '16px 18px' : '20px 22px', display: 'flex', flexDirection: 'column', gap: 4,
      background: 'linear-gradient(135deg, color-mix(in oklch, var(--accent) 10%, var(--surface)), var(--surface) 70%)',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <span style={{ fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '.06em', color: 'var(--text-3)' }}>
          Credit balance
        </span>
      </div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
        <span style={{ fontFamily: 'var(--font-display)', fontSize: compact ? 28 : 34, fontWeight: 800, letterSpacing: '-.02em', color: low ? 'var(--danger)' : 'var(--text)' }}>
          {balance.toLocaleString()}
        </span>
        <span style={{ fontSize: 13.5, color: 'var(--text-3)', fontWeight: 600 }}>credits</span>
      </div>
      {low ? (
        <div style={{ display: 'flex', gap: 7, alignItems: 'center', fontSize: 12.5, fontWeight: 600, color: balance === 0 ? 'var(--danger)' : 'var(--warn)' }}>
          <Icon name="alert" size={13}></Icon>
          {balance === 0 ? 'Zero balance' : 'Low balance'}
        </div>
      ) : null}
      {!compact && canTopUp ? (
        <Btn variant="secondary" size="sm" onClick={() => nav('/dashboard/credits')} style={{ marginTop: 4 }}>Top up</Btn>
      ) : null}
    </Card>
  );
}

// ---------- Out-of-credits blocked state ----------
function mhBlockedRows(acct) {
  return [
    { ts: 'Just now', mcp: 'ssm', tool: 'request_ssm_profile', credits: 10, status: 'insufficient', member: acct.name },
    { ts: '3 min ago', mcp: 'court-search', tool: 'search_cases', credits: 4, status: 'insufficient', member: acct.name },
    { ts: '8 min ago', mcp: 'legal-docs', tool: 'generate_agreement', credits: 6, status: 'insufficient', member: acct.name },
  ];
}

function OutOfCreditsBanner({ nav, balance }) {
  const canTopUp = true; // Real API will determine this
  const toast = useToast();
  const errJson =
`{
  "error": {
    "code": "insufficient_credits",
    "message": "Balance is 0 credits \u2014 request_ssm_profile needs 10.",
    "balance": 0,
    "required": 10,
    "top_up_url": "https://mcp-hero.agmogroup.com/dashboard/credits"
  }
}`;
  return (
    <Card style={{ padding: 0, overflow: 'hidden', marginBottom: 24, border: '1px solid color-mix(in oklch, var(--danger) 38%, var(--border))' }}>
      <div style={{ display: 'flex', gap: 18, padding: '22px 24px', alignItems: 'flex-start', flexWrap: 'wrap', background: 'color-mix(in oklch, var(--danger) 7%, var(--surface))' }}>
        <div style={{ width: 48, height: 48, borderRadius: 14, background: 'var(--danger-bg)', color: 'var(--danger)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
          <Icon name="alert" size={24}></Icon>
        </div>
        <div style={{ flex: 1, minWidth: 260 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
            <h3 style={{ margin: 0, fontFamily: 'var(--font-display)', fontSize: 19, fontWeight: 800, letterSpacing: '-.01em' }}>You’re out of credits</h3>
            <Badge tone="danger">Paid tools paused</Badge>
          </div>
          <p style={{ margin: '6px 0 0', fontSize: 13.5, color: 'var(--text-2)', lineHeight: 1.55, maxWidth: 580 }}>
            {canTopUp
              ? 'Your balance has reached 0, so paid tool calls now return an error to your AI agents until you top up. Free tools keep working as normal.'
              : `The ${user?.organizationName || user?.orgName || 'your organization'} credit pool has reached 0, so paid tool calls are paused for the whole team until an Org Admin tops up. Free tools keep working.`}
          </p>
          <div style={{ display: 'flex', gap: 10, marginTop: 14, flexWrap: 'wrap' }}>
            {canTopUp
              ? <Btn icon="zap" onClick={() => nav('/dashboard/credits')}>Top up now</Btn>
              : <Btn icon="mail" onClick={() => toast('Your Org Admin has been notified')}>Notify Org Admin</Btn>}
            <Btn variant="secondary" onClick={() => nav('/dashboard/usage')}>View blocked calls</Btn>
          </div>
        </div>
      </div>
      <div style={{ padding: '4px 24px 22px' }}>
        <div style={{ fontSize: 11.5, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '.06em', color: 'var(--text-3)', margin: '0 0 8px' }}>What your agent receives</div>
        <CopyBlock label="gateway response · 402 Payment Required" code={errJson}></CopyBlock>
      </div>
    </Card>
  );
}

// ---------- Overview ----------
function DashOverview({ user, nav }) {
  const [loading, setLoading] = React.useState(true);
  const [balance, setBalance] = React.useState(0);
  const [canTopUp, setCanTopUp] = React.useState(false);
  const [usage, setUsage] = React.useState([]);

  // Fetch real organization data on mount
  React.useEffect(() => {
    const fetchOrgData = async () => {
      try {
        // Check if dataService is available
        if (!window.dataService || typeof window.dataService.getOrganizationData !== 'function') {
          console.warn('dataService not available, using default values');
          setBalance(1000); // Default balance
          setCanTopUp(true);
          setLoading(false);
          return;
        }

        const orgData = await window.dataService.getOrganizationData();
        setBalance(orgData.credits || 1000);
        setCanTopUp(orgData.canTopUp !== false); // Default to true
        setLoading(false);
      } catch (error) {
        console.error('Failed to fetch organization data:', error);
        // Set default values if API fails
        setBalance(1000); // Default balance
        setCanTopUp(true);
        setLoading(false);
      }
    };

    fetchOrgData();
  }, []);

  if (loading) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '200px' }}>
        <div style={{
          width: 40, height: 40, borderRadius: '50%',
          border: '3px solid var(--border)', borderTopColor: 'var(--accent)',
          animation: 'spin 1s linear infinite', margin: '0 auto 16px'
        }}></div>
        <div style={{ color: 'var(--text-2)', fontSize: 14 }}>Loading your data...</div>
      </div>
    );
  }

  const firstName = user?.fullName ? user.fullName.split(' ')[0] : 'User';
  const accountType = user?.accountType === 'organization' ? 'Organization' : 'Personal';
  const role = user?.role === 'org_admin' ? 'Admin' : user?.role === 'org_editor' ? 'Editor' : 'Personal';
  const empty = balance === 0;

  // Get user initials for avatar
  const getInitials = (name) => {
    if (!name) return 'U';
    return name
      .split(' ')
      .map(n => n[0])
      .join('')
      .toUpperCase()
      .slice(0, 2);
  };

  const recent = (empty ? mhBlockedRows({ balance }).slice(0, 2).concat(MH_USAGE) : MH_USAGE).slice(0, 5);

  return (
    <div className="mh-anim">
      <SectionHead
        title={`Good morning, ${firstName}`}
        sub={`${accountType} · ${role}`}
        right={<Btn variant="secondary" icon="search" onClick={() => nav('/')}>Browse marketplace</Btn>}
      ></SectionHead>
      {empty ? <OutOfCreditsBanner nav={nav} balance={balance} user={user} /> : null}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 16, marginBottom: 24 }}>
        <BalanceCard balance={balance} canTopUp={canTopUp} nav={nav} compact />
        <StatCard label={user?.accountType === 'organization' ? 'Team members' : 'Installed MCPs'} icon={user?.accountType === 'organization' ? 'users' : 'box'}
          value={user?.teamMembers || user?.installedMcps || (user?.accountType === 'organization' ? '5' : '3')}
          sub={user?.accountType === 'organization' ? (user?.pendingInvites ? `${user.pendingInvites} invite pending` : 'No pending invites') : 'across your AI clients'} />
        <StatCard label={user?.accountType === 'organization' ? 'Org calls this month' : 'Calls this month'} icon="zap" value={user?.callsThisMonth || '1,234'} sub="July 2026" />
        <StatCard label="Account status" icon="check" value={user?.accountStatus || 'Active'} sub={`Since ${user?.memberSince ? new Date(user.memberSince).toLocaleDateString() : new Date().toLocaleDateString()}`} />
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1.7fr) minmax(260px, 1fr)', gap: 20, alignItems: 'flex-start' }}>
        <Card style={{ padding: 0, overflow: 'hidden' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '15px 20px', borderBottom: '1px solid var(--border)' }}>
            <span style={{ fontWeight: 700, fontFamily: 'var(--font-display)', fontSize: 15.5 }}>Recent activity</span>
            <Btn variant="ghost" size="sm" onClick={() => nav('/dashboard/usage')}>View all</Btn>
          </div>
          {recent.map((u, i) => {
            const mcp = mhGetMcp(u.mcp);
            return (
              <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '12px 20px', borderBottom: i < recent.length - 1 ? '1px solid var(--border)' : 'none' }}>
                <McpIcon mcp={mcp} size={32}></McpIcon>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <code style={{ fontFamily: 'var(--font-mono)', fontSize: 12.5, fontWeight: 600 }}>{u.tool}</code>
                  <div style={{ fontSize: 12, color: 'var(--text-3)' }}>{mcp.name} · {u.ts}</div>
                </div>
                {u.status === 'insufficient'
                  ? <Badge tone="danger">Insufficient credits</Badge>
                  : <span style={{ fontSize: 13, fontWeight: 700, color: u.credits === 0 ? 'var(--ok)' : 'var(--text-2)', whiteSpace: 'nowrap' }}>{u.credits === 0 ? 'Free' : '−' + u.credits + ' cr'}</span>}
              </div>
            );
          })}
        </Card>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          {role === 'org-admin' ? (
            <Card style={{ padding: 20 }}>
              <div style={{ fontWeight: 700, fontFamily: 'var(--font-display)', fontSize: 15.5, marginBottom: 12 }}>Top spenders · June</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 11 }}>
                {MH_TEAM.slice(0, 4).map((m) => (
                  <div key={m.email} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                    <Avatar initials={m.initials} size={28} hue={(m.name.length * 47) % 360}></Avatar>
                    <span style={{ flex: 1, fontSize: 13.5, fontWeight: 600 }}>{m.name}</span>
                    <span style={{ fontSize: 13, color: 'var(--text-2)', fontWeight: 700 }}>{m.creditsUsed} cr</span>
                  </div>
                ))}
              </div>
              <Btn variant="ghost" size="sm" style={{ marginTop: 12 }} onClick={() => nav('/dashboard/team')}>Manage team</Btn>
            </Card>
          ) : (
            <Card style={{ padding: 20 }}>
              <div style={{ fontWeight: 700, fontFamily: 'var(--font-display)', fontSize: 15.5, marginBottom: 10 }}>Quick setup</div>
              <p style={{ margin: '0 0 12px', fontSize: 13, color: 'var(--text-2)', lineHeight: 1.55 }}>Grab a config snippet for any installed MCP and paste it into your client.</p>
              <Btn size="sm" variant="secondary" icon="copy" onClick={() => nav('/dashboard/mcps')}>Get config snippets</Btn>
            </Card>
          )}
        </div>
      </div>
    </div>
  );
}

// ---------- Installed MCPs ----------
function InstalledRow({ row, user, expanded, onToggle, nav }) {
  const role = user?.role || 'personal';
  const mcp = mhGetMcp(row.slug);
  const toast = useToast();
  const [modal, setModal] = useDashState(null); // 'rotate' | 'rotated' | 'uninstall'
  const newKey = 'mh_live_' + row.slug.replace(/-/g, '').slice(0, 3) + 'N3wK3yGen9aB4xYz';
  return (
    <Card style={{ padding: 0, overflow: 'hidden' }}>
      <div onClick={onToggle} style={{ display: 'flex', alignItems: 'center', gap: 15, padding: '15px 20px', cursor: 'pointer' }}>
        <McpIcon mcp={mcp} size={40}></McpIcon>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontWeight: 700, fontSize: 15, fontFamily: 'var(--font-display)' }}>{mcp.name}</div>
          <div style={{ fontSize: 12.5, color: 'var(--text-3)' }}>Installed {row.installed} · Last call {row.lastCall}</div>
        </div>
        <div style={{ textAlign: 'right', marginRight: 6 }}>
          <div style={{ fontSize: 13.5, fontWeight: 700 }}>{row.spent} cr</div>
          <div style={{ fontSize: 11.5, color: 'var(--text-3)' }}>spent</div>
        </div>
        <code style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--text-3)', background: 'var(--bg-sunken)', padding: '4px 9px', borderRadius: 7 }}>{row.keyPrefix}…</code>
        <Icon name="chevronDown" size={17} style={{ color: 'var(--text-3)', transform: expanded ? 'rotate(180deg)' : 'none', transition: 'transform .2s ease' }}></Icon>
      </div>
      {expanded ? (
        <div className="mh-anim" style={{ padding: '4px 20px 20px', borderTop: '1px solid var(--border)' }}>
          <div style={{ paddingTop: 16, display: 'flex', flexDirection: 'column', gap: 14 }}>
            <CopyBlock code={mhConfigSnippet(row.slug, row.keyPrefix + '••••••••••••')}></CopyBlock>
            <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
              <Btn variant="secondary" size="sm" icon="refresh" onClick={() => setModal('rotate')}>Rotate key</Btn>
              <Btn variant="secondary" size="sm" icon="external" onClick={() => nav('/mcps/' + row.slug)}>View in marketplace</Btn>
              <Btn variant="danger" size="sm" icon="trash" onClick={() => setModal('uninstall')} style={{ marginLeft: 'auto' }}>Uninstall</Btn>
            </div>
          </div>
        </div>
      ) : null}
      <Modal open={modal === 'rotate'} onClose={() => setModal(null)} title="Rotate API key?">
        <p style={{ margin: '0 0 16px', fontSize: 14, color: 'var(--text-2)', lineHeight: 1.55 }}>
          The current key <code style={{ fontFamily: 'var(--font-mono)', fontSize: 12.5 }}>{row.keyPrefix}…</code> stops working <strong>immediately</strong>. Any client using it will get a 401 until you update the config.
        </p>
        <div style={{ display: 'flex', gap: 10 }}>
          <Btn onClick={() => setModal('rotated')} style={{ flex: 1, justifyContent: 'center' }} icon="refresh">Rotate now</Btn>
          <Btn variant="secondary" onClick={() => setModal(null)}>Cancel</Btn>
        </div>
      </Modal>
      <Modal open={modal === 'rotated'} onClose={() => { setModal(null); toast('Key rotated'); }} title="Here's your new key" width={560}>
        <p style={{ margin: '0 0 14px', fontSize: 14, color: 'var(--text-2)' }}>Copy it now — for security it won't be shown again.</p>
        <CopyBlock code={mhConfigSnippet(row.slug, newKey)}></CopyBlock>
        <Btn style={{ marginTop: 16, width: '100%', justifyContent: 'center' }} onClick={() => { setModal(null); toast('Key rotated'); }}>I've copied it</Btn>
      </Modal>
      <Modal open={modal === 'uninstall'} onClose={() => setModal(null)} title={'Uninstall ' + mcp.name + '?'}>
        <p style={{ margin: '0 0 16px', fontSize: 14, color: 'var(--text-2)', lineHeight: 1.55 }}>
          Its API key is <strong>revoked immediately</strong> and the MCP disappears from your client. You can re-install any time — you'll get a fresh key.
        </p>
        <div style={{ display: 'flex', gap: 10 }}>
          <Btn variant="danger" onClick={() => { setModal(null); toast('MCP uninstalled', 'danger'); }} style={{ flex: 1, justifyContent: 'center' }} icon="trash">Uninstall &amp; revoke key</Btn>
          <Btn variant="secondary" onClick={() => setModal(null)}>Keep it</Btn>
        </div>
      </Modal>
    </Card>
  );
}

function DashMcps({ user, nav, scenario }) {
  const role = user?.role || 'personal';
  const acct = mhAcct(role, scenario);
  const rows = MH_INSTALLED.filter((r) => acct.installedSlugs.includes(r.slug));
  const [open, setOpen] = useDashState(rows.length ? rows[0].slug : null);
  return (
    <div className="mh-anim">
      <SectionHead title="Installed MCPs" sub="Config snippets and keys for every MCP you've installed."
        right={<Btn icon="plus" onClick={() => nav('/')}>Install another</Btn>}></SectionHead>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        {rows.map((r) => (
          <InstalledRow key={r.slug} row={r} user={user} nav={nav} expanded={open === r.slug} onToggle={() => setOpen(open === r.slug ? null : r.slug)}></InstalledRow>
        ))}
      </div>
    </div>
  );
}

// ---------- Usage ----------
function DashUsage({ user, scenario }) {
  const role = user?.role || 'personal';
  const acct = mhAcct(role, scenario);
  const empty = acct.balance === 0;
  const [mcpFilter, setMcpFilter] = useDashState('all');
  const [range, setRange] = useDashState('30d');
  const allRows = role === 'org-admin' ? MH_USAGE : MH_USAGE.filter((u) => u.member === acct.name);
  const mine = empty ? mhBlockedRows(acct).concat(allRows) : allRows;
  const rows = mine.filter((u) => mcpFilter === 'all' || u.mcp === mcpFilter);
  const mcpOptions = [{ value: 'all', label: 'All MCPs' }].concat(
    [...new Set(mine.map((u) => u.mcp))].map((s) => ({ value: s, label: mhGetMcp(s).name }))
  );
  const cols = [{ label: 'When' }, { label: 'MCP' }, { label: 'Tool' }];
  if (role === 'org-admin') cols.push({ label: 'Member' });
  cols.push({ label: 'Credits', align: 'right' }, { label: 'Status', align: 'right' });
  return (
    <div className="mh-anim">
      <SectionHead title="Usage history" sub={role === 'org-admin' ? 'Every tool call across your organization.' : 'Every tool call made with your API keys.'}
        right={
          <div style={{ display: 'flex', gap: 10 }}>
            <Select value={mcpFilter} onChange={setMcpFilter} options={mcpOptions} style={{ padding: '8px 12px', fontSize: 13.5 }}></Select>
            <Segmented size="sm" value={range} onChange={setRange} options={[{ value: '7d', label: '7 days' }, { value: '30d', label: '30 days' }, { value: '90d', label: '90 days' }]}></Segmented>
          </div>
        }></SectionHead>
      {empty ? (
        <div style={{ display: 'flex', gap: 11, alignItems: 'center', padding: '13px 16px', borderRadius: 12, marginBottom: 16, background: 'var(--danger-bg)', color: 'var(--danger)', border: '1px solid color-mix(in oklch, var(--danger) 30%, var(--border))' }}>
          <Icon name="alert" size={17}></Icon>
          <span style={{ fontSize: 13.5, fontWeight: 600 }}>Calls are being blocked — your balance is 0. Paid tools resume the moment you top up.</span>
        </div>
      ) : null}
      <Table cols={cols}>
        {rows.map((u, i) => {
          const mcp = mhGetMcp(u.mcp);
          return (
            <Tr key={i}>
              <Td style={{ whiteSpace: 'nowrap', color: 'var(--text-3)' }}>{u.ts}</Td>
              <Td><span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontWeight: 600, color: 'var(--text)' }}><McpIcon mcp={mcp} size={22}></McpIcon>{mcp.name}</span></Td>
              <Td><code style={{ fontFamily: 'var(--font-mono)', fontSize: 12.5 }}>{u.tool}</code></Td>
              {role === 'org-admin' ? <Td>{u.member}</Td> : null}
              <Td align="right" style={{ fontWeight: 700, color: u.credits === 0 ? 'var(--ok)' : 'var(--text)' }}>{u.status === 'insufficient' ? '—' : u.credits === 0 ? 'Free' : '−' + u.credits}</Td>
              <Td align="right">{u.status === 'insufficient' ? <Badge tone="danger">Insufficient</Badge> : <Badge tone="ok">OK</Badge>}</Td>
            </Tr>
          );
        })}
      </Table>
      <div style={{ display: 'flex', justifyContent: 'center', gap: 8, marginTop: 16 }}>
        <Btn variant="secondary" size="sm" disabled>Previous</Btn>
        <Btn variant="secondary" size="sm">Next page</Btn>
      </div>
    </div>
  );
}

// ---------- Credits ----------
function DashCredits({ user, nav, scenario }) {
  const role = user?.role || 'personal';
  const acct = mhAcct(role, scenario);
  const [selected, setSelected] = useDashState('standard');
  const toast = useToast();
  return (
    <div className="mh-anim">
      <SectionHead title="Credits" sub={role === 'org-admin' ? `Shared pool for everyone at ${acct.orgName}.` : 'Your private credit wallet.'}></SectionHead>
      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(260px, 1fr) minmax(0, 2fr)', gap: 20, alignItems: 'flex-start', marginBottom: 26 }}>
        <BalanceCard balance={acct.balance} canTopUp={role !== 'org-editor'} nav={nav} compact={false}></BalanceCard>
        <Card style={{ padding: 22 }}>
          <div style={{ fontWeight: 700, fontFamily: 'var(--font-display)', fontSize: 15.5, marginBottom: 14 }}>Top up</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(140px, 1fr))', gap: 10, marginBottom: 16 }}>
            {MH_PACKAGES.filter((p) => p.id !== 'custom').map((p) => {
              const active = selected === p.id;
              return (
                <button key={p.id} onClick={() => setSelected(p.id)} style={{
                  padding: '13px 14px', borderRadius: 12, cursor: 'pointer', textAlign: 'left', transition: 'all .15s ease',
                  border: `2px solid ${active ? 'var(--accent)' : 'var(--border)'}`,
                  background: active ? 'color-mix(in oklch, var(--accent) 7%, var(--bg-raised))' : 'var(--bg-raised)',
                }}>
                  <div style={{ fontWeight: 700, fontSize: 13.5, color: 'var(--text-2)' }}>{p.name}</div>
                  <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 19, color: 'var(--text)' }}>RM {p.price}</div>
                  <div style={{ fontSize: 12.5, color: 'var(--text-2)', fontWeight: 600 }}>{p.credits.toLocaleString()} cr {p.bonus ? <span style={{ color: 'var(--ok)' }}>{p.bonus}</span> : null}</div>
                </button>
              );
            })}
          </div>
          <Btn icon="zap" onClick={() => toast('Redirecting to Stripe checkout…')}>Pay RM {MH_PACKAGES.find((p) => p.id === selected).price} · get {MH_PACKAGES.find((p) => p.id === selected).credits.toLocaleString()} credits</Btn>
        </Card>
      </div>
      <SectionHead title="Transaction history" sub="Org-level top-ups, newest first."></SectionHead>
      <Table cols={[{ label: 'Date' }, { label: 'Package' }, { label: 'Amount' }, { label: 'Credits', align: 'right' }, { label: 'Gateway' }, { label: 'Status', align: 'right' }]}>
        {MH_TRANSACTIONS.map((t, i) => (
          <Tr key={i}>
            <Td style={{ whiteSpace: 'nowrap' }}>{t.date}</Td>
            <Td style={{ fontWeight: 600, color: 'var(--text)' }}>{t.pkg}</Td>
            <Td>RM {t.amount}</Td>
            <Td align="right" style={{ fontWeight: 700, color: t.credits ? 'var(--ok)' : 'var(--text-3)' }}>{t.credits ? '+' + t.credits.toLocaleString() : '—'}</Td>
            <Td>{t.gateway}</Td>
            <Td align="right">{t.status === 'paid' ? <Badge tone="ok">Paid</Badge> : <Badge tone="warn">Abandoned</Badge>}</Td>
          </Tr>
        ))}
      </Table>
    </div>
  );
}

// ---------- API keys ----------
function DashKeys({ user }) {
  const role = user?.role || 'personal';
  const toast = useToast();
  const active = MH_KEYS.filter((k) => k.status === 'active');
  const revoked = MH_KEYS.filter((k) => k.status === 'revoked');
  const teamKeys = role === 'org-admin' ? [
    { mcp: 'court-search', prefix: 'mh_live_z3Jd', created: '8 May 2026', lastUsed: 'Today, 09:18', owner: 'Daniel Wong', status: 'active' },
    { mcp: 'legal-docs', prefix: 'mh_live_m7Cb', created: '12 May 2026', lastUsed: '4 Jun 2026', owner: 'Mei Chen', status: 'active' },
    { mcp: 'watchlist', prefix: 'mh_live_q9Fs', created: '20 May 2026', lastUsed: 'Today, 08:02', owner: 'Sarah Lim', status: 'active' },
  ] : [];
  const KeyTable = ({ rows, showOwner }) => (
    <Table cols={[{ label: 'MCP' }, { label: 'Key' }].concat(showOwner ? [{ label: 'Member' }] : []).concat([{ label: 'Created' }, { label: 'Last used' }, { label: '', align: 'right' }])}>
      {rows.map((k, i) => {
        const mcp = mhGetMcp(k.mcp);
        return (
          <Tr key={i}>
            <Td><span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontWeight: 600, color: 'var(--text)' }}><McpIcon mcp={mcp} size={22}></McpIcon>{mcp.name}</span></Td>
            <Td><code style={{ fontFamily: 'var(--font-mono)', fontSize: 12.5, background: 'var(--bg-sunken)', padding: '3px 8px', borderRadius: 6 }}>{k.prefix}…</code></Td>
            {showOwner ? <Td>{k.owner}</Td> : null}
            <Td style={{ whiteSpace: 'nowrap' }}>{k.created}</Td>
            <Td style={{ whiteSpace: 'nowrap' }}>{k.lastUsed}</Td>
            <Td align="right">
              <span style={{ display: 'inline-flex', gap: 6 }}>
                <Btn variant="secondary" size="sm" icon="refresh" onClick={() => toast('Key rotated — copy the new key from Installed MCPs')}>Rotate</Btn>
                <Btn variant="danger" size="sm" onClick={() => toast('Key revoked', 'danger')}>Revoke</Btn>
              </span>
            </Td>
          </Tr>
        );
      })}
    </Table>
  );
  return (
    <div className="mh-anim">
      <SectionHead title="API keys" sub="Every key is scoped to one MCP and one account. Rotate immediately if a key leaks."></SectionHead>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 28 }}>
        <div>
          <div style={{ fontWeight: 700, fontSize: 14, marginBottom: 10, color: 'var(--text-2)' }}>Your active keys · {active.length}</div>
          <KeyTable rows={active}></KeyTable>
        </div>
        {role === 'org-admin' ? (
          <div>
            <div style={{ fontWeight: 700, fontSize: 14, marginBottom: 10, color: 'var(--text-2)', display: 'flex', alignItems: 'center', gap: 8 }}>
              Team members' keys · {teamKeys.length}
              <Badge tone="accent">Org Admin</Badge>
            </div>
            <KeyTable rows={teamKeys} showOwner></KeyTable>
          </div>
        ) : null}
        <div>
          <div style={{ fontWeight: 700, fontSize: 14, marginBottom: 10, color: 'var(--text-3)' }}>Revoked</div>
          <Table cols={[{ label: 'MCP' }, { label: 'Key' }, { label: 'Created' }, { label: 'Revoked', align: 'right' }]}>
            {revoked.map((k, i) => {
              const mcp = mhGetMcp(k.mcp);
              return (
                <Tr key={i}>
                  <Td style={{ color: 'var(--text-3)' }}>{mcp.name}</Td>
                  <Td><code style={{ fontFamily: 'var(--font-mono)', fontSize: 12.5, color: 'var(--text-3)', textDecoration: 'line-through' }}>{k.prefix}…</code></Td>
                  <Td style={{ color: 'var(--text-3)' }}>{k.created}</Td>
                  <Td align="right" style={{ color: 'var(--text-3)' }}>{k.revokedAt}</Td>
                </Tr>
              );
            })}
          </Table>
        </div>
      </div>
    </div>
  );
}

// ---------- Team (org admin) ----------
function DashTeam({ user, nav }) {
  const toast = useToast();
  const [inviteOpen, setInviteOpen] = useDashState(false);
  const [inviteEmail, setInviteEmail] = useDashState('');
  const [inviteRole, setInviteRole] = useDashState('Editor');
  const [confirmRemove, setConfirmRemove] = useDashState(null);
  return (
    <div className="mh-anim">
      <SectionHead title="Team" sub="Kapital Partners · 5 members, 1 pending invite."
        right={<Btn icon="plus" onClick={() => setInviteOpen(true)}>Invite member</Btn>}></SectionHead>
      <Table cols={[{ label: 'Member' }, { label: 'Role' }, { label: 'Joined' }, { label: 'Last active' }, { label: 'Credits used · Jun', align: 'right' }, { label: '', align: 'right' }]}>
        {MH_TEAM.map((m, i) => (
          <Tr key={i}>
            <Td>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 10 }}>
                <Avatar initials={m.initials} size={32} hue={(m.name.length * 47) % 360}></Avatar>
                <span>
                  <span style={{ display: 'block', fontWeight: 700, color: 'var(--text)' }}>{m.name}</span>
                  <span style={{ display: 'block', fontSize: 12, color: 'var(--text-3)' }}>{m.email}</span>
                </span>
              </span>
            </Td>
            <Td>
              <Select value={m.role} onChange={(v) => toast(`${m.name} is now ${v === 'Admin' ? 'an Admin' : 'an Editor'}`)} options={['Admin', 'Editor']} style={{ padding: '5px 9px', fontSize: 13 }}></Select>
            </Td>
            <Td style={{ whiteSpace: 'nowrap' }}>{m.joined}</Td>
            <Td style={{ whiteSpace: 'nowrap' }}>{m.lastActive}</Td>
            <Td align="right" style={{ fontWeight: 700, color: 'var(--text)' }}>{m.creditsUsed}</Td>
            <Td align="right">
              <Btn variant="ghost" size="sm" icon="trash" title={i === 0 ? 'Org must keep at least one Admin' : 'Remove member'} onClick={() => i === 0 ? toast('Organization must have at least one admin', 'danger') : setConfirmRemove(m)}></Btn>
            </Td>
          </Tr>
        ))}
      </Table>
      <div style={{ marginTop: 26 }}>
        <div style={{ fontWeight: 700, fontSize: 14, marginBottom: 10, color: 'var(--text-2)' }}>Pending invitations</div>
        <Table cols={[{ label: 'Email' }, { label: 'Role' }, { label: 'Invited' }, { label: 'Expires' }, { label: '', align: 'right' }]}>
          {MH_PENDING_INVITES.map((p, i) => (
            <Tr key={i}>
              <Td style={{ fontWeight: 600, color: 'var(--text)' }}>{p.email} <Badge tone="warn" style={{ marginLeft: 8 }}>Pending</Badge></Td>
              <Td>{p.role}</Td>
              <Td>{p.invited}</Td>
              <Td>{p.expires}</Td>
              <Td align="right">
                <span style={{ display: 'inline-flex', gap: 6 }}>
                  <Btn variant="secondary" size="sm" onClick={() => toast('Invitation resent')}>Resend</Btn>
                  <Btn variant="ghost" size="sm" onClick={() => toast('Invitation cancelled', 'danger')}>Cancel</Btn>
                </span>
              </Td>
            </Tr>
          ))}
        </Table>
      </div>
      <Modal open={inviteOpen} onClose={() => setInviteOpen(false)} title="Invite a member">
        <div style={{ display: 'flex', flexDirection: 'column', gap: 15 }}>
          <Field label="Email"><TextInput value={inviteEmail} onChange={setInviteEmail} placeholder="teammate@kapitalpartners.my" type="email"></TextInput></Field>
          <Field label="Role">
            <Segmented value={inviteRole} onChange={setInviteRole} options={['Admin', 'Editor']}></Segmented>
          </Field>
          <p style={{ margin: 0, fontSize: 12.5, color: 'var(--text-3)', lineHeight: 1.5 }}>
            {inviteRole === 'Admin' ? 'Admins manage members, billing and the credit pool — and can use MCPs.' : 'Editors install and use MCPs, drawing from the org pool. No billing or team access.'} The invite link expires in 48 hours.
          </p>
          <Btn size="lg" disabled={!inviteEmail.includes('@')} onClick={() => { setInviteOpen(false); toast('Invitation sent to ' + inviteEmail); setInviteEmail(''); }} style={{ justifyContent: 'center' }} icon="mail">Send invitation</Btn>
        </div>
      </Modal>
      <Modal open={!!confirmRemove} onClose={() => setConfirmRemove(null)} title={confirmRemove ? 'Remove ' + confirmRemove.name + '?' : ''}>
        {confirmRemove ? (
          <div>
            <p style={{ margin: '0 0 16px', fontSize: 14, color: 'var(--text-2)', lineHeight: 1.55 }}>
              Their account is deactivated and <strong>all their API keys are revoked immediately</strong>. Usage history is kept for reporting. They'll be notified by email.
            </p>
            <div style={{ display: 'flex', gap: 10 }}>
              <Btn variant="danger" icon="trash" onClick={() => { toast(confirmRemove.name + ' removed from org', 'danger'); setConfirmRemove(null); }} style={{ flex: 1, justifyContent: 'center' }}>Remove member</Btn>
              <Btn variant="secondary" onClick={() => setConfirmRemove(null)}>Keep</Btn>
            </div>
          </div>
        ) : null}
      </Modal>
    </div>
  );
}

// ---------- Dashboard shell ----------
function DashboardShell({ route, user, nav }) {
  if (!user) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '50vh' }}>
        <div style={{ textAlign: 'center' }}>
          <div style={{
            width: 40, height: 40, borderRadius: '50%',
            border: '3px solid var(--border)', borderTopColor: 'var(--accent)',
            animation: 'spin 1s linear infinite', margin: '0 auto 16px'
          }}></div>
          <div style={{ color: 'var(--text-2)', fontSize: 14 }}>Loading user data...</div>
        </div>
      </div>
    );
  }

  // Get user initials from fullName
  const getInitials = (name) => {
    if (!name) return 'U';
    return name
      .split(' ')
      .map(n => n[0])
      .join('')
      .toUpperCase()
      .slice(0, 2);
  };

  const initials = getInitials(user.fullName);
  const role = user.role || 'personal'; // Default to personal if no role

  // Filter navigation items based on user role
  const items = DASH_NAV.filter((n) => !n.roles || n.roles.includes(role));

  let screen = <DashOverview user={user} nav={nav}></DashOverview>;
  if (route === '/dashboard/mcps') screen = <DashMcps user={user} nav={nav}></DashMcps>;
  if (route === '/dashboard/usage') screen = <DashUsage user={user} nav={nav}></DashUsage>;
  if (route === '/dashboard/credits') screen = role === 'org-editor' ? <DashOverview user={user} nav={nav}></DashOverview> : <DashCredits user={user} nav={nav}></DashCredits>;
  if (route === '/dashboard/keys') screen = <DashKeys user={user} nav={nav}></DashKeys>;
  if (route === '/dashboard/team') screen = role === 'org-admin' ? <DashTeam user={user} nav={nav}></DashTeam> : <DashOverview user={user} nav={nav}></DashOverview>;
  if (route === '/dashboard/profile') screen = <DashProfile user={user} nav={nav}></DashProfile>;

  return (
    <div data-screen-label={'Dashboard — ' + route} style={{ display: 'flex', maxWidth: 1240, margin: '0 auto', padding: '24px 28px 80px', gap: 30, alignItems: 'flex-start' }}>
      <nav style={{ width: 212, flexShrink: 0, position: 'sticky', top: 88, display: 'flex', flexDirection: 'column', gap: 3 }}>
        <button onClick={() => nav('/dashboard/profile')} title="Account settings" style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px', marginBottom: 10, borderRadius: 12, background: route === '/dashboard/profile' ? 'color-mix(in oklch, var(--accent) 11%, transparent)' : 'var(--bg-sunken)', border: `1px solid ${route === '/dashboard/profile' ? 'color-mix(in oklch, var(--accent) 30%, var(--border))' : 'var(--border)'}`, cursor: 'pointer', width: '100%', textAlign: 'left', transition: 'all .13s ease' }}>
          <Avatar initials={initials} size={32} hue={(user.fullName?.length || 1) * 47 % 360}></Avatar>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontWeight: 700, fontSize: 13.5, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{user.fullName || 'User'}</div>
            <div style={{ fontSize: 11.5, color: 'var(--text-3)', whiteSpace: 'nowrap' }}>
              {user.accountType === 'organization' ? 'Organization · ' + (role === 'org_admin' ? 'Admin' : 'Editor') : 'Personal Account'}
            </div>
          </div>
          <Icon name="chevronRight" size={15} style={{ color: 'var(--text-3)', marginLeft: 'auto' }}></Icon>
        </button>
        {items.map((n) => {
          const active = route === n.path;
          return (
            <button key={n.path} onClick={() => nav(n.path)} style={{
              display: 'flex', alignItems: 'center', gap: 11, padding: '9px 12px', borderRadius: 10,
              border: 'none', cursor: 'pointer', fontSize: 14, fontWeight: 600, textAlign: 'left',
              background: active ? 'color-mix(in oklch, var(--accent) 11%, transparent)' : 'transparent',
              color: active ? 'var(--accent)' : 'var(--text-2)', transition: 'all .13s ease',
            }}>
              <Icon name={n.icon} size={16}></Icon>{n.label}
            </button>
          );
        })}
        <div style={{ borderTop: '1px solid var(--border)', marginTop: 10, paddingTop: 10 }}>
          <button onClick={() => window.handleLogout && window.handleLogout(nav)} style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '9px 12px', borderRadius: 10, border: 'none', cursor: 'pointer', fontSize: 14, fontWeight: 600, background: 'transparent', color: 'var(--text-3)', width: '100%', textAlign: 'left' }}>
            <Icon name="logout" size={16}></Icon>Log out
          </button>
        </div>
      </nav>
      <main style={{ flex: 1, minWidth: 0 }}>{screen}</main>
    </div>
  );
}

Object.assign(window, { DashboardShell });
