'use client';

/**
 * TeamInvites — link-first teammate invites.
 *
 * Primary path: create a shareable link. The server builds the join URL from the
 * vault-resolved Supabase url + anon key (POST /api/orgs/[id]/invites returns
 * `joinPath`), so the link works whenever Supabase is configured — no
 * NEXT_PUBLIC_* baked into this browser build required. The recipient opens it,
 * signs in once, and is auto-joined (token carried in an httpOnly cookie, not
 * client storage).
 *
 * Secondary path: email pre-invite — they join automatically the first time they
 * sign in with that verified email.
 *
 * The raw token is shown ONCE (H1). Granted roles are bounded by the creator's
 * role (H5), enforced server-side and reflected in the role options here.
 */

import { useCallback, useEffect, useMemo, useState } from 'react';
import { Link2, Mail, Copy, Check, Trash2, Plus } from 'lucide-react';

const ROLE_CEILING = {
  owner: ['admin', 'member', 'viewer'],
  admin: ['member', 'viewer'],
};

function fmtExpiry(iso) {
  if (!iso) return 'no expiry';
  const ms = new Date(iso).getTime() - Date.now();
  if (ms <= 0) return 'expired';
  const h = Math.round(ms / 3_600_000);
  return h < 48 ? `in ${h}h` : `in ${Math.round(h / 24)}d`;
}

