// Settings — the account surface, reached ONLY by clicking the profile avatar.
//
// ── Where it came from (Omar, 2026-08-24 / 25) ───────────────────────────────
// "The current Members page should be called Settings and should be positioned
// at the bottom left" — then, after seeing it: "the way to access the Settings
// will be available only from the top right clicking on the profile icon. When
// the user clicks on the profile it lands on the page." So there is exactly ONE
// door, the avatar, and the left rail no longer carries a Members entry.
//
// Three tabs, per his list. Two are real. The third is a placeholder he asked
// for explicitly — "the AI section will be developed later, so create a
// placeholder for it".
//
// ── What the reference design showed that this deliberately does NOT ──────────
// The mock had a LAST ACTIVE column ("2 hours ago", "Yesterday") and the roles
// "Owner" and "Author". Neither survives contact with the system:
//
//   · `GET /v1/members` returns { email, displayName, role, assignedLangs,
//     status } and NOTHING about activity. A column of em-dashes is worse than
//     no column — it implies a value is coming.
//   · The four roles were LOCKED on 2026-08-18: admin · editor · reviewer ·
//     language_reviewer. `owner` was explicitly DECLINED, and there is no
//     "Author". Rendering the mock's words would have put role names on screen
//     that no route accepts and no CHECK constraint allows.
//
// The members table itself is NOT reimplemented here — `SurfaceMembers` is
// rendered in embedded mode. A second members table would be a second set of
// rules about roles (`feedback_one_rule_one_place`).

const SETTINGS_TABS = [
  { id: 'profile', label: 'Profile & preferences' },
  { id: 'members', label: 'Members', requires: 'member:manage' },
  { id: 'ai', label: 'AI spend & limits' },
];

function SurfaceSettings({ me, meOrg, initialTab, onSignOut }) {
  const canManageMembers =
    typeof window.dynamoCan === 'function' && window.dynamoCan('member:manage');
  const tabs = SETTINGS_TABS.filter(t => !t.requires || canManageMembers);

  const [tab, setTab] = React.useState(() => {
    const wanted = initialTab || 'profile';
    return tabs.some(t => t.id === wanted) ? wanted : 'profile';
  });
  // Filled by the Members tab when it loads, so the header does not issue a
  // second request for a number the tab already has.
  const [memberCount, setMemberCount] = React.useState(null);

  const workspace = (meOrg && meOrg.name) || '';
  const subtitle = [workspace, memberCount == null ? null :
    `${memberCount} ${memberCount === 1 ? 'member' : 'members'}`]
    .filter(Boolean).join(' · ');

  return (
    <div style={{ height: '100%', overflowY: 'auto', background: 'var(--bg)' }}
         data-screen-label="Settings">
      <div style={{ maxWidth: 1160, margin: '0 auto', padding: '28px 28px 48px' }}>
        <h1 style={{ margin: 0, fontSize: 26, fontWeight: 650, letterSpacing: '-.01em' }}>
          Settings
        </h1>
        <div style={{ fontSize: 13.5, color: 'var(--text-muted)', marginTop: 4, minHeight: 20 }}>
          {subtitle}
        </div>

        {/* Tabs */}
        <div role="tablist" style={{
          display: 'flex', gap: 4, marginTop: 20,
          borderBottom: '1px solid var(--border)',
        }}>
          {tabs.map(t => {
            const active = t.id === tab;
            return (
              <button key={t.id} role="tab" aria-selected={active}
                onClick={() => setTab(t.id)}
                style={{
                  appearance: 'none', background: 'transparent', border: 0,
                  borderBottom: `2px solid ${active ? 'var(--accent)' : 'transparent'}`,
                  padding: '10px 14px', marginBottom: -1,
                  fontFamily: 'inherit', fontSize: 14,
                  fontWeight: active ? 650 : 500,
                  color: active ? 'var(--text)' : 'var(--text-muted)',
                  cursor: 'default',
                }}
                onMouseOver={e => { if (!active) e.currentTarget.style.color = 'var(--text)'; }}
                onMouseOut={e => { if (!active) e.currentTarget.style.color = 'var(--text-muted)'; }}>
                {t.label}
              </button>
            );
          })}
        </div>

        <div style={{ paddingTop: 22 }}>
          {tab === 'profile' && <ProfileTab me={me} meOrg={meOrg} onSignOut={onSignOut} />}
          {tab === 'members' && (
            <window.SurfaceMembers embedded onCount={setMemberCount} />
          )}
          {tab === 'ai' && <AiSpendTab meOrg={meOrg} />}
        </div>
      </div>
    </div>
  );
}

