// Team Sync pages — skill/prompt sharing for personal users, org member
// management for org accounts. Client: team_sync_api.jsx.
//
//   TeamSyncPage({ mode })   — left: Skills / Prompts tabs; right: persistent
//                              daemon install/uninstall rail.
//   MembersPage({ session }) — org-only: list / add-by-email / remove members.
//
// Skills tab: pick a device → see each of its agents and the skills each agent
// has installed (managed vs local), deploy shared skills to an agent, and the
// team skills library (import / delete). Prompts tab: my prompts + shared
// prompts. Capability split mirrors the backend (users/me/* and library writes
// are user-only), so org accounts get the read / deploy / delete surfaces only.

const { useState: useTsS, useEffect: useTsE, useRef: useTsR } = React;

// ── PromptsPanel ──────────────────────────────────────────────────────────────
function PromptsPanel({ orgId, personal, isPersonalWorkspace }) {
  const [prompts, setPrompts] = useTsS(personal ? null : []);   // my prompts (personal only)
  const [shared, setShared] = useTsS(null);
  const [name, setName] = useTsS('');
  const [desc, setDesc] = useTsS('');
  const [content, setContent] = useTsS('');
  const [busy, setBusy] = useTsS(false);
  const [flash, showFlash] = useFlash();
  const [view, setView] = useTsS(null);   // prompt clicked → modal
  const selMine = useSel();
  const selShared = useSel();
  const confirm = useConfirm();

  const loadMine = () => { if (personal) tsListUserPrompts(orgId).then(setPrompts).catch(e => showFlash(e.message, 'error')); };
  // Shared prompt library is org-only; a personal workspace has none.
  const loadShared = () => {
    if (isPersonalWorkspace) { setShared([]); return; }
    return tsListSharedPrompts(orgId).then(setShared).catch(e => showFlash(e.message, 'error'));
  };
  useTsE(() => {
    selMine.clear(); selShared.clear();
    if (personal) setPrompts(null);
    loadMine(); setShared(null); loadShared();
  }, [orgId]);

  const create = async () => {
    if (!name.trim() || !content.trim()) { showFlash('Name and content are required', 'error'); return; }
    setBusy(true);
    try {
      await tsCreateUserPrompt(orgId, { name: name.trim(), description: desc.trim() || null, content });
      setName(''); setDesc(''); setContent(''); await loadMine();
      showFlash('Prompt saved');
    } catch (e) { showFlash(e.message, 'error'); } finally { setBusy(false); }
  };

  const shareMine = async () => {
    const ids = Array.from(selMine.ids);
    if (!ids.length) { showFlash('Select one or more prompts first', 'error'); return; }
    setBusy(true);
    try { await tsSharePrompts(orgId, ids); showFlash(`Shared ${ids.length} prompt(s)`); selMine.clear(); loadShared(); }
    catch (e) { showFlash(e.message, 'error'); } finally { setBusy(false); }
  };
  const doDeleteMine = async () => {
    const ids = Array.from(selMine.ids);
    if (!ids.length) return;
    setBusy(true);
    try { for (const id of ids) await tsDeleteUserPrompt(orgId, id); showFlash(`Deleted ${ids.length} prompt(s)`); selMine.clear(); loadMine(); }
    catch (e) { showFlash(e.message, 'error'); } finally { setBusy(false); }
  };
  const deleteMine = () => { const n = selMine.ids.size; if (!n) { showFlash('Select one or more prompts first', 'error'); return; } confirm.ask(`Delete ${n} prompt(s) from My Prompts?`, 'Delete', doDeleteMine); };

  const doDeleteShared = async () => {
    const ids = Array.from(selShared.ids);
    if (!ids.length) return;
    setBusy(true);
    try { for (const id of ids) await tsDeleteLibraryPrompt(orgId, id); showFlash(`Deleted ${ids.length} from library`); selShared.clear(); loadShared(); }
    catch (e) { showFlash(e.message, 'error'); } finally { setBusy(false); }
  };
  const deleteShared = () => { const n = selShared.ids.size; if (!n) { showFlash('Select one or more prompts first', 'error'); return; } confirm.ask(`Delete ${n} prompt(s) from the shared library? This removes it for everyone in the org.`, 'Delete', doDeleteShared); };

  const mineActions = (
    <>
      {!isPersonalWorkspace && <button className="btn sm" disabled={busy} onClick={shareMine}>⇧ Share</button>}
      <button className="btn sm danger" disabled={busy} onClick={deleteMine}>⌫ Delete</button>
      <button className="btn sm ghost" onClick={loadMine}>↻</button>
    </>
  );
  const sharedActions = (
    <>
      <button className="btn sm danger" disabled={busy} onClick={deleteShared}>⌫ Delete</button>
      <button className="btn sm ghost" onClick={loadShared}>↻</button>
    </>
  );

  return (
    <div>
      {personal && (
        <TsSection title="New prompt">
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginBottom: 10 }}>
            <TsField label="Name"><input style={fieldStyle} value={name} onChange={e => setName(e.target.value)} placeholder="Bug triage" /></TsField>
            <TsField label="Description"><input style={fieldStyle} value={desc} onChange={e => setDesc(e.target.value)} placeholder="Quickly assess bug priority" /></TsField>
          </div>
          <TsField label="Content">
            <textarea value={content} onChange={e => setContent(e.target.value)} placeholder="Enter a prompt to save"
              style={{ ...fieldStyle, height: 90, padding: 10, lineHeight: 1.5 }} />
          </TsField>
          <div style={{ marginTop: 10 }}>
            <button className="btn accent" disabled={busy} onClick={create}>＋ Save to My Prompts</button>
          </div>
        </TsSection>
      )}

      {personal && (
        <TsSection title="My Prompts" collapsible count={prompts ? prompts.length : undefined} lead={<SelectAllChk ids={(prompts || []).map(p => p.id)} sel={selMine} />} actions={mineActions}>
          {prompts === null && <div className="text-secondary t-small">Loading…</div>}
          {prompts && prompts.length === 0 && <div className="text-secondary t-small">No prompts yet.</div>}
          {prompts && prompts.map(p => (
            <SkillRow key={p.id} checked={selMine.ids.has(p.id)} onToggle={() => selMine.toggle(p.id)} onView={() => setView(p)}>
              <span style={{ fontSize: 13, fontWeight: 500 }}>{p.name}</span>
            </SkillRow>
          ))}
        </TsSection>
      )}

      {!isPersonalWorkspace && (
        <TsSection title="Shared prompt library" collapsible count={shared ? shared.length : undefined} lead={<SelectAllChk ids={(shared || []).map(p => p.prompt_id)} sel={selShared} />} actions={sharedActions}>
          {shared === null && <div className="text-secondary t-small">Loading…</div>}
          {shared && shared.length === 0 && <div className="text-secondary t-small">No shared prompts yet.</div>}
          {shared && shared.map(p => (
            <SkillRow key={p.prompt_id} checked={selShared.ids.has(p.prompt_id)} onToggle={() => selShared.toggle(p.prompt_id)} onView={() => setView(p)}>
              <span style={{ fontSize: 13, fontWeight: 500 }}>{p.name}</span>
            </SkillRow>
          ))}
        </TsSection>
      )}

      <TsFlash flash={flash} />
      <ConfirmDialog req={confirm.req} onClose={confirm.close} />
      <PromptModal item={view} onClose={() => setView(null)} />
    </div>
  );
}

