/* Admin console — the bookkeeper's view.
   Create clients, connect their QuickBooks, manage their logins, and open any
   client's live dashboard. Also hosts the invite "set your password" screen that
   clients land on from their email link. All admin endpoints are behind requireAdmin
   server-side; this UI only renders for role === 'admin'. */

const CBAdmin = {
  async listCompanies() {
    const r = await fetch('/api/admin/companies', { credentials: 'same-origin' });
    if (!r.ok) throw new Error('Failed to load clients');
    return r.json();
  },
  async getCompany(id) {
    const r = await fetch(`/api/admin/companies/${id}`, { credentials: 'same-origin' });
    if (!r.ok) throw new Error('Failed to load client');
    return r.json();
  },
  async createCompany(name) {
    const r = await fetch('/api/admin/companies', {
      method: 'POST', credentials: 'same-origin',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name }),
    });
    if (!r.ok) throw new Error((await r.json().catch(() => ({}))).error || 'Failed to create client');
    return r.json();
  },
  async addUser(companyId, email, name) {
    const r = await fetch(`/api/admin/companies/${companyId}/users`, {
      method: 'POST', credentials: 'same-origin',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email, name }),
    });
    if (!r.ok) throw new Error((await r.json().catch(() => ({}))).error || 'Failed to add login');
    return r.json();
  },
  async reinvite(companyId, userId) {
    const r = await fetch(`/api/admin/companies/${companyId}/users/${userId}/invite`, {
      method: 'POST', credentials: 'same-origin',
    });
    if (!r.ok) throw new Error('Failed to send invite');
    return r.json();
  },
};

function StatusBadge({ connected }) {
  return (
    <span className="cb-badge" data-on={connected ? '1' : '0'}>
      {connected ? <IconCheck size={12} /> : <IconAlert size={12} />}
      {connected ? 'Connected' : 'Not connected'}
    </span>
  );
}