// ── Profile & preferences ───────────────────────────────────────────────────
//
// Everything here is READ-ONLY and says so, because every field comes from the
// sign-in provider and nothing in this app can write any of them yet. An
// editable-looking field that cannot save is the same defect as a button with
// no handler (`feedback_no_false_affordance_toggles`), which is what the four
// dead items in the old profile menu were.
// ⚠️ No `maxWidth` here, and none in AiSpendTab. Both were capped at 680px
// while the Members tab filled the container, so the page jumped width as you
// moved between tabs of the same screen. Omar: "make sure that Profile &
// preferences and AI spend & limits have the same width of the Members tab."
// The one container is the page's own `maxWidth: 1160`, which all three share.
function ProfileTab({ me, meOrg, onSignOut }) {
  const ROLE_LABEL = { admin: 'Admin', editor: 'Editor', reviewer: 'Reviewer',
                       language_reviewer: 'Language Reviewer' };
  const langs = (meOrg && meOrg.defaultLanguages) || [];
  const assigned = (me && me.assignedLangs) || [];
  const rows = [
    ['Name', (me && me.displayName) || null, 'Not set. It comes from your sign-in.'],
    ['Email', (me && me.email) || null, null],
    ['Role', (me && ROLE_LABEL[me.role]) || (me && me.role) || null, null],
    ['Workspace', (meOrg && meOrg.name) || null, null],
    ['Workspace languages', langs.length ? langs.join(', ') : null, 'None set.'],
  ];
  // ⚠️ DERIVED FROM CAPABILITIES, NOT FROM THE ROLE NAME. This was written as
  // `me.role === 'language_reviewer'` and `fe-members-screen.test.ts` caught it
  // — in the very file whose job is to take authority from the server. The
  // guard was right: a role-name check here is the first step back to the
  // denylist-of-one this app already removed once.
  //
  // The row means "which languages may you edit", which is meaningful exactly
  // when someone's editing is language-SCOPED: they may write localisation but
  // not courses. That is a property of the capability set, and it stays true if
  // the roles are ever renamed.
  //
  // The empty case is shown rather than hidden: a language reviewer with no
  // assignment can edit nothing, and empty here means "none", never "all"
  // (`feedback_an_empty_list_may_mean_everything`).
  const caps = (me && Array.isArray(me.capabilities)) ? me.capabilities : [];
  const languageScoped = caps.indexOf('localisation:write') !== -1
    && caps.indexOf('course:write') === -1;
  if (languageScoped) {
    rows.push(['Languages you may edit',
      assigned.length ? assigned.join(', ') : null,
      'None assigned — ask an admin.']);
  }

  return (
    <div>
      <SettingsCard
        title="Your account"
        note="These come from your sign-in and cannot be changed here yet.">
        {rows.map(([k, v, empty]) => (
          <SettingsRow key={k} label={k} value={v} emptyNote={empty} />
        ))}
      </SettingsCard>

      <SettingsCard title="Preferences">
        <div style={{ fontSize: 13, color: 'var(--text-muted)', padding: '4px 0 2px' }}>
          There is nothing to change yet. Interface language and theme follow
          your browser, and neither is stored against your account.
        </div>
      </SettingsCard>

      <div style={{ marginTop: 20, display: 'flex', justifyContent: 'flex-start' }}>
        {/* Sign out lived in the avatar menu, which this screen replaced. It has
            to land somewhere reachable or clicking the avatar would remove the
            only way out (`feedback_an_error_screen_that_replaces_the_app_removes_the_remedy`). */}
        <button className="btn sm" onClick={onSignOut}
          style={{ color: 'var(--error-text)', borderColor: 'var(--border-strong)' }}>
          <I.ArrowLeft size={13} />Sign out
        </button>
      </div>
    </div>
  );
}

