// Install ask-parcle skill into one of the supported AI clients
// (Claude Code / Codex / OpenClaw / Hermes), on Windows / macOS / Linux.
//
// Per-platform one-line command that downloads SKILL.md (served with
// {base_url} already substituted by GET /skill/skill.md) into the chosen
// client's ~/.<client>/skills/ask-parcle/ directory. Windows uses Invoke-WebRequest;
// macOS / Linux use curl. The command body is plain HTTP fetches — no
// embedded base64 — so a non-technical viewer can read it end-to-end before
// pasting. The command also pre-checks that the client's home dir exists so
// users who haven't installed that client get a friendly error.

const { useState: useIs, useEffect: useIsEffect } = React;

// Each supported client uses the same skill layout (SKILL.md) under a
// different home-relative config dir. dirSlug is the only per-client
// difference; the generated command also checks this dir exists before
// writing so a user who hasn't installed the client gets a friendly error
// instead of a stray folder.
const CLIENT_META = {
  claudecode: { name: 'Claude Code', dirSlug: '.claude' },
  codex:      { name: 'Codex',       dirSlug: '.codex' },
  openclaw:   { name: 'OpenClaw',    dirSlug: '.openclaw' },
  hermes:     { name: 'Hermes',      dirSlug: '.hermes' },
};

const DEFAULT_CLIENT = 'claudecode';

function clientTargetPath(client, platform) {
  const slug = CLIENT_META[client].dirSlug;
  return platform === 'windows'
    ? `%USERPROFILE%\\${slug}\\skills\\ask-parcle\\`
    : `~/${slug}/skills/ask-parcle/`;
}

const PLATFORM_META = {
  windows: {
    tab: 'Windows',
    shellLabel: 'powershell',
    instruction: 'Open PowerShell (Win+X → Windows PowerShell), paste this command, press Enter:',
  },
  macos: {
    tab: 'macOS',
    shellLabel: 'bash',
    instruction: 'Open Terminal (⌘Space → "Terminal"), paste this command, press Enter:',
  },
  linux: {
    tab: 'Linux',
    shellLabel: 'bash',
    instruction: 'Open a terminal, paste this command, press Enter:',
  },
};

const PLATFORM_ORDER = ['windows', 'macos', 'linux'];

function detectPlatform() {
  // Prefer the modern, non-deprecated `navigator.userAgentData.platform`
  // (Chromium 93+). Fall back to `navigator.platform` / `userAgent` for
  // Safari, Firefox, and older browsers.
  const uad = (navigator.userAgentData && navigator.userAgentData.platform || '').toLowerCase();
  if (uad === 'windows') return 'windows';
  if (uad === 'macos') return 'macos';
  if (uad === 'linux' || uad === 'chrome os') return 'linux';
  const plat = (navigator.platform || '').toLowerCase();
  const ua = (navigator.userAgent || '').toLowerCase();
  if (plat.indexOf('win') !== -1 || ua.indexOf('windows') !== -1) return 'windows';
  if (plat.indexOf('mac') !== -1 || ua.indexOf('mac os') !== -1 || ua.indexOf('macintosh') !== -1) return 'macos';
  return 'linux';
}

// Wraps the install steps in `if (Test-Path) { ... } else { ... }` so a pasted
// command on a machine without the client installed prints a friendly error
// instead of creating a stray ~/.<client>/ directory. Avoids `exit` so an
// interactive PowerShell window stays open after the error.
function buildPsCommand(apiBase, client) {
  const meta = CLIENT_META[client];
  const checkPath = '$env:USERPROFILE\\' + meta.dirSlug;
  const inner = [
    '$d="' + checkPath + '\\skills\\ask-parcle"',
    'New-Item -Force -ItemType Directory -Path $d | Out-Null',
    'Invoke-WebRequest -UseBasicParsing -Uri "' + apiBase + '/skill/skill.md" -OutFile "$d\\SKILL.md"',
    'Write-Host "ask-parcle installed at $d" -ForegroundColor Green',
  ];
  const errorMsg = meta.name + " doesn't look installed (~/" + meta.dirSlug + ' not found).';
  return 'if (Test-Path "' + checkPath + '") { ' + inner.join('; ') + ' } else { Write-Host "' + errorMsg + '" -ForegroundColor Red }';
}