/* Expandable detail for one client: connection + logins. */
function ClientRow({ company, onChanged, onOpenDashboard }) {
  const [open, setOpen] = React.useState(false);
  const [detail, setDetail] = React.useState(null);
  const [email, setEmail] = React.useState('');
  const [name, setName] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [notice, setNotice] = React.useState(null);
  const [err, setErr] = React.useState(null);

  const loadDetail = async () => {
    try { setDetail(await CBAdmin.getCompany(company.id)); }
    catch (e) { setErr(e.message); }
  };
  const toggle = () => { const n = !open; setOpen(n); if (n && !detail) loadDetail(); };

  const addLogin = async (e) => {
    e.preventDefault();
    setBusy(true); setErr(null); setNotice(null);
    try {
      const res = await CBAdmin.addUser(company.id, email.trim(), name.trim());
      setEmail(''); setName('');
      if (res.invite?.devLink) {
        setNotice({ type: 'devlink', link: res.invite.devLink });
      } else {
        setNotice({ type: 'emailed', email: res.email });
      }
      await loadDetail(); onChanged && onChanged();
    } catch (ex) { setErr(ex.message); }
    finally { setBusy(false); }
  };

  const resend = async (userId) => {
    setErr(null); setNotice(null);
    try {
      const res = await CBAdmin.reinvite(company.id, userId);
      if (res.invite?.devLink) setNotice({ type: 'devlink', link: res.invite.devLink });
      else setNotice({ type: 'emailed' });
    } catch (ex) { setErr(ex.message); }
  };

  return (
    <div className="cb-admin-row" data-open={open ? '1' : '0'}>
      <div className="cb-admin-row-head" onClick={toggle} role="button">
        <IconChevRight size={15} className="cb-admin-caret" />
        <div className="cb-admin-row-name">{company.name}</div>
        <StatusBadge connected={company.connected} />
        <div className="cb-admin-row-meta">{company.users} login{company.users === 1 ? '' : 's'}</div>
        <div className="cb-admin-row-actions" onClick={(e) => e.stopPropagation()}>
          {company.connected ? (
            <button type="button" className="cb-btn cb-btn-primary cb-btn-sm"
                    onClick={() => onOpenDashboard(company.id)}>
              View dashboard
            </button>
          ) : (
            <a className="cb-btn cb-btn-ghost cb-btn-sm" href={`/api/qbo/connect?companyId=${company.id}`}>
              <IconExternal size={13} /> Connect QuickBooks
            </a>
          )}
        </div>
      </div>

      {open && (
        <div className="cb-admin-row-body">
          {err && <div className="cb-auth-err">{err}</div>}

          <div className="cb-admin-section">
            <div className="cb-admin-section-title">QuickBooks</div>
            {company.connected ? (
              <p className="cb-admin-dim">Connected · realm {company.realmId}
                {company.refreshExpiresAt && ` · token valid to ${new Date(company.refreshExpiresAt).toLocaleDateString()}`}
              </p>
            ) : (
              <p className="cb-admin-dim">
                Not connected. <a href={`/api/qbo/connect?companyId=${company.id}`}>Authorize this client's QuickBooks →</a>
              </p>
            )}
          </div>

          <div className="cb-admin-section">
            <div className="cb-admin-section-title">Client logins</div>
            {detail?.users?.length ? (
              <ul className="cb-admin-users">
                {detail.users.map((u) => (
                  <li key={u.id}>
                    <span className="cb-admin-user-email">{u.email}</span>
                    {u.name && <span className="cb-admin-dim"> · {u.name}</span>}
                    <span className="cb-badge cb-badge-sm" data-on={u.activated ? '1' : '0'}>
                      {u.activated ? 'Active' : 'Invited'}
                    </span>
                    {!u.activated && (
                      <button type="button" className="cb-btn cb-btn-ghost cb-btn-xs"
                              onClick={() => resend(u.id)}>Resend invite</button>
                    )}
                  </li>
                ))}
              </ul>
            ) : <p className="cb-admin-dim">No logins yet.</p>}

            {notice?.type === 'emailed' && (
              <div className="cb-admin-notice"><IconCheck size={13} /> Invite emailed{notice.email ? ` to ${notice.email}` : ''}.</div>
            )}
            {notice?.type === 'devlink' && (
              <div className="cb-admin-notice">
                Email isn't configured yet — share this invite link manually:
                <input className="cb-input cb-admin-link" readOnly value={notice.link}
                       onFocus={(e) => e.target.select()} />
              </div>
            )}

            <form className="cb-admin-addlogin" onSubmit={addLogin}>
              <input className="cb-input" type="email" required placeholder="client@email.com"
                     value={email} onChange={(e) => setEmail(e.target.value)} />
              <input className="cb-input" type="text" placeholder="Name (optional)"
                     value={name} onChange={(e) => setName(e.target.value)} />
              <button type="submit" className="cb-btn cb-btn-primary cb-btn-sm" disabled={busy}>
                {busy ? 'Adding…' : 'Add & invite'}
              </button>
            </form>
          </div>
        </div>
      )}
    </div>
  );
}

function AddClientForm({ onCreated }) {
  const [name, setName] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const submit = async (e) => {
    e.preventDefault();
    setBusy(true); setErr(null);
    try { await CBAdmin.createCompany(name.trim()); setName(''); onCreated && onCreated(); }
    catch (ex) { setErr(ex.message); }
    finally { setBusy(false); }
  };
  return (
    <form className="cb-admin-addclient" onSubmit={submit}>
      <input className="cb-input" type="text" required placeholder="New client company name…"
             value={name} onChange={(e) => setName(e.target.value)} />
      <button type="submit" className="cb-btn cb-btn-primary" disabled={busy}>
        <IconPlus size={14} /> {busy ? 'Adding…' : 'Add client'}
      </button>
      {err && <span className="cb-auth-err cb-admin-inline-err">{err}</span>}
    </form>
  );
}

function AdminConsole({ user, onOpenDashboard }) {
  const [companies, setCompanies] = React.useState(null);
  const [err, setErr] = React.useState(null);

  const load = async () => {
    try { setCompanies(await CBAdmin.listCompanies()); setErr(null); }
    catch (e) { setErr(e.message); }
  };
  React.useEffect(() => { load(); }, []);

  return (
    <div className="cb-admin">
      <header className="cb-admin-top">
        <div className="cb-admin-brand">
          <span className="cb-brand-mark"><IconLogo size={20} /></span>
          <span className="cb-brand-name">contractor<i>books</i></span>
          <span className="cb-admin-tag">Admin</span>
        </div>
        <div className="cb-admin-top-right">
          <span className="cb-admin-dim">{user?.email}</span>
          <button type="button" className="cb-btn cb-btn-ghost cb-btn-sm"
                  onClick={() => window.__CB_LOGOUT && window.__CB_LOGOUT()}>Sign out</button>
        </div>
      </header>

      <main className="cb-admin-main">
        <div className="cb-admin-headline">
          <h1>Clients</h1>
          <p className="cb-admin-dim">Create a client, connect their QuickBooks, and invite them to their dashboard.</p>
        </div>

        <AddClientForm onCreated={load} />

        {err && <div className="cb-auth-err">{err}</div>}

        {companies === null ? (
          <p className="cb-admin-dim">Loading…</p>
        ) : companies.length === 0 ? (
          <div className="cb-admin-empty">No clients yet. Add your first client above.</div>
        ) : (
          <div className="cb-admin-list">
            {companies.map((c) => (
              <ClientRow key={c.id} company={c} onChanged={load} onOpenDashboard={onOpenDashboard} />
            ))}
          </div>
        )}
      </main>
    </div>
  );
}