// ── AI spend & limits — the placeholder Omar asked for ──────────────────────
//
// ⚠️ NOTHING IN THIS SYSTEM MEASURES AI SPEND. There is no spend route, no
// usage table and no meter; the `$4.82 / $25` in the header is a literal in
// `data.jsx`. The one real number available is the workspace's monthly budget,
// which /v1/me returns as `aiBudgetUsdMonthly` and which is usually null.
//
// So this screen shows the budget when there is one, and states plainly that
// spend is NOT MEASURED. It must never render $0.00: nothing-recorded and
// nothing-spent are different facts, and showing them identically is how a
// reader concludes the meter works and reads zero
// (`feedback_absence_and_emptiness_read_the_same`).
function AiSpendTab({ meOrg }) {
  const budget = meOrg && meOrg.aiBudgetUsdMonthly != null
    ? meOrg.aiBudgetUsdMonthly : null;
  return (
    <div>
      <SettingsCard
        title="AI spend"
        note="What this workspace has spent on AI generation and translation.">
        <SettingsRow label="Spend this month" value={null}
          emptyNote="Not measured yet — see below." />
        <SettingsRow label="Monthly budget"
          value={budget != null ? `$${budget.toFixed(2)}` : null}
          emptyNote="No budget set for this workspace." />
      </SettingsCard>

      <div style={{
        display: 'flex', gap: 10, padding: '12px 14px', marginTop: 4,
        background: 'var(--surface-inset)', border: '1px solid var(--border-faint)',
        borderRadius: 'var(--radius-md)', fontSize: 12.5, color: 'var(--text-muted)',
        lineHeight: 1.55,
      }}>
        <I.Info size={14} style={{ flexShrink: 0, marginTop: 2 }} />
        <div>
          <strong style={{ color: 'var(--text)' }}>This screen is a placeholder,
          and deliberately empty rather than zero.</strong> Nothing records AI
          spend yet — there is no meter behind this page — so no figure can
          honestly be shown. <em>$0.00</em> would claim the opposite: that
          spending is being counted and none has happened. Per-workspace limits
          and a real running total arrive with the metering work.
        </div>
      </div>
    </div>
  );
}

// ── Small shared pieces ─────────────────────────────────────────────────────
function SettingsCard({ title, note, children }) {
  return (
    <section style={{
      background: 'var(--surface)', border: '1px solid var(--border)',
      borderRadius: 'var(--radius-md)', padding: '16px 18px', marginBottom: 16,
    }}>
      <div style={{ fontSize: 14, fontWeight: 650 }}>{title}</div>
      {note && <div style={{ fontSize: 12.5, color: 'var(--text-muted)', marginTop: 3 }}>
        {note}</div>}
      <div style={{ marginTop: 12 }}>{children}</div>
    </section>
  );
}

/**
 * One label/value line. A missing value is rendered as its own SENTENCE, not as
 * a dash — "Not set. It comes from your sign-in." tells the reader what to do;
 * "—" leaves them guessing whether it is broken.
 */
function SettingsRow({ label, value, emptyNote }) {
  return (
    <div style={{
      display: 'grid', gridTemplateColumns: '190px 1fr', gap: 14,
      padding: '9px 0', borderTop: '1px solid var(--border-faint)',
      fontSize: 13, alignItems: 'baseline',
    }}>
      <span style={{ color: 'var(--text-muted)' }}>{label}</span>
      {value
        ? <span style={{ fontWeight: 500 }}>{value}</span>
        : <span style={{ color: 'var(--text-faint)', fontStyle: 'italic' }}>
            {emptyNote || 'Not available.'}
          </span>}
    </div>
  );
}

Object.assign(window, { SurfaceSettings });
