import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import Layout from '../components/Layout';
import { supabase } from '../lib/supabase';
import { useAuth } from '../context/AuthContext';
import { readPageCache, writePageCache } from '../lib/pageCache';
import { withTimeout } from '../lib/withTimeout';
import SortTh from '../components/SortTh';
import { useSortable } from '../hooks/useSortable';

const ICON_TONES = [
  { bg: 'rgba(245,165,35,0.15)', color: '#F5A523' },
  { bg: 'rgba(74,222,128,0.15)', color: '#4ade80' },
  { bg: 'rgba(96,165,250,0.15)', color: '#60a5fa' },
  { bg: 'rgba(167,139,250,0.15)', color: '#a78bfa' },
];

function iconTone(key) {
  let h = 0;
  for (let i = 0; i < (key || '').length; i++) h = (h * 31 + key.charCodeAt(i)) % ICON_TONES.length;
  return ICON_TONES[h];
}

function InitialPortrait({ name }) {
  const tone = iconTone(name);
  return (
    <div style={{ width: 27, height: 27, borderRadius: '50%', background: tone.bg, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
      <span style={{ fontSize: 12, fontWeight: 500, color: tone.color, lineHeight: 1 }}>{(name || '?')[0].toUpperCase()}</span>
    </div>
  );
}

function ExternalDashboard({ currentUser, projects, tasks, pos, submissions, clientProfiles, companyMemberships }) {
  const myTasks = tasks.filter(t => t.assigned_to === currentUser?.id);
  const myActiveTasks = myTasks.filter(t => !['client_approved', 'on_hold'].includes(t.status));
  const myCompleted = myTasks.filter(t => t.status === 'client_approved');
  const myCompletedRevisions = myCompleted.reduce((sum, t) => sum + Number(t.current_version || 0), 0);
  const myOnHold = myTasks.filter(t => t.status === 'on_hold');
  const myAssignedProjectCount = new Set(myTasks.map(t => t.project_id).filter(Boolean)).size;
  const unpaidAmount = pos.filter(p => !['paid', 'cancelled'].includes(p.status)).reduce((s, p) => s + Number(p.amount || 0), 0);
  const paidAmount = pos.filter(p => p.status === 'paid').reduce((s, p) => s + Number(p.amount || 0), 0);

  const myProjectIds = new Set(myTasks.map(t => t.project_id).filter(Boolean));
  const myProjects = myProjectIds.size > 0
    ? projects.filter(p => myProjectIds.has(p.id))
    : projects;
  const companyById = Object.fromEntries(myProjects.filter(p => p.company).map(p => [p.company_id, p.company]));
  const myProjectIdSet = new Set(myProjects.map(p => p.id));
  const activityEvents = buildActivityEvents(submissions, myProjectIdSet);
  const externalHighlights = buildClientHighlights(Object.values(companyById), myProjects, tasks, clientProfiles, companyMemberships || [])
    .sort((a, b) => b.openTaskCount - a.openTaskCount || a.company.name.localeCompare(b.company.name))
    .slice(0, 5);
  return (
    <Layout>
      <div className="dash-stat-grid">
        <DashStatCard label="Active Tasks" value={myActiveTasks.length} sub={`${myOnHold.length} on hold`} iconBg="rgba(96,165,250,0.15)" iconColor="#60a5fa" iconPath={DASH_ICONS.tasks} />
        <DashStatCard label="Completed Tasks" value={myCompleted.length} sub={`${myCompletedRevisions} total revisions`} iconBg="rgba(74,222,128,0.15)" iconColor="#4ade80" iconPath={DASH_ICONS.trending} />
        <DashStatCard label="Active Projects" value={myProjects.length} sub={`${myAssignedProjectCount} assigned to me`} iconBg="rgba(167,139,250,0.15)" iconColor="#a78bfa" iconPath={DASH_ICONS.projects} />
        <DashStatCard label="Pending Payment" value={fmtMoney(unpaidAmount)} sub={`${fmtMoney(paidAmount)} paid`} iconBg="rgba(245,165,35,0.15)" iconColor="#F5A523" iconPath={DASH_ICONS.invoice} />
      </div>
      <div className="dashboard-bottom-grid">
        <ActivityFeed events={activityEvents} />
        {myProjects.length > 0 && <ClientHighlightTable highlights={externalHighlights} />}
      </div>
    </Layout>
  );
}

// ─── Shared dashboard helpers ──────────────────────────────────────────────

const ACTION_ICON = {
  task_started:       { bg: 'rgba(96,165,250,0.15)',  color: '#60a5fa', path: <polygon points="6,4 20,12 6,20" fill="currentColor"/> },
  task_resumed:       { bg: 'rgba(96,165,250,0.15)',  color: '#60a5fa', path: <polygon points="6,4 20,12 6,20" fill="currentColor"/> },
  task_submitted:     { bg: 'rgba(74,222,128,0.15)',  color: '#4ade80', path: <><line x1="12" y1="19" x2="12" y2="5" strokeWidth="2" strokeLinecap="round"/><polyline points="5,12 12,5 19,12" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" fill="none"/></> },
  task_approved:      { bg: 'rgba(74,222,128,0.15)',  color: '#4ade80', path: <polyline points="4,13 9,18 20,7" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" fill="none"/> },
  task_on_hold:       { bg: 'rgba(239,68,68,0.15)',   color: '#ef4444', path: <><rect x="6" y="4" width="4" height="16" rx="1" fill="currentColor"/><rect x="14" y="4" width="4" height="16" rx="1" fill="currentColor"/></> },
  task_created:       { bg: 'rgba(167,139,250,0.15)', color: '#a78bfa', path: <><line x1="12" y1="5" x2="12" y2="19" strokeWidth="2" strokeLinecap="round"/><line x1="5" y1="12" x2="19" y2="12" strokeWidth="2" strokeLinecap="round"/></> },
  project_created:    { bg: 'rgba(245,165,35,0.15)',  color: '#F5A523', path: <><path d="M3 7a2 2 0 012-2h4l2 2h8a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" fill="none" strokeWidth="1.5"/></> },
  request_submitted:  { bg: 'rgba(167,139,250,0.15)', color: '#a78bfa', path: <><rect x="5" y="3" width="14" height="18" rx="2" fill="none" strokeWidth="1.5"/><line x1="9" y1="8" x2="15" y2="8" strokeWidth="1.5" strokeLinecap="round"/><line x1="9" y1="12" x2="15" y2="12" strokeWidth="1.5" strokeLinecap="round"/><line x1="9" y1="16" x2="12" y2="16" strokeWidth="1.5" strokeLinecap="round"/></> },
  revision_requested: { bg: 'rgba(245,158,11,0.15)',  color: '#f59e0b', path: <><path d="M4 12a8 8 0 018-8v0a8 8 0 018 8" fill="none" strokeWidth="1.5" strokeLinecap="round"/><polyline points="18,8 20,12 16,12" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" fill="none"/></> },
};
function ActionIcon({ actionKey, size = 27 }) {
  const cfg = ACTION_ICON[actionKey] || { bg: 'rgba(255,255,255,0.08)', color: 'rgba(255,255,255,0.4)', path: <circle cx="12" cy="12" r="3" fill="currentColor"/> };
  return (
    <div style={{ width: size, height: size, borderRadius: '50%', background: cfg.bg, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <svg width="13" height="13" viewBox="0 0 24 24" stroke={cfg.color} fill="none" style={{ color: cfg.color }}>{cfg.path}</svg>
    </div>
  );
}

const ACTION_LABEL = {
  task_created: 'created',
  task_started: 'started',
  task_on_hold: 'put on hold',
  task_resumed: 'resumed',
  task_submitted: 'submitted',
  task_approved: 'approved',
  project_created: 'created project',
  request_submitted: 'submitted',
  revision_requested: 'requested revision on',
};

function buildActivityEvents(activityData, projectIdSet = null) {
  return (activityData || [])
    .filter(e => !projectIdSet || !e.project_id || projectIdSet.has(e.project_id))
    .map(e => ({
      time: new Date(e.created_at),
      name: e.actor_name || 'Fourge',
      actionKey: e.action,
      action: ACTION_LABEL[e.action] || e.action,
      task: e.task_title || null,
      project: e.project_name || null,
    })).filter(e => !isNaN(e.time)).slice(0, 10);
}

function buildClientHighlights(companies, projects, tasks, clientProfiles, companyMemberships = [], invoices = []) {
  const doneStatuses = ['client_approved', 'invoiced', 'paid'];
  return (companies || []).map(company => {
    const companyProjects = (projects || []).filter(p => p.company_id === company.id);
    const primaryContact = (clientProfiles || []).find(p =>
      p.company_id === company.id ||
      (companyMemberships || []).some(m => m.company_id === company.id && m.profile_id === p.id)
    );
    const openTasks = (tasks || []).filter(t => companyProjects.some(p => p.id === t.project_id) && !doneStatuses.includes(t.status));
    const companyInvoices = (invoices || []).filter(i => i.company_id === company.id);
    const outstandingTotal = companyInvoices.filter(i => i.status === 'sent').reduce((s, i) => s + Number(i.total || 0), 0);
    const paidTotal = companyInvoices.filter(i => i.status === 'paid').reduce((s, i) => s + Number(i.total || 0), 0);
    return { company, primaryContact, projectCount: companyProjects.length, openTaskCount: openTasks.length, outstandingTotal, paidTotal };
  });
}

function fmtMoney(n) {
  if (Math.abs(n) >= 1000000) return `$${(n / 1000000).toFixed(2)}M`;
  if (Math.abs(n) >= 10000) return `$${(n / 1000).toFixed(1)}k`;
  return `$${Number(n).toFixed(2)}`;
}

function smoothCurve(pts) {
  if (pts.length < 2) return '';
  let d = `M${pts[0][0].toFixed(1)},${pts[0][1].toFixed(1)}`;
  for (let i = 1; i < pts.length; i++) {
    const [x0, y0] = pts[i - 1];
    const [x1, y1] = pts[i];
    const cpX = (x0 + x1) / 2;
    d += ` C${cpX.toFixed(1)},${y0.toFixed(1)} ${cpX.toFixed(1)},${y1.toFixed(1)} ${x1.toFixed(1)},${y1.toFixed(1)}`;
  }
  return d;
}

function MiniAreaChart({ data }) {
  const W = 90, H = 42;
  if (!data || data.length < 2) return null;
  const max = Math.max(...data, 1);
  const pts = data.map((v, i) => [
    (i / (data.length - 1)) * W,
    4 + (1 - v / max) * (H - 8),
  ]);
  const line = smoothCurve(pts);
  const lastPt = pts[pts.length - 1];
  const firstPt = pts[0];
  const area = `${line} L${lastPt[0].toFixed(1)},${H} L${firstPt[0].toFixed(1)},${H} Z`;
  return (
    <svg width="100%" height={H} viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" style={{ display: 'block', overflow: 'hidden' }}>
      <defs>
        <linearGradient id="areaGrad" x1="0" y1="0" x2="0" y2="1">
          <stop offset="5%" stopColor="#F5A523" stopOpacity="0.3" />
          <stop offset="95%" stopColor="#F5A523" stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={area} fill="url(#areaGrad)" />
      <path d={line} fill="none" stroke="#F5A523" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function DashStatCard({ label, value, sub, iconBg, iconColor, iconPath, chartData }) {
  return (
    <div style={{ background: 'var(--card-bg)', backdropFilter: 'blur(12px)', WebkitBackdropFilter: 'blur(12px)', border: '1px solid var(--border)', borderRadius: 8, padding: '18px 21px', display: 'flex', alignItems: 'stretch', gap: 21, minHeight: 120 }}>
      <div style={{ flexShrink: 0, display: 'flex', flexDirection: 'column', ...(chartData ? {} : { flex: 1 }) }}>
        <div style={{ fontSize: 11, fontWeight: 500, color: 'rgba(255,255,255,0.7)', letterSpacing: 0.8, textTransform: 'uppercase', marginBottom: 5 }}>{label}</div>
        <div style={{ flex: 1, display: 'flex', alignItems: 'center' }}>
          <div style={{ fontSize: 30, fontWeight: 400, color: '#ffffff', letterSpacing: -0.5, lineHeight: 1.1 }}>{value}</div>
        </div>
        {sub && <div style={{ fontSize: 12, color: 'rgba(255,255,255,0.5)', marginTop: 5 }}>{sub}</div>}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', justifyContent: 'space-between', ...(chartData ? { flex: 1, minWidth: 0 } : { flexShrink: 0 }) }}>
        <div style={{ width: 27, height: 27, borderRadius: '50%', background: iconBg, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke={iconColor} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" dangerouslySetInnerHTML={{ __html: iconPath }} />
        </div>
        {chartData && <MiniAreaChart data={chartData} />}
      </div>
    </div>
  );
}

const DASH_ICONS = {
  revenue: '<line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6"/>',
  projects: '<path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"/>',
  tasks: '<path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2h11"/>',
  invoice: '<rect x="2" y="2" width="20" height="20" rx="2"/><line x1="12" y1="6" x2="12" y2="18"/><path d="M16 8H9.5a2.5 2.5 0 000 5h5a2.5 2.5 0 010 5H8"/>',
  trending: '<polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/><polyline points="17 6 23 6 23 12"/>',
  profit: '<line x1="12" y1="20" x2="12" y2="4"/><polyline points="5 11 12 4 19 11"/>',
};

function StatBar({ items }) {
  return (
    <div className="stat-bar">
      {items.map((item, i) => (
        <div key={i} className="stat-bar-item">
          <div className="stat-bar-header">
            <div className="stat-bar-label">{item.label}</div>
            <div className="stat-bar-dot" style={{ background: item.color }} />
          </div>
          <div className="stat-bar-value">{item.value}</div>
        </div>
      ))}
    </div>
  );
}

function TaskFeed({ title, tasks, projects, emptyMessage }) {
  const navigate = useNavigate();
  return (
    <div className="card" style={{ padding: 0, overflow: 'hidden', borderRadius: 4, flexShrink: 0 }}>
      <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', background: 'var(--card-bg-2)', display: 'flex', alignItems: 'center', gap: 8 }}>
        <span style={{ fontSize: 13, fontWeight: 400, color: 'var(--text-primary)' }}>{title}</span>
        {tasks.length > 0 && <span style={{ fontSize: 11, fontWeight: 400, padding: '1px 7px', borderRadius: 20, background: 'var(--accent)', color: '#1a1a1a' }}>{tasks.length}</span>}
      </div>
      {tasks.length === 0 ? (
        <div style={{ padding: 24, textAlign: 'center', color: 'var(--text-muted)', fontSize: 13 }}>{emptyMessage}</div>
      ) : tasks.map((task, i) => {
        const project = projects.find(p => p.id === task.project_id);
        return (
          <div key={task.id} onClick={() => navigate(`/requests/${task.id}`)} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, padding: '10px 16px', borderBottom: i < tasks.length - 1 ? '1px solid var(--border)' : 'none', cursor: 'pointer' }}>
            <div style={{ minWidth: 0 }}>
              <div style={{ fontSize: 13, fontWeight: 400, color: 'var(--text-primary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{task.title}</div>
              {project && <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 2 }}>{project.name}</div>}
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-muted)', whiteSpace: 'nowrap', flexShrink: 0 }}>
              {task.assigned_name ? <>Assigned to <span style={{ color: 'var(--text-primary)' }}>{task.assigned_name}</span></> : 'Unassigned'}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function ActivityFeed({ events }) {
  const visible = events.slice(0, 5);
  return (
    <div style={{ background: 'var(--card-bg)', backdropFilter: 'blur(12px)', WebkitBackdropFilter: 'blur(12px)', border: '1px solid var(--border)', borderRadius: 8, padding: '18px 21px', flexShrink: 0 }}>
      <div style={{ marginBottom: visible.length > 0 ? 14 : 0 }}>
        <span style={{ fontSize: 11, fontWeight: 500, color: 'rgba(255,255,255,0.7)', letterSpacing: 0.8, textTransform: 'uppercase' }}>Recent Activity</span>
      </div>
      {visible.length === 0 ? (
        <div style={{ fontSize: 13, color: 'rgba(255,255,255,0.5)', marginTop: 14 }}>No recent activity</div>
      ) : visible.map((e, i) => (
        <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: i > 0 ? 10 : 0 }}>
          <ActionIcon actionKey={e.actionKey} />
          <div style={{ flex: 1, minWidth: 0, fontSize: 13, lineHeight: 1.4 }}>
            <span style={{ color: '#ffffff', fontWeight: 400 }}>{e.name}</span>
            {e.action && <span style={{ color: 'rgba(255,255,255,0.5)' }}> {e.action}</span>}
            {e.task && <span style={{ color: '#ffffff' }}> {e.task}</span>}
          </div>
          <span style={{ fontSize: 11, color: 'rgba(255,255,255,0.5)', whiteSpace: 'nowrap', flexShrink: 0 }}>{e.time.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}</span>
        </div>
      ))}
    </div>
  );
}

function ClientHighlightTable({ highlights }) {
  const { sortKey, sortDir, toggle, sort } = useSortable('company');
  if (!highlights || highlights.length === 0) return null;
  const fmtMoney = (n) => `$${Number(n || 0).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
  const sortedHighlights = sort(highlights, (row, key) => {
    if (key === 'company') return row.company?.name || '';
    if (key === 'primaryContact') return row.primaryContact?.name || '';
    if (key === 'projectCount') return row.projectCount || 0;
    if (key === 'openTaskCount') return row.openTaskCount || 0;
    if (key === 'outstandingTotal') return Number(row.outstandingTotal || 0);
    if (key === 'paidTotal') return Number(row.paidTotal || 0);
    return '';
  });
  return (
    <div className="card" style={{ padding: 0, overflow: 'hidden', borderRadius: 4, flexShrink: 0 }}>
      <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', background: 'var(--card-bg-2)' }}>
        <span style={{ fontSize: 13, fontWeight: 400, color: 'var(--text-primary)' }}>Client Highlight</span>
      </div>
      <table style={{ width: '100%', borderCollapse: 'collapse' }}>
        <thead>
          <tr style={{ background: 'var(--card-bg-2)' }}>
            <SortTh col="company" sortKey={sortKey} sortDir={sortDir} onSort={toggle} style={{ padding: '8px 16px', textAlign: 'left', fontSize: 11, fontWeight: 400, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.4px', borderBottom: '1px solid var(--border)' }}>Company</SortTh>
            <SortTh col="primaryContact" sortKey={sortKey} sortDir={sortDir} onSort={toggle} style={{ padding: '8px 16px', textAlign: 'center', fontSize: 11, fontWeight: 400, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.4px', borderBottom: '1px solid var(--border)' }}>Primary Contact</SortTh>
            <SortTh col="projectCount" sortKey={sortKey} sortDir={sortDir} onSort={toggle} style={{ padding: '8px 16px', textAlign: 'center', fontSize: 11, fontWeight: 400, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.4px', borderBottom: '1px solid var(--border)' }}>Projects</SortTh>
            <SortTh col="openTaskCount" sortKey={sortKey} sortDir={sortDir} onSort={toggle} style={{ padding: '8px 16px', textAlign: 'center', fontSize: 11, fontWeight: 400, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.4px', borderBottom: '1px solid var(--border)' }}>Open Tasks</SortTh>
            <SortTh col="outstandingTotal" sortKey={sortKey} sortDir={sortDir} onSort={toggle} style={{ padding: '8px 16px', textAlign: 'right', fontSize: 11, fontWeight: 400, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.4px', borderBottom: '1px solid var(--border)' }}>Outstanding</SortTh>
            <SortTh col="paidTotal" sortKey={sortKey} sortDir={sortDir} onSort={toggle} style={{ padding: '8px 16px', textAlign: 'right', fontSize: 11, fontWeight: 400, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.4px', borderBottom: '1px solid var(--border)' }}>Paid</SortTh>
          </tr>
        </thead>
        <tbody>
          {sortedHighlights.map(({ company, primaryContact, projectCount, openTaskCount, outstandingTotal = 0, paidTotal = 0 }, i) => (
            <tr key={company.id} style={{ borderBottom: i < sortedHighlights.length - 1 ? '1px solid var(--border)' : 'none' }}>
              <td style={{ padding: '10px 16px', fontSize: 13, fontWeight: 400, color: 'var(--text-primary)' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <InitialPortrait name={company.name} />
                  {company.name}
                </div>
              </td>
              <td style={{ padding: '10px 16px', fontSize: 13, color: 'var(--text-secondary)', textAlign: 'center' }}>{primaryContact?.name || '—'}</td>
              <td style={{ padding: '10px 16px', fontSize: 13, color: 'var(--text-secondary)', textAlign: 'center' }}>{projectCount}</td>
              <td style={{ padding: '10px 16px', fontSize: 13, color: 'var(--text-primary)', textAlign: 'center' }}>{openTaskCount}</td>
              <td style={{ padding: '10px 16px', fontSize: 13, color: 'var(--accent)', textAlign: 'right' }}>{fmtMoney(outstandingTotal)}</td>
              <td style={{ padding: '10px 16px', fontSize: 13, color: 'var(--accent)', textAlign: 'right' }}>{fmtMoney(paidTotal)}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

// ─── Main export ───────────────────────────────────────────────────────────

export default function DashboardPage() {
  const { currentUser } = useAuth();
  const isClient = currentUser?.role === 'client';
  const isExternal = currentUser?.role === 'external';

  // ── Client state ──────────────────────────────────────────────────────
  const hasCompany = Boolean(currentUser?.company_id || currentUser?.company?.id || currentUser?.companies?.length);
  const companies = isClient
    ? (currentUser?.companies?.length ? currentUser.companies : (currentUser?.company ? [currentUser.company] : [])).slice().sort((a, b) => a.name.localeCompare(b.name))
    : [];
  const [allClientTasks, setAllClientTasks] = useState([]);
  const [allClientProjects, setAllClientProjects] = useState([]);
  const [allClientInvoices, setAllClientInvoices] = useState([]);
  const [clientActivity, setClientActivity] = useState([]);

  // ── External state ────────────────────────────────────────────────────
  const cacheKey = 'team_dashboard_external';
  const cached = isExternal ? readPageCache(cacheKey, 5 * 60_000) : null;
  const [tasks, setTasks] = useState(() => cached?.tasks || []);
  const [projects, setProjects] = useState(() => cached?.projects || []);
  const [submissions, setSubmissions] = useState(() => cached?.submissions || []);
  const [pos, setPos] = useState(() => cached?.pos || []);
  const [clientProfiles, setClientProfiles] = useState(() => cached?.clientProfiles || []);
  const [companyMemberships, setCompanyMemberships] = useState(() => cached?.companyMemberships || []);

  const [loading, setLoading] = useState(() => isClient ? hasCompany : isExternal && !cached);

  useEffect(() => {
    let cancelled = false;
    if (isClient) {
      if (!hasCompany) { setLoading(false); return; }
      async function loadClient() {
        try {
          const [{ data: activeTasks }, { data: invoices }, { data: activityData }] = await withTimeout(Promise.all([
            supabase.from('tasks').select('id, title, status, project_id, assigned_name, project:projects(id, name, company_id)').order('submitted_at', { ascending: false }),
            supabase.from('invoices').select('total, status, company_id').in('status', ['sent', 'paid']),
            supabase.from('activity_log').select('id, created_at, actor_name, action, task_title, project_name, project_id').order('created_at', { ascending: false }).limit(20),
          ]), 30000, 'Client dashboard load');
          if (cancelled) return;
          const clientTasks = activeTasks || [];
          setAllClientTasks(clientTasks);
          setAllClientInvoices(invoices || []);
          setClientActivity(activityData || []);
          const projectMap = {};
          clientTasks.forEach(t => { if (t.project?.id) projectMap[t.project.id] = t.project; });
          setAllClientProjects(Object.values(projectMap));
        } catch (error) {
          console.error('ClientDashboard load failed:', error);
        } finally {
          if (!cancelled) setLoading(false);
        }
      }
      loadClient();
    } else if (isExternal) {
      async function loadExternal() {
        try {
          const [{ data: p }, { data: t }, { data: posData }, { data: memRows }, { data: clientProfiles }, { data: activityData }] = await withTimeout(Promise.all([
            supabase.from('projects').select('id, name, company_id, company:companies(id, name)').order('created_at', { ascending: false }),
            supabase.from('tasks').select('id, title, status, current_version, project_id, assigned_to, assigned_name').order('submitted_at', { ascending: false }),
            supabase.from('subcontractor_payments').select('id, amount, status').eq('profile_id', currentUser.id),
            supabase.from('company_members').select('company_id, profile_id'),
            supabase.from('profiles').select('id, name, email, company_id').eq('role', 'client'),
            supabase.from('activity_log').select('id, created_at, actor_name, action, task_title, project_name, project_id').order('created_at', { ascending: false }).limit(20),
          ]), 30000, 'External dashboard load');
          if (!cancelled) {
            setProjects(p || []);
            setTasks(t || []);
            setPos(posData || []);
            setSubmissions(activityData || []);
            setClientProfiles(clientProfiles || []);
            setCompanyMemberships(memRows || []);
            writePageCache(cacheKey, { projects: p || [], tasks: t || [], submissions: activityData || [], pos: posData || [], clientProfiles: clientProfiles || [], companyMemberships: memRows || [] });
          }
        } catch (error) {
          console.error('External dashboard load failed:', error);
        } finally {
          if (!cancelled) setLoading(false);
        }
      }
      loadExternal();
    } else {
      setLoading(false);
    }
    return () => { cancelled = true; };
  }, [isClient, isExternal, hasCompany, cacheKey, currentUser?.id]);

  if (loading) return <Layout><p style={{ padding: 24, color: 'var(--text-muted)' }}>Loading...</p></Layout>;

  // ── Client render ──────────────────────────────────────────────────────
  if (isClient) {
    const myCompanyIds = new Set(companies.map(c => c.id));
    const myTasks = myCompanyIds.size > 0
      ? allClientTasks.filter(t => t.project?.company_id && myCompanyIds.has(t.project.company_id))
      : allClientTasks;
    const myProjects = myCompanyIds.size > 0
      ? allClientProjects.filter(p => myCompanyIds.has(p.company_id))
      : allClientProjects;
    const myInvoices = myCompanyIds.size > 0
      ? allClientInvoices.filter(i => myCompanyIds.has(i.company_id))
      : allClientInvoices;
    const myProjectIds = new Set(myProjects.map(p => p.id));
    const reviewTasks = myTasks.filter(t => t.status === 'client_review');
    const inProgressTasks = myTasks.filter(t => t.status === 'in_progress');
    const onHoldTasks = myTasks.filter(t => t.status === 'on_hold');
    const notStartedTasks = myTasks.filter(t => t.status === 'not_started');
    const outstandingInvoices = myInvoices.filter(i => i.status === 'sent').reduce((sum, inv) => sum + Number(inv.total || 0), 0);
    const paidInvoices = myInvoices.filter(i => i.status === 'paid').reduce((sum, inv) => sum + Number(inv.total || 0), 0);

    return (
      <Layout>
        <div className="dash-stat-grid">
          <DashStatCard label="Active Projects" value={myProjects.length} sub={`${myTasks.length} total tasks`} iconBg="rgba(96,165,250,0.15)" iconColor="#60a5fa" iconPath={DASH_ICONS.projects} />
          <DashStatCard label="Outstanding" value={fmtMoney(outstandingInvoices)} sub={`${fmtMoney(paidInvoices)} paid`} iconBg="rgba(245,165,35,0.15)" iconColor="#F5A523" iconPath={DASH_ICONS.invoice} />
          <DashStatCard label="In Progress" value={inProgressTasks.length} sub={`${notStartedTasks.length} not started`} iconBg="rgba(74,222,128,0.15)" iconColor="#4ade80" iconPath={DASH_ICONS.tasks} />
          <DashStatCard label="Awaiting Review" value={reviewTasks.length} sub={`${onHoldTasks.length} on hold`} iconBg="rgba(245,165,35,0.15)" iconColor="#F5A523" iconPath={DASH_ICONS.trending} />
        </div>
        <ActivityFeed events={buildActivityEvents(clientActivity, myProjectIds)} />
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 24, marginTop: 24 }}>
          <TaskFeed title="Awaiting Your Review" tasks={reviewTasks} projects={myProjects} emptyMessage="No items need your review." />
          <TaskFeed title="In Progress" tasks={inProgressTasks} projects={myProjects} emptyMessage="No items currently in progress." />
        </div>
      </Layout>
    );
  }

  // ── External render ────────────────────────────────────────────────────
  if (isExternal) {
    return <ExternalDashboard currentUser={currentUser} projects={projects} tasks={tasks} pos={pos} submissions={submissions} clientProfiles={clientProfiles} companyMemberships={companyMemberships} />;
  }

  return null;
}