/* Floating control shown while an admin is viewing a client's dashboard. */
function AdminBackBar({ companyName, onBack }) {
  return (
    <div className="cb-admin-backbar">
      <button type="button" className="cb-btn cb-btn-ghost cb-btn-sm" onClick={onBack}>← Clients</button>
      <span className="cb-admin-dim">Viewing <strong>{companyName}</strong> as admin</span>
    </div>
  );
}

/* Invite landing page: client sets their password, then is signed in. */
function SetPasswordScreen() {
  const [state, setState] = React.useState({ status: 'loading' });
  const [pw, setPw] = React.useState('');
  const [pw2, setPw2] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);

  const token = new URLSearchParams(location.search).get('token') || '';

  React.useEffect(() => {
    (async () => {
      if (!token) { setState({ status: 'invalid' }); return; }
      const r = await fetch(`/api/auth/invite/${encodeURIComponent(token)}`);
      if (!r.ok) { setState({ status: 'invalid' }); return; }
      setState({ status: 'ready', ...(await r.json()) });
    })();
  }, []);

  const submit = async (e) => {
    e.preventDefault();
    setErr(null);
    if (pw.length < 8) { setErr('Password must be at least 8 characters.'); return; }
    if (pw !== pw2) { setErr('Passwords do not match.'); return; }
    setBusy(true);
    try {
      const r = await fetch('/api/auth/set-password', {
        method: 'POST', credentials: 'same-origin',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token, password: pw }),
      });
      if (!r.ok) throw new Error((await r.json().catch(() => ({}))).error || 'Could not set password');
      window.location.href = '/'; // signed in → boot loads their dashboard
    } catch (ex) { setErr(ex.message); setBusy(false); }
  };

  if (state.status === 'loading') {
    return <div className="cb-auth"><div className="cb-auth-card"><p className="cb-auth-sub">Checking your invite…</p></div></div>;
  }
  if (state.status === 'invalid') {
    return (
      <div className="cb-auth"><div className="cb-auth-card">
        <h1 className="cb-auth-title">Link expired</h1>
        <p className="cb-auth-sub">This invite link is invalid or has expired. Ask your bookkeeper to send a new one.</p>
      </div></div>
    );
  }
  return (
    <div className="cb-auth">
      <form className="cb-auth-card" onSubmit={submit}>
        <div className="cb-auth-brand">
          <span className="cb-brand-mark"><IconLogo size={20} /></span>
          <span className="cb-brand-name">contractor<i>books</i></span>
        </div>
        <h1 className="cb-auth-title">Welcome{state.name ? `, ${state.name.split(' ')[0]}` : ''}</h1>
        <p className="cb-auth-sub">Choose a password for <strong>{state.email}</strong> to access your dashboard.</p>
        {err && <div className="cb-auth-err">{err}</div>}
        <label className="cb-auth-field">
          <span>New password</span>
          <input className="cb-input" type="password" autoComplete="new-password" required
                 value={pw} onChange={(e) => setPw(e.target.value)} />
        </label>
        <label className="cb-auth-field">
          <span>Confirm password</span>
          <input className="cb-input" type="password" autoComplete="new-password" required
                 value={pw2} onChange={(e) => setPw2(e.target.value)} />
        </label>
        <button type="submit" className="cb-btn cb-btn-primary cb-btn-block" disabled={busy}>
          {busy ? 'Setting up…' : 'Set password & sign in'}
        </button>
      </form>
    </div>
  );
}

Object.assign(window, { AdminConsole, AdminBackBar, SetPasswordScreen });