// ── DaemonRail — persistent install / uninstall on the right ──────────────────
function DaemonRail({ orgId, autoCollapse }) {
  const [collapsed, setCollapsed] = useTsS(false);
  // Auto-collapse when a skill detail opens, so this panel doesn't push the
  // detail off-screen. Manual toggle still works; it only re-collapses each time
  // a new skill is opened (autoCollapse flips false→true).
  useTsE(() => { if (autoCollapse) setCollapsed(true); }, [autoCollapse]);
  const [platform, setPlatform] = useTsS(() => {
    const p = (typeof navigator !== 'undefined' && navigator.platform || '').toLowerCase();
    if (p.includes('mac')) return 'macos';
    if (p.includes('linux') || p.includes('x11')) return 'linux';
    return 'windows';
  });
  const [devName, setDevName] = useTsS('');
  const [dialogCmd, setDialogCmd] = useTsS(null);   // generated command shown in the "copied" dialog
  const [busy, setBusy] = useTsS(false);
  const [flash, showFlash] = useFlash();

  // Copy the command to the clipboard and pop the confirm dialog.
  const present = async (cmd) => {
    try { await navigator.clipboard.writeText(cmd); } catch (e) { /* clipboard blocked — dialog still shows it */ }
    setDialogCmd(cmd);
  };
  const install = async () => {
    if (!devName.trim()) { showFlash('Device name is required', 'error'); return; }
    setBusy(true);
    try {
      const r = await tsCreateInstallCommand(orgId, { platform, name: devName.trim(), os: platform });
      await present(r.install_command || '');
    } catch (e) { showFlash(e.message, 'error'); } finally { setBusy(false); }
  };
  const uninstall = async () => {
    setBusy(true);
    try {
      const r = await tsCreateUninstallCommand(orgId, platform);
      await present(r.uninstall_command || '');
    } catch (e) { showFlash(e.message, 'error'); } finally { setBusy(false); }
  };

  return (
    <div className="card" style={{ padding: 16 }}>
      <div onClick={() => setCollapsed(c => !c)} style={{ display: 'flex', alignItems: 'center', marginBottom: collapsed ? 0 : 8, gap: 6, cursor: 'pointer', userSelect: 'none' }}>
        <span className="text-tertiary" style={{ fontSize: 10, width: 9, display: 'inline-block' }}>{collapsed ? '▶' : '▼'}</span>
        <span className="t-micro text-tertiary" style={{ textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 600 }}>Daemon</span>
        <div style={{ flex: 1 }} />
        <span className="mono-sm mono text-tertiary">{platform}</span>
      </div>
      {!collapsed && (<>
      <div className="text-tertiary t-small" style={{ marginBottom: 12 }}>Each device runs its own daemon.</div>

      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        <TsField label="Platform">
          <select style={fieldStyle} value={platform} onChange={e => setPlatform(e.target.value)}>
            <option value="windows">Windows</option>
            <option value="macos">macOS</option>
            <option value="linux">Linux</option>
          </select>
        </TsField>
        <TsField label="Device name"><input style={fieldStyle} value={devName} onChange={e => setDevName(e.target.value)} placeholder="Name this device" /></TsField>
        <button className="btn accent" disabled={busy} onClick={install} style={{ justifyContent: 'center' }}>⧉ Install</button>
      </div>

      <div style={{ borderTop: '1px solid var(--border-subtle)', margin: '14px 0' }} />

      <button className="btn" disabled={busy} onClick={uninstall} style={{ width: '100%', justifyContent: 'center' }}>⌫ Uninstall</button>
      </>)}
      <TsFlash flash={flash} />

      {dialogCmd != null && (
        <div onClick={() => setDialogCmd(null)} style={{
          position: 'fixed', inset: 0, background: 'rgba(0,0,0,.4)', zIndex: 130,
          display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24,
        }}>
          <div onClick={e => e.stopPropagation()} style={{
            width: 460, maxWidth: '100%', background: 'var(--surface-raised)',
            border: '1px solid var(--border)', borderRadius: 14, boxShadow: 'var(--shadow-2)', padding: 20,
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
              <span style={{ width: 28, height: 28, borderRadius: 8, flexShrink: 0, background: 'var(--accent-muted)', color: 'var(--accent-text)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                {typeof Icons !== 'undefined' && Icons.Check ? <Icons.Check size={15} /> : '✓'}
              </span>
              <h3 className="t-h3" style={{ margin: 0 }}>Copied to your clipboard</h3>
            </div>
            <div className="text-secondary t-small" style={{ marginBottom: 12 }}>
              Paste and run it in your {platform === 'windows' ? 'PowerShell' : 'terminal'}.
            </div>
            <CodeBlock language="bash">{dialogCmd}</CodeBlock>
            <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 14 }}>
              <button className="btn accent" onClick={() => setDialogCmd(null)}>Done</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ── TeamSyncPage ──────────────────────────────────────────────────────────────
function TeamSyncPage({ mode }) {
  const personal = mode !== 'org';
  const { orgs, workspaces, orgId, setOrgId, error, isPersonalWorkspace } = useOrgContext(mode);
  const tabs = [['skills', 'Skills'], ['prompts', 'Prompts']];
  const [tab, setTab] = useTsS('skills');
  const [viewSkill, setViewSkill] = useTsS(null);   // skill clicked for the detail rail
  const [skillRefresh, setSkillRefresh] = useTsS(0); // bump → SkillsPanel re-pulls lists

  // AUTO SYNC — the BACKEND owns the flag and all reconciliation. The frontend
  // only reads/writes the flag and animates the enable response.
  const [autoSync, setAutoSync] = useTsS(false);
  const [autoBusy, setAutoBusy] = useTsS(false);
  const [syncTask, setSyncTask] = useTsS(null);     // { plan, task } → the first-run animation is playing
  const autoConfirm = useConfirm();
  const [autoFlash, showAutoFlash] = useFlash();

  // Load the persisted flag from the backend (source of truth).
  useTsE(() => {
    if (!personal || !orgId) return undefined;
    let cancelled = false;
    tsGetAutoSync(orgId).then(r => { if (!cancelled) setAutoSync(!!(r && r.enabled)); }).catch(() => {});
    return () => { cancelled = true; };
  }, [personal, orgId]);

  // Enable: the backend persists the flag, reconciles, and returns the plan +
  // operation_ids. We just animate the plan and wait for the operations to
  // finish (so the overlay closes only once the sync work is actually done).
  const runFirstSync = async () => {
    setAutoBusy(true);
    try {
      const res = await tsSetAutoSync(orgId, true);
      setAutoSync(true);
      const plan = (res && res.plan) || { skills_synced: 0, skipped: 0, agents: [] };
      if (!plan.agents || !plan.agents.length) {
        showAutoFlash('Auto-sync on — no agents online yet. Skills will sync when a device connects.');
        return;
      }
      setSyncTask({ plan, task: tsAwaitOperations(orgId, (res && res.operation_ids) || []) });
    } catch (e) { showAutoFlash((e && e.message) || 'Could not start auto-sync', 'error'); }
    finally { setAutoBusy(false); }
  };
  const onToggleAuto = (next) => {
    if (next) {
      autoConfirm.ask(
        'Keep your Cloud skills synced to every agent across all your devices — automatically, as you add skills or connect devices. Same-named skills only sync to agents of their source type.',
        'Enable auto-sync', runFirstSync);
    } else {
      setAutoBusy(true);
      tsSetAutoSync(orgId, false)
        .then(() => { setAutoSync(false); showAutoFlash('Auto-sync off'); })
        .catch(e => showAutoFlash((e && e.message) || 'Could not turn off auto-sync', 'error'))
        .finally(() => setAutoBusy(false));
    }
  };

  const wrap = { padding: '32px 32px 80px', maxWidth: 1280, margin: '0 auto' };

  if (error) {
    return <div style={wrap}><h1 className="t-h1" style={{ margin: 0 }}>Team Sync</h1><div className="text-secondary t-body" style={{ marginTop: 8 }}>{error}</div></div>;
  }
  if (personal && orgs === null) {
    return <div style={wrap}><h1 className="t-h1" style={{ margin: 0 }}>Team Sync</h1><div className="text-secondary t-body" style={{ marginTop: 8 }}>Loading your workspace…</div></div>;
  }

  return (
    <div style={{ display: 'flex', gap: 24, alignItems: 'flex-start', ...wrap }}>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, flexWrap: 'wrap' }}>
          <div>
            <h1 className="t-h1" style={{ margin: 0 }}>Team Sync</h1>
            <div className="text-secondary t-body" style={{ marginTop: 4 }}>Share skills and prompts across your team.</div>
          </div>
          <div style={{ flex: 1 }} />
          <div style={{ display: 'flex', alignItems: 'center', gap: 16, flexWrap: 'wrap' }}>
            {personal && <AutoSyncToggle on={autoSync} busy={autoBusy} onToggle={onToggleAuto} />}
            {personal && workspaces && workspaces.length > 1 && (
              <label style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <span className="t-micro text-tertiary">Workspace</span>
                <select style={{ ...fieldStyle, width: 'auto', height: 32 }} value={orgId || ''} onChange={e => setOrgId(e.target.value)}>
                  {workspaces.map(w => <option key={w.id} value={w.id}>{w.personal ? 'Personal' : w.email}</option>)}
                </select>
              </label>
            )}
          </div>
        </div>

        <div className="segmented" style={{ margin: '20px 0', display: 'inline-flex' }}>
          {tabs.map(([k, label]) => (
            <button key={k} className={tab === k ? 'active' : ''} onClick={() => setTab(k)}>{label}</button>
          ))}
        </div>

        {orgId && tab === 'skills' && <SkillsPanel orgId={orgId} personal={personal} isPersonalWorkspace={isPersonalWorkspace} onView={setViewSkill} reloadSignal={skillRefresh} />}
        {orgId && tab === 'prompts' && <PromptsPanel orgId={orgId} personal={personal} isPersonalWorkspace={isPersonalWorkspace} />}
      </div>

      {tab === 'skills' && (personal || viewSkill) && (
        <div style={{ width: 300, flexShrink: 0, position: 'sticky', top: 16, alignSelf: 'flex-start' }}>
          {orgId && personal && <DaemonRail orgId={orgId} autoCollapse={!!viewSkill} />}
          {orgId && viewSkill && <SkillDetail key={viewSkill.bundle_id || viewSkill.cloud_skill_id || viewSkill.team_skill_id || viewSkill.name} item={viewSkill} orgId={orgId} onClose={() => setViewSkill(null)} onSaved={() => setSkillRefresh(n => n + 1)} />}
        </div>
      )}

      <ConfirmDialog req={autoConfirm.req} onClose={autoConfirm.close} />
      <TsFlash flash={autoFlash} />
      {syncTask && <AutoSyncOverlay plan={syncTask.plan} task={syncTask.task} onDone={() => setSyncTask(null)} />}
    </div>
  );
}

// ── MembersPage (org-only) ────────────────────────────────────────────────────
function MembersPage({ session }) {
  const orgId = (session && session.account && session.account.id) || (typeof parcleAccount === 'function' && parcleAccount() ? parcleAccount().id : 'org_mock_1');
  const [members, setMembers] = useTsS(null);
  const [email, setEmail] = useTsS('');
  const [found, setFound] = useTsS(null);
  const [busy, setBusy] = useTsS(false);
  const [flash, showFlash] = useFlash();

  const load = () => tsListMembers(orgId).then(setMembers).catch(e => showFlash(e.message, 'error'));
  useTsE(() => { setMembers(null); load(); }, [orgId]);

  const search = async () => {
    if (!email.trim()) return;
    setBusy(true); setFound(null);
    try {
      const acct = await tsSearchUserByEmail(orgId, email.trim());
      setFound(acct);
    } catch (e) {
      if (e.status === 404) showFlash('No user account with that email', 'error');
      else showFlash(e.message, 'error');
    } finally { setBusy(false); }
  };
  const add = async () => {
    if (!found) return;
    setBusy(true);
    try { await tsAddMember(orgId, found.id); setFound(null); setEmail(''); await load(); showFlash('Member added'); }
    catch (e) { showFlash(e.message, 'error'); } finally { setBusy(false); }
  };
  const remove = async (userId) => {
    setBusy(true);
    try { await tsRemoveMember(orgId, userId); await load(); showFlash('Member removed'); }
    catch (e) { showFlash(e.message, 'error'); } finally { setBusy(false); }
  };

  return (
    <div style={{ padding: '32px 32px 80px', maxWidth: 900, margin: '0 auto' }}>
      <h1 className="t-h1" style={{ margin: 0 }}>Members</h1>
      <div className="text-secondary t-body" style={{ marginTop: 4 }}>Add people to your organization by email.</div>

      <TsSection title="Add a member">
        <div style={{ display: 'flex', gap: 8, alignItems: 'flex-end', flexWrap: 'wrap' }}>
          <TsField label="User email">
            <input style={fieldStyle} value={email} type="email"
              onChange={e => { setEmail(e.target.value); setFound(null); }}
              onKeyDown={e => { if (e.key === 'Enter') search(); }} placeholder="teammate@company.com" />
          </TsField>
          <button className="btn" disabled={busy || !email.trim()} onClick={search}>Search</button>
        </div>
        {found && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 12, padding: '10px 12px', border: '1px solid var(--border-subtle)', borderRadius: 8 }}>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 13, fontWeight: 500 }}>{found.email}</div>
              <div className="mono-sm mono text-tertiary">{found.kind} · {found.id}</div>
            </div>
            <button className="btn sm accent" disabled={busy} onClick={add}>＋ Add to org</button>
          </div>
        )}
        <TsFlash flash={flash} />
      </TsSection>

      <TsSection title="Current members" actions={<button className="btn sm ghost" onClick={load}>↻</button>}>
        {members === null && <div className="text-secondary t-small">Loading…</div>}
        {members && members.length === 0 && <div className="text-secondary t-small">No members yet.</div>}
        {members && members.map(m => (
          <div key={m.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 12px', border: '1px solid var(--border-subtle)', borderRadius: 8, marginBottom: 6, background: 'var(--surface)' }}>
            <span style={{ fontSize: 13, fontWeight: 500 }}>{m.email}</span>
            <span className="mono-sm mono text-tertiary">{m.kind}</span>
            <div style={{ flex: 1 }} />
            <button className="btn sm danger" disabled={busy} onClick={() => remove(m.id)}>Remove</button>
          </div>
        ))}
      </TsSection>
    </div>
  );
}

Object.assign(window, { TeamSyncPage, MembersPage });