function buildBashCommand(apiBase, client) {
  const meta = CLIENT_META[client];
  const checkPath = '$HOME/' + meta.dirSlug;
  const inner = [
    'd="' + checkPath + '/skills/ask-parcle"',
    'mkdir -p "$d"',
    'curl -fsSL "' + apiBase + '/skill/skill.md" -o "$d/SKILL.md"',
    'echo "ask-parcle installed at $d"',
  ];
  const errorMsg = meta.name + " doesn't look installed (~/" + meta.dirSlug + ' not found).';
  return 'if [ -d "' + checkPath + '" ]; then ' + inner.join(' && ') + '; else echo "' + errorMsg + '"; fi';
}

function buildAllCommands(apiBase, client) {
  return {
    windows: buildPsCommand(apiBase, client),
    macos: buildBashCommand(apiBase, client),
    linux: buildBashCommand(apiBase, client),
  };
}

function InstallSkillModal({ open, client = DEFAULT_CLIENT, onClose }) {
  const apiBase = window.PARCLE_API_BASE || null;
  const [phase, setPhase] = useIs('idle');           // idle | preparing | ready | failed
  const [commands, setCommands] = useIs(null);
  const [error, setError] = useIs(null);
  const [pathCopied, setPathCopied] = useIs(false);
  const [cmdCopied, setCmdCopied] = useIs(false);
  const [platform, setPlatform] = useIs(detectPlatform);

  useIsEffect(() => {
    if (!open) {
      setPhase('idle');
      setCommands(null);
      setError(null);
      setPathCopied(false);
      setCmdCopied(false);
      setPlatform(detectPlatform());
      return;
    }

    if (!apiBase) {
      setPhase('failed');
      setError('No backend configured. Edit config.js to point apiBase at a real backend, then refresh and try again.');
      return;
    }

    setPhase('preparing');
    let cancelled = false;

    // Probe that SKILL.md is actually served before handing the user a command
    // that downloads it — a 404/503 here means the backend isn't deployed, and
    // we'd rather surface that than hand out a command that silently fails.
    // GET, not HEAD: the backend's @router.get only registers GET; FastAPI
    // does not auto-allow HEAD on GET routes, so a HEAD probe gets 405.
    fetch(apiBase + '/skill/skill.md')
      .then((r) => {
        if (!r.ok) throw new Error('SKILL.md unavailable at ' + r.url + ' (HTTP ' + r.status + ')');
        if (cancelled) return;
        setCommands(buildAllCommands(apiBase, client));
        setPhase('ready');
      })
      .catch((err) => {
        if (cancelled) return;
        setPhase('failed');
        setError(err.message || String(err));
      });

    return () => { cancelled = true; };
  }, [open, apiBase, client]);

  // Reset the per-tab "Copied" badges when the user switches platform tabs.
  useIsEffect(() => {
    setCmdCopied(false);
    setPathCopied(false);
  }, [platform]);

  const command = commands ? commands[platform] : null;
  const targetPath = clientTargetPath(client, platform);
  const meta = PLATFORM_META[platform];
  const clientName = CLIENT_META[client].name;

  const copyPath = () => {
    if (!navigator.clipboard || !navigator.clipboard.writeText) return;
    navigator.clipboard.writeText(targetPath).then(() => {
      setPathCopied(true);
      setTimeout(() => setPathCopied(false), 1500);
    }).catch(() => { /* clipboard denied — keep silent */ });
  };

  const copyCommand = () => {
    if (!command || !navigator.clipboard || !navigator.clipboard.writeText) return;
    navigator.clipboard.writeText(command).then(() => {
      setCmdCopied(true);
      setTimeout(() => setCmdCopied(false), 1800);
    }).catch(() => { /* clipboard denied — keep silent */ });
  };

  if (!open) return null;

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,.4)', zIndex: 250,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      animation: 'fadeIn 160ms ease-out',
    }}>
      <div onClick={(e) => e.stopPropagation()} style={{
        width: 620, maxWidth: 'calc(100vw - 32px)', maxHeight: '88vh',
        background: 'var(--surface)',
        border: '1px solid var(--border)',
        borderRadius: 12,
        boxShadow: 'var(--shadow-2)',
        display: 'flex', flexDirection: 'column',
      }}>
        <div style={{
          padding: '20px 24px 14px',
          borderBottom: '1px solid var(--border-subtle)',
          display: 'flex', alignItems: 'flex-start', gap: 12,
        }}>
          <div style={{ flex: 1 }}>
            <div className="t-h2" style={{ margin: 0 }}>Install ask-parcle into {clientName}</div>
            <div className="t-small text-secondary" style={{ marginTop: 4 }}>
              Pick your OS, then paste the command into a terminal.
            </div>
          </div>
          <button className="btn sm ghost" onClick={onClose}><Icons.X size={14}/></button>
        </div>

        <div style={{ flex: 1, overflowY: 'auto', padding: '20px 24px' }}>
          {phase === 'preparing' && (
            <div style={{
              padding: '10px 14px',
              background: 'var(--bg)', border: '1px solid var(--border-subtle)',
              borderRadius: 8, fontSize: 13, color: 'var(--text-secondary)',
            }}>
              <div style={{ marginBottom: 8 }}>Preparing install command…</div>
              <Progress value={60} height={3}/>
            </div>
          )}

          {phase === 'failed' && (
            <div style={{
              padding: '10px 14px',
              background: 'var(--error-bg)', borderRadius: 8,
              fontSize: 13, color: 'var(--error)',
              display: 'flex', gap: 8, alignItems: 'flex-start',
            }}>
              <Icons.AlertTri size={14} style={{ marginTop: 3, flexShrink: 0 }}/>
              <span>{error || 'Failed to prepare install command.'}</span>
            </div>
          )}

          {phase === 'ready' && command && (
            <>
              <div role="tablist" aria-label="Operating system" style={{
                display: 'flex', gap: 4, marginBottom: 12,
                padding: 3,
                background: 'var(--bg)',
                border: '1px solid var(--border-subtle)',
                borderRadius: 8,
                width: 'fit-content',
              }}>
                {PLATFORM_ORDER.map((p) => {
                  const active = p === platform;
                  return (
                    <button
                      key={p}
                      role="tab"
                      aria-selected={active}
                      onClick={() => setPlatform(p)}
                      className="mono-sm"
                      style={{
                        padding: '4px 12px',
                        fontSize: 12,
                        borderRadius: 6,
                        border: 'none',
                        cursor: 'pointer',
                        background: active ? 'var(--surface)' : 'transparent',
                        color: active ? 'var(--text-primary)' : 'var(--text-secondary)',
                        boxShadow: active ? 'var(--shadow-1)' : 'none',
                        fontWeight: active ? 600 : 500,
                      }}>
                      {PLATFORM_META[p].tab}
                    </button>
                  );
                })}
              </div>

              <div style={{ fontSize: 13, color: 'var(--text-secondary)', lineHeight: '20px', marginBottom: 12 }}>
                {meta.instruction}
              </div>

              <div style={{
                background: 'var(--bg)', border: '1px solid var(--border-subtle)',
                borderRadius: 8, overflow: 'hidden',
              }}>
                <div style={{
                  display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                  padding: '8px 12px', borderBottom: '1px solid var(--border-subtle)',
                }}>
                  <span className="mono-sm mono text-tertiary">{meta.shellLabel}</span>
                  <button className="btn sm ghost" onClick={copyCommand}>
                    <Icons.Copy size={12}/> {cmdCopied ? 'Copied' : 'Copy command'}
                  </button>
                </div>
                <pre className="mono" style={{
                  margin: 0, padding: '12px 16px',
                  fontSize: 11, lineHeight: '18px',
                  maxHeight: 180, overflow: 'auto',
                  color: 'var(--text-primary)',
                  whiteSpace: 'pre-wrap', wordBreak: 'break-all',
                }}>{command}</pre>
              </div>

              <div style={{
                marginTop: 16, padding: '10px 14px',
                background: 'var(--bg)', border: '1px solid var(--border-subtle)',
                borderRadius: 8, fontSize: 12, color: 'var(--text-secondary)',
                display: 'flex', flexDirection: 'column', gap: 10,
              }}>
                <div>If the install errors out, make sure {clientName} is installed first, then re-run the command.</div>
                <div>After it runs: restart {clientName} and ask <i>"Do you have the ask-parcle skill?"</i> to confirm the skill loaded.</div>
              </div>
            </>
          )}
        </div>

        <div style={{
          padding: '14px 24px',
          borderTop: '1px solid var(--border-subtle)',
          display: 'flex', justifyContent: 'flex-end', gap: 8,
        }}>
          <button className="btn" onClick={onClose}>Close</button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { InstallSkillModal });
