// dashboard.jsx — Workspace-scoped signed-in dashboard.
//
// Renders the Workspace Home (R07 / T0011) — the admin entry point per
// ADR 0003. The page is intentionally sparse: it shows admin posture
// (tier, modules, members) and the load-bearing "Open on Mac" CTA that
// hands the user off to the native app for the daily work. No working
// data lives on this surface.
//
// Five sections, in vertical order:
//   1. Welcome + trial banner
//   2. Open-on-Mac / Pair-desktop card (the big CTA)
//   3. Quick-status row: tier, modules, members
//   4. Open-questions banner (only if enrichment surfaced any)
//   5. (nothing — sparseness is the point)
//
// Exposes window.Dashboard (routing-compat name; conceptually this is
// now Workspace Home).

(function (window) {
  'use strict';

  const {
    useAuth,
    db,
    signOut,
    useActiveWorkspaceId,
    useWorkspace,
    navigateTo,
    workspacePath,
  } = window.exoteamAuth || {};
  if (!useAuth) {
    console.error('dashboard.jsx: window.exoteamAuth missing');
    return;
  }

  const ALIVE_THRESHOLD_S = 3 * 60;

  function Dashboard() {
    const { user, userDoc, loading } = useAuth();
    const activeWorkspaceId = useActiveWorkspaceId();
    const { workspaces, loading: wsLoading, activeWorkspace } = useWorkspace();
    const [workspace, setWorkspace] = React.useState(null);
    const [devices, setDevices] = React.useState([]);
    const [modules, setModules] = React.useState({});
    const [memberCount, setMemberCount] = React.useState(null);
    const [pendingInviteCount, setPendingInviteCount] = React.useState(null);
    const [loadError, setLoadError] = React.useState(null);
    const [deepLinkStatus, setDeepLinkStatus] = React.useState('idle'); // idle | trying | failed

    // If the URL has no /w/<id>/ prefix but the user has workspaces,
    // redirect to their first. Email "go to dashboard" links land here.
    React.useEffect(() => {
      if (!user || wsLoading) return;
      if (!activeWorkspaceId && workspaces.length > 0) {
        navigateTo(workspacePath(workspaces[0].workspace_id, 'dashboard'));
      }
    }, [user, wsLoading, activeWorkspaceId, workspaces]);

    // Live workspace doc.
    React.useEffect(() => {
      if (!activeWorkspaceId) return undefined;
      setLoadError(null);
      const unsub = db
        .collection('workspaces')
        .doc(activeWorkspaceId)
        .onSnapshot(
          (snap) => {
            if (snap.exists) {
              setWorkspace({ id: snap.id, ...snap.data() });
            } else {
              setLoadError(
                'Your Workspace record could not be loaded. Try switching Workspace or contact support.',
              );
            }
          },
          (err) => {
            console.error('Dashboard: workspace snapshot', err);
            setLoadError(err.message || String(err));
          },
        );
      return unsub;
    }, [activeWorkspaceId]);

    // Devices subscription.
    React.useEffect(() => {
      if (!activeWorkspaceId) return undefined;
      const unsub = db
        .collection('workspaces')
        .doc(activeWorkspaceId)
        .collection('devices')
        .onSnapshot(
          (snap) => setDevices(snap.docs.map((d) => ({ id: d.id, ...d.data() }))),
          (err) => console.error('Dashboard: devices snapshot', err),
        );
      return unsub;
    }, [activeWorkspaceId]);

    // Modules subscription — drives the "N modules active" pill.
    React.useEffect(() => {
      if (!activeWorkspaceId) return undefined;
      const unsub = db
        .collection('workspaces')
        .doc(activeWorkspaceId)
        .collection('modules')
        .onSnapshot(
          (snap) => {
            const next = {};
            snap.docs.forEach((d) => {
              next[d.id] = { id: d.id, ...d.data() };
            });
            setModules(next);
          },
          (err) => console.error('Dashboard: modules snapshot', err),
        );
      return unsub;
    }, [activeWorkspaceId]);

    // Memberships count — one-shot; stable between admin actions.
    React.useEffect(() => {
      if (!activeWorkspaceId) return;
      db.collection('memberships')
        .where('workspace_id', '==', activeWorkspaceId)
        .get()
        .then((snap) => setMemberCount(snap.size))
        .catch((err) => console.error('Dashboard: memberships count', err));
    }, [activeWorkspaceId]);

    // Pending invitations count — via the listInvitations callable.
    React.useEffect(() => {
      if (!activeWorkspaceId) return;
      const fns = window.exoteamAuth && window.exoteamAuth.fns;
      if (!fns) return;
      const callable = fns.httpsCallable('listInvitations');
      callable({ workspace_id: activeWorkspaceId })
        .then(({ data }) => {
          const list = (data && data.invitations) || [];
          setPendingInviteCount(list.length);
        })
        .catch((err) => {
          console.warn('Dashboard: listInvitations', err);
          setPendingInviteCount(0);
        });
    }, [activeWorkspaceId]);

    const hasPairedDevice = devices.length > 0;
    const aliveDevices = devices.filter((d) => isAlive(d.last_seen_at));

    if (loading || !user) return null;

    if (loadError) {
      return (
        <div className="exo-admin" style={{ padding: 24 }}>
          <div className="exo-state exo-state-error" role="alert">
            <h4>We hit a snag</h4>
            <p>{loadError}</p>
            <button className="exo-btn" onClick={() => window.location.reload()}>
              Retry
            </button>
          </div>
        </div>
      );
    }

    if (!activeWorkspaceId || !workspace) {
      return (
        <div className="exo-admin" style={{ padding: 24 }}>
          <div className="exo-state exo-state-loading" aria-live="polite">
            <div className="exo-spinner" />
            <p>Loading your dashboard…</p>
          </div>
        </div>
      );
    }

    const name = (userDoc && userDoc.display_name) || workspace.display_name || 'there';
    const trialEnds =
      workspace.trial_ends_at && workspace.trial_ends_at.toDate
        ? workspace.trial_ends_at.toDate()
        : null;
    const trialDaysLeft = trialEnds
      ? Math.max(0, Math.ceil((trialEnds - Date.now()) / (24 * 60 * 60 * 1000)))
      : null;

    const wsBase = `/w/${activeWorkspaceId}`;

    // Active modules — `doc.enabled === true` is the canonical signal
    // (matches the Modules pane in settings.jsx).
    const catalog = (window.exoteamModules && window.exoteamModules.CATALOG) || [];
    const moduleLabel = (id) => {
      const entry = catalog.find((m) => m.id === id);
      return entry ? entry.label : id;
    };
    const activeModuleIds = Object.keys(modules).filter(
      (id) => modules[id] && modules[id].enabled === true,
    );
    const activeModuleSummary = (() => {
      if (activeModuleIds.length === 0) return null;
      const labels = activeModuleIds.map(moduleLabel);
      if (labels.length <= 2) return labels.join(', ');
      return `${labels.slice(0, 2).join(', ')} +${labels.length - 2}`;
    })();

    // Tier display label.
    const tierLabel = (() => {
      const t = workspace.tier;
      if (!t) return 'FREE';
      if (t === 'trial') return 'TRIAL';
      return String(t).toUpperCase();
    })();

    // Open-questions count from the live workspace doc.
    const openQuestions =
      (workspace.enrichment && Array.isArray(workspace.enrichment.open_questions)
        ? workspace.enrichment.open_questions
        : []);
    const openQuestionsCount = openQuestions.length;

    // Deep-link handler. Modern browsers swallow unknown-scheme nav
    // silently — we set a 1.2s timer; if the page is still focused, we
    // surface a fallback note. If the app handled the link, the tab
    // gets backgrounded and the timer's clean-up never updates state
    // visibly to the user.
    function tryOpenOnMac() {
      setDeepLinkStatus('trying');
      const target = `exoteam://workspace/${activeWorkspaceId}`;
      // window.location.href will navigate the top frame; for unknown
      // schemes that's a no-op visually. Wrap to avoid throwing.
      try {
        window.location.href = target;
      } catch (err) {
        console.warn('Dashboard: deep-link nav failed', err);
      }
      window.setTimeout(() => {
        if (document.hidden) return; // app likely opened — leave UI alone
        setDeepLinkStatus('failed');
      }, 1200);
    }

    // Sub-line: "Last active …" for paired-device card.
    const lastSeenMs = (() => {
      let max = 0;
      for (const d of devices) {
        const ls = d.last_seen_at;
        if (!ls) continue;
        let ms = 0;
        if (typeof ls.toMillis === 'function') ms = ls.toMillis();
        else if (typeof ls === 'string') ms = Date.parse(ls);
        else if (ls instanceof Date) ms = ls.getTime();
        if (ms > max) max = ms;
      }
      return max || null;
    })();
    const lastSeenLabel = lastSeenMs ? formatRelativeTime(lastSeenMs) : null;

    return (
      <div className="exo-admin">
        <header className="exo-admin-header">
          <a
            href={wsBase}
            className="exo-admin-header-logo"
            onClick={(e) => { e.preventDefault(); navigateTo(wsBase); }}
          >
            <img src="/lockup.svg" alt="exoteam" style={{ height: 22 }} />
          </a>
          {window.WorkspaceSwitcher && <window.WorkspaceSwitcher />}
          <nav className="exo-admin-nav">
            <a
              href={`${wsBase}/dashboard`}
              className="exo-admin-nav-item is-active"
              onClick={(e) => {
                e.preventDefault();
                navigateTo(`${wsBase}/dashboard`);
              }}
            >
              Home
            </a>
            <a
              href={`${wsBase}/settings`}
              className="exo-admin-nav-item"
              onClick={(e) => {
                e.preventDefault();
                navigateTo(`${wsBase}/settings`);
              }}
            >
              Settings
            </a>
            <a
              href={
                workspace.tier === 'trial'
                  ? `${wsBase}/settings/modules`
                  : `${wsBase}/settings/billing`
              }
              className="exo-admin-nav-item"
              onClick={(e) => {
                e.preventDefault();
                const target =
                  workspace.tier === 'trial'
                    ? `${wsBase}/settings/modules`
                    : `${wsBase}/settings/billing`;
                navigateTo(target);
              }}
            >
              {workspace.tier === 'trial' ? 'Upgrade' : 'Billing'}
            </a>
          </nav>
          <div className="exo-admin-header-right">
            <span className="exo-admin-header-user">{name}</span>
            <button
              type="button"
              className="exo-admin-btn--link is-muted"
              onClick={() => signOut()}
            >
              Sign out
            </button>
          </div>
        </header>

        <main className="exo-admin-main">
          <div>
            <h1 className="exo-admin-page-title">Welcome back, {name}.</h1>
            {workspace.tier === 'trial' && trialDaysLeft !== null && (
              <p className="exo-admin-subtitle" style={{ marginTop: 8, marginBottom: 0 }}>
                {trialDaysLeft > 0
                  ? `${trialDaysLeft} day${trialDaysLeft === 1 ? '' : 's'} left on your free trial.`
                  : 'Your trial has ended.'}{' '}
                <a
                  href={`${wsBase}/settings/modules`}
                  style={{ color: 'var(--exo-accent)' }}
                  onClick={(e) => {
                    e.preventDefault();
                    navigateTo(`${wsBase}/settings/modules`);
                  }}
                >
                  Upgrade a module →
                </a>
              </p>
            )}
          </div>

          {/* Section 2 — Open-on-Mac / Pair-desktop CTA. The load-
              bearing handoff per ADR 0003: daily work lives native;
              this is the door to it. */}
          <section className="exo-admin-card exo-admin-card--hero">
            {hasPairedDevice ? (
              <>
                <h2 className="exo-admin-title" style={{ marginBottom: 10 }}>
                  Your desktop is paired.
                </h2>
                <p className="exo-admin-subtitle" style={{ marginBottom: 22 }}>
                  Open exoteam on your Mac to keep working — outreach,
                  scout, dossiers, drafts all live there.
                </p>
                <div style={{ display: 'flex', alignItems: 'center', gap: 14, flexWrap: 'wrap' }}>
                  <button
                    type="button"
                    className="exo-admin-btn"
                    onClick={tryOpenOnMac}
                  >
                    Open exoteam →
                  </button>
                  {lastSeenLabel && (
                    <span style={{ fontSize: 13, color: 'var(--exo-ink-tertiary)' }}>
                      {aliveDevices.length > 0 ? 'Active' : 'Last active'} {lastSeenLabel}
                    </span>
                  )}
                </div>
                {deepLinkStatus === 'failed' && (
                  <p
                    className="exo-admin-hint"
                    style={{ marginTop: 14 }}
                  >
                    If nothing happened, exoteam may not be installed on
                    this device.{' '}
                    <a
                      href="#"
                      style={{ color: 'var(--exo-ink-secondary)', textDecoration: 'underline' }}
                    >
                      Download for Mac →
                    </a>
                  </p>
                )}
              </>
            ) : (
              <>
                <h2 className="exo-admin-title" style={{ marginBottom: 10 }}>
                  Pair your desktop to start.
                </h2>
                <p className="exo-admin-subtitle" style={{ marginBottom: 22 }}>
                  The daily work — outreach, scout, dossiers, drafts —
                  runs in the native app. This page is for admin only.
                </p>
                <div style={{ display: 'flex', alignItems: 'center', gap: 14, flexWrap: 'wrap' }}>
                  <button
                    type="button"
                    className="exo-admin-btn"
                    onClick={(e) => {
                      e.preventDefault();
                      navigateTo('/onboard/pair');
                    }}
                  >
                    Set up desktop →
                  </button>
                </div>
              </>
            )}
          </section>

          {/* Section 3 — Quick status row. Three at-a-glance cards
              (responsive: stack on narrow). Info-only, not CTAs — but
              the whole card is clickable to the relevant settings tab. */}
          <section className="exo-admin-status-row">
            <StatusCard
              label={tierLabel}
              detail={
                workspace.tier === 'trial' && trialDaysLeft !== null
                  ? `${trialDaysLeft} day${trialDaysLeft === 1 ? '' : 's'} left`
                  : 'Billing & plan'
              }
              onClick={() => navigateTo(`${wsBase}/settings/billing`)}
            />
            <StatusCard
              label={`${activeModuleIds.length} module${activeModuleIds.length === 1 ? '' : 's'} active`}
              detail={activeModuleSummary || 'No modules enabled yet'}
              onClick={() => navigateTo(`${wsBase}/settings/modules`)}
            />
            <StatusCard
              label={
                memberCount === null
                  ? 'Members'
                  : `${memberCount} member${memberCount === 1 ? '' : 's'}`
              }
              detail={
                pendingInviteCount === null
                  ? ' '
                  : pendingInviteCount === 0
                    ? 'No pending invites'
                    : `${pendingInviteCount} pending invite${pendingInviteCount === 1 ? '' : 's'}`
              }
              onClick={() => navigateTo(`${wsBase}/settings/members`)}
            />
          </section>

          {/* Section 4 — Open-questions passive banner. Only renders
              if the last enrichment run surfaced unanswered questions. */}
          {openQuestionsCount > 0 && (
            <section className="exo-admin-banner is-info">
              <a
                href={`${wsBase}/settings/open-questions`}
                style={{ color: 'inherit', textDecoration: 'none' }}
                onClick={(e) => {
                  e.preventDefault();
                  navigateTo(`${wsBase}/settings/open-questions`);
                }}
              >
                {openQuestionsCount} open question
                {openQuestionsCount === 1 ? '' : 's'} from your last
                enrichment run — answer them in Settings → Open
                Questions →
              </a>
            </section>
          )}
        </main>
      </div>
    );
  }

  // Quick-status card used in the row of three under the hero. The
  // whole tile is a button so the click target matches the visual
  // affordance.
  function StatusCard({ label, detail, onClick }) {
    return (
      <button type="button" className="exo-admin-status-card" onClick={onClick}>
        <div className="exo-admin-status-label">{label}</div>
        <div className="exo-admin-status-detail">{detail}</div>
      </button>
    );
  }

  function isAlive(lastSeenAt) {
    if (!lastSeenAt) return false;
    let ms;
    if (typeof lastSeenAt.toMillis === 'function') {
      ms = lastSeenAt.toMillis();
    } else if (typeof lastSeenAt === 'string') {
      ms = Date.parse(lastSeenAt);
    } else if (lastSeenAt instanceof Date) {
      ms = lastSeenAt.getTime();
    } else {
      return false;
    }
    return Date.now() - ms < ALIVE_THRESHOLD_S * 1000;
  }

  function formatRelativeTime(ms) {
    const deltaS = Math.max(0, Math.floor((Date.now() - ms) / 1000));
    if (deltaS < 60) return 'just now';
    if (deltaS < 3600) {
      const m = Math.floor(deltaS / 60);
      return `${m} minute${m === 1 ? '' : 's'} ago`;
    }
    if (deltaS < 86400) {
      const h = Math.floor(deltaS / 3600);
      return `${h} hour${h === 1 ? '' : 's'} ago`;
    }
    const d = Math.floor(deltaS / 86400);
    return `${d} day${d === 1 ? '' : 's'} ago`;
  }

  window.Dashboard = Dashboard;
})(window);