export default function TeamInvites({ orgId, creatorRole = 'owner', cloudReady = false }) {
  const allowedRoles = ROLE_CEILING[creatorRole] || ['member', 'viewer'];
  const base = `/api/orgs/${orgId}/invites`;

  const [invites, setInvites] = useState(null); // null = loading
  const [error, setError] = useState('');
  const [busy, setBusy] = useState('');
  const [created, setCreated] = useState(null); // { token, invite, url }
  const [copied, setCopied] = useState(''); // '' | 'link' | 'code'
  const [showOptions, setShowOptions] = useState(false);

  const [linkRole, setLinkRole] = useState('member');
  const [expiresInHours, setExpiresInHours] = useState('72');
  const [maxUses, setMaxUses] = useState('');

  const [email, setEmail] = useState('');
  const [emailRole, setEmailRole] = useState('member');

  const load = useCallback(async () => {
    try {
      const res = await fetch(base);
      const data = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(data.error || 'Failed to load invites');
      setInvites(data.invites || []);
      setError('');
    } catch (err) {
      setError(err.message);
      setInvites([]);
    }
  }, [base]);

  useEffect(() => { load(); }, [load]);

  const { emailInvites, linkInvites } = useMemo(() => {
    const list = invites || [];
    return {
      emailInvites: list.filter((i) => i.kind === 'email' || i.email),
      linkInvites: list.filter((i) => i.kind === 'link' || (!i.email && i.has_token)),
    };
  }, [invites]);

  async function createLink(e) {
    e?.preventDefault?.();
    setBusy('link'); setError('');
    try {
      const body = { role: linkRole };
      if (expiresInHours !== '') body.expiresInHours = Number(expiresInHours);
      if (maxUses !== '') body.maxUses = Number(maxUses);
      const res = await fetch(base, {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(data.message || data.error || 'Could not create link');
      const url = data.joinPath ? `${window.location.origin}${data.joinPath}` : '';
      setCreated({ token: data.token, invite: data.invite, url });
      setCopied('');
      setShowOptions(false);
      await load();
    } catch (err) { setError(err.message); }
    finally { setBusy(''); }
  }

  async function sendEmailInvite(e) {
    e.preventDefault();
    setBusy('email'); setError('');
    try {
      const res = await fetch(base, {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: email.trim(), role: emailRole }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(data.message || data.error || 'Could not send invite');
      setEmail('');
      await load();
    } catch (err) { setError(err.message); }
    finally { setBusy(''); }
  }

  async function revoke(id) {
    setBusy(id); setError('');
    try {
      const res = await fetch(`${base}/${id}`, { method: 'DELETE' });
      if (!res.ok) {
        const data = await res.json().catch(() => ({}));
        throw new Error(data.error || 'Could not revoke');
      }
      await load();
    } catch (err) { setError(err.message); }
    finally { setBusy(''); }
  }

  async function copy(value, which) {
    try {
      await navigator.clipboard.writeText(value);
      setCopied(which);
      setTimeout(() => setCopied(''), 2000);
    } catch { /* clipboard blocked — text is selectable */ }
  }

  const roleOptions = (
    <>{allowedRoles.map((r) => <option key={r} value={r}>{r}</option>)}</>
  );

  return (
    <div className="admin-card-list">
      {error ? (
        <div className="admin-record" role="alert" style={{ borderColor: 'var(--accent-500)', color: 'var(--accent-600)' }}>
          {error}
        </div>
      ) : null}

      {/* One-time reveal */}
      {created ? (
        <div className="admin-record" style={{ borderColor: 'var(--accent-500)' }}>
          <div className="admin-record-top">
            <b style={{ display: 'inline-flex', alignItems: 'center', gap: '0.45rem' }}>
              <Check className="settings-rail-icon" strokeWidth={2} aria-hidden="true" />
              Invite link ready
            </b>
            <span className="admin-pill mars">Shown once</span>
          </div>
          <p className="admin-muted" style={{ fontSize: '0.85em', margin: '0.35rem 0 0.6rem' }}>
            {created.url
              ? 'Send this link. They sign in once and join automatically.'
              : 'Connect Supabase to generate a one-click link. For now, share this code — they paste it under “Join with code”.'}
          </p>

          {created.url ? (
            <>
              <code className="team-invite-code">{created.url}</code>
              <div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap', marginTop: '0.5rem' }}>
                <button className="admin-btn-primary admin-btn-sm" onClick={() => copy(created.url, 'link')}
                  style={{ display: 'inline-flex', alignItems: 'center', gap: '0.4rem' }}>
                  {copied === 'link' ? <Check className="settings-rail-icon" strokeWidth={2} /> : <Copy className="settings-rail-icon" strokeWidth={1.75} />}
                  {copied === 'link' ? 'Copied' : 'Copy link'}
                </button>
                <button className="admin-btn-sm" onClick={() => setCreated(null)}>Done</button>
              </div>
            </>
          ) : (
            <>
              <code className="team-invite-code">{created.token}</code>
              <div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap', marginTop: '0.5rem' }}>
                <button className="admin-btn-primary admin-btn-sm" onClick={() => copy(created.token, 'code')}
                  style={{ display: 'inline-flex', alignItems: 'center', gap: '0.4rem' }}>
                  {copied === 'code' ? <Check className="settings-rail-icon" strokeWidth={2} /> : <Copy className="settings-rail-icon" strokeWidth={1.75} />}
                  {copied === 'code' ? 'Copied' : 'Copy code'}
                </button>
                <button className="admin-btn-sm" onClick={() => setCreated(null)}>Done</button>
              </div>
            </>
          )}
          <div className="admin-muted" style={{ fontSize: '0.8em', marginTop: '0.5rem' }}>
            {created.invite?.role} · {created.invite?.max_uses ? `${created.invite.max_uses} uses` : 'unlimited uses'} · expires {fmtExpiry(created.invite?.expires_at)}
          </div>
        </div>
      ) : null}

      {/* Primary: create link */}
      <div className="admin-record">
        <div className="admin-record-top">
          <b style={{ display: 'inline-flex', alignItems: 'center', gap: '0.45rem' }}>
            <Link2 className="settings-rail-icon" strokeWidth={1.75} aria-hidden="true" />
            Shareable invite link
          </b>
          <button type="button" className="admin-btn-sm" onClick={() => setShowOptions((v) => !v)}>
            {showOptions ? 'Hide options' : 'Options'}
          </button>
        </div>
        <p className="admin-muted" style={{ fontSize: '0.85em', margin: '0.35rem 0 0.6rem' }}>
          One link, sign in, joined. {cloudReady ? '' : 'Connect Supabase above for one-click links.'}
        </p>

        <form onSubmit={createLink} style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap', alignItems: 'flex-end' }}>
          {showOptions ? (
            <>
              <label className="admin-field" style={{ minWidth: 120 }}>
                <span>Role</span>
                <select className="admin-select" value={linkRole} onChange={(e) => setLinkRole(e.target.value)}>{roleOptions}</select>
              </label>
              <label className="admin-field" style={{ minWidth: 120 }}>
                <span>Expires</span>
                <select className="admin-select" value={expiresInHours} onChange={(e) => setExpiresInHours(e.target.value)}>
                  <option value="24">24 hours</option>
                  <option value="72">72 hours</option>
                  <option value="168">7 days</option>
                  <option value="">No expiry</option>
                </select>
              </label>
              <label className="admin-field" style={{ minWidth: 140 }}>
                <span>Max uses</span>
                <input className="admin-input" type="number" min="1" value={maxUses}
                  onChange={(e) => setMaxUses(e.target.value)} placeholder="Unlimited" />
              </label>
            </>
          ) : null}
          <button type="submit" className="admin-btn-primary" disabled={busy === 'link'}
            style={{ display: 'inline-flex', alignItems: 'center', gap: '0.4rem' }}>
            <Plus className="settings-rail-icon" strokeWidth={2} aria-hidden="true" />
            {busy === 'link' ? 'Creating…' : 'Create invite link'}
          </button>
        </form>
      </div>

      {/* Secondary: email pre-invite */}
      <form className="admin-record" onSubmit={sendEmailInvite}>
        <div className="admin-record-top">
          <b style={{ display: 'inline-flex', alignItems: 'center', gap: '0.45rem' }}>
            <Mail className="settings-rail-icon" strokeWidth={1.75} aria-hidden="true" />
            Invite by email
          </b>
        </div>
        <p className="admin-muted" style={{ fontSize: '0.85em', margin: '0.35rem 0 0.6rem' }}>
          They join automatically the first time they sign in with this email.
        </p>
        <div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap', alignItems: 'flex-end' }}>
          <label className="admin-field" style={{ flex: 1, minWidth: 200 }}>
            <span>Email</span>
            <input className="admin-input" type="email" value={email}
              onChange={(e) => setEmail(e.target.value)} placeholder="teammate@example.com" />
          </label>
          <label className="admin-field" style={{ minWidth: 120 }}>
            <span>Role</span>
            <select className="admin-select" value={emailRole} onChange={(e) => setEmailRole(e.target.value)}>{roleOptions}</select>
          </label>
          <button type="submit" className="admin-btn-primary" disabled={busy === 'email' || !email.trim()}>
            {busy === 'email' ? 'Sending…' : 'Add'}
          </button>
        </div>
      </form>

      {/* Active invites */}
      {invites === null ? (
        <div className="admin-record admin-muted">Loading invites…</div>
      ) : (emailInvites.length === 0 && linkInvites.length === 0) ? (
        <div className="admin-record admin-muted">No active invites.</div>
      ) : (
        <div className="admin-record">
          <div className="admin-record-top"><b>Active invites</b></div>
          <ul className="team-invite-list">
            {linkInvites.map((i) => (
              <li key={i.id}>
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: '0.4rem' }}>
                  <Link2 className="settings-rail-icon" strokeWidth={1.75} aria-hidden="true" />
                  {i.label || 'Invite link'} · {i.role} · {i.used_count}{i.max_uses ? `/${i.max_uses}` : ''} used · expires {fmtExpiry(i.expires_at)}
                </span>
                <button className="admin-btn-danger-sm" disabled={busy === i.id} onClick={() => revoke(i.id)}
                  style={{ display: 'inline-flex', alignItems: 'center', gap: '0.35rem' }}>
                  <Trash2 className="settings-rail-icon" strokeWidth={1.75} aria-hidden="true" />
                  {busy === i.id ? '…' : 'Revoke'}
                </button>
              </li>
            ))}
            {emailInvites.map((i) => (
              <li key={i.id}>
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: '0.4rem' }}>
                  <Mail className="settings-rail-icon" strokeWidth={1.75} aria-hidden="true" />
                  {i.email} · {i.role} · expires {fmtExpiry(i.expires_at)}
                </span>
                <button className="admin-btn-danger-sm" disabled={busy === i.id} onClick={() => revoke(i.id)}
                  style={{ display: 'inline-flex', alignItems: 'center', gap: '0.35rem' }}>
                  <Trash2 className="settings-rail-icon" strokeWidth={1.75} aria-hidden="true" />
                  {busy === i.id ? '…' : 'Revoke'}
                </button>
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}
