import { useEffect, useRef, useState } from 'react';
import type { Card } from '../../lib/kanbanApi';
import type { RunEvent } from '../../lib/orchestratorApi';
import type { UseOrchestrator } from './useOrchestrator';

/**
 * Inline agentic control for one kanban card.
 *
 * Lets the operator launch a `pi` run against the card, watch its live
 * tool/thought stream, steer it mid-flight, and stop it — all while the rest of
 * the board stays interactive. Settled runs show their outcome, commit, and
 * summary, with the worktree-backed changes recorded back onto the card and the
 * documentation by the agent itself.
 */

interface AgentRunBarProps {
  card: Card;
  orch: UseOrchestrator;
}

const STATUS_META: Record<string, { label: string; color: string }> = {
  queued: { label: 'Queued', color: 'var(--muted)' },
  running: { label: 'Running', color: 'var(--accent)' },
  completed: { label: 'Completed', color: 'var(--green)' },
  failed: { label: 'Failed', color: 'var(--red)' },
  stopped: { label: 'Stopped', color: 'var(--fg-dim)' },
};

export function AgentRunBar({ card, orch }: AgentRunBarProps) {
  const run = orch.runForCard(card.id);
  const isActive = run?.status === 'running';

  const [promptDraft, setPromptDraft] = useState('');
  const [steerDraft, setSteerDraft] = useState('');
  const [showPrompt, setShowPrompt] = useState(false);
  const [busy, setBusy] = useState(false);
  const logRef = useRef<HTMLDivElement>(null);

  // Stream the active run's events while it is running.
  useEffect(() => {
    if (!run || !isActive) return;
    orch.watch(run.id);
    return () => orch.unwatch(run.id);
  }, [run, isActive, orch]);

  // Auto-scroll the log to the latest event.
  const events = run ? orch.eventsForRun(run.id) : [];
  useEffect(() => {
    if (logRef.current) logRef.current.scrollTop = logRef.current.scrollHeight;
  }, [events.length]);

  const start = async () => {
    setBusy(true);
    try {
      await orch.start({ cardId: card.id, prompt: promptDraft.trim() || undefined });
      setPromptDraft('');
      setShowPrompt(false);
    } catch (e) {
      alert(e instanceof Error ? e.message : 'Failed to start run');
    } finally {
      setBusy(false);
    }
  };

  const steer = async () => {
    if (!run || !steerDraft.trim()) return;
    setBusy(true);
    try {
      await orch.message(run.id, steerDraft.trim(), 'steer');
      setSteerDraft('');
    } catch (e) {
      alert(e instanceof Error ? e.message : 'Failed to steer');
    } finally {
      setBusy(false);
    }
  };

  const stop = async () => {
    if (!run) return;
    setBusy(true);
    try {
      await orch.stop(run.id);
    } finally {
      setBusy(false);
    }
  };

  const dismiss = async () => {
    if (!run) return;
    try {
      await orch.remove(run.id);
    } catch (e) {
      alert(e instanceof Error ? e.message : 'Failed to remove run');
    }
  };

  return (
    <div style={wrapStyle}>
      <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '6px' }}>
        <span style={{ fontSize: '0.78rem', fontWeight: 600, color: 'var(--fg)' }}>🤖 Agent</span>
        {run && (
          <StatusPill status={run.status} />
        )}
        {run?.branch && (
          <span style={branchStyle} title={run.worktreePath ?? undefined}>
            ⎇ {run.branch}
          </span>
        )}
        <span style={{ marginLeft: 'auto' }}>
          {!run && !showPrompt && (
            <button type="button" style={primaryBtn} onClick={() => setShowPrompt(true)}>
              ▶ Run agent
            </button>
          )}
          {isActive && (
            <button type="button" style={dangerBtn} onClick={stop} disabled={busy}>
              ■ Stop
            </button>
          )}
          {run && !isActive && (
            <>
              <button type="button" style={ghostBtn} onClick={() => setShowPrompt((s) => !s)}>
                ↻ Re-run
              </button>
              <button type="button" style={ghostBtn} onClick={dismiss} title="Remove this run">
                Dismiss
              </button>
            </>
          )}
        </span>
      </div>

      {/* Start prompt (create or re-run) */}
      {showPrompt && (
        <div style={{ marginBottom: '8px' }}>
          <textarea
            placeholder="Optional extra instructions for this run (e.g. 'focus on the Rust client', 'also update the economy doc')…"
            value={promptDraft}
            onChange={(e) => setPromptDraft(e.target.value)}
            onClick={(e) => e.stopPropagation()}
            style={{ ...inputStyle, width: '100%', minHeight: '56px', resize: 'vertical' }}
            spellCheck={false}
          />
          <div style={{ marginTop: '4px', display: 'flex', gap: '6px' }}>
            <button type="button" style={primaryBtn} onClick={start} disabled={busy}>
              {busy ? 'Starting…' : '▶ Start'}
            </button>
            <button type="button" style={ghostBtn} onClick={() => setShowPrompt(false)}>
              Cancel
            </button>
            <span style={hintStyle}>
              Runs in an isolated git worktree. The agent reads the docs, implements,
              verifies with cargo/pnpm, then updates the card & docs.
            </span>
          </div>
        </div>
      )}

      {/* Steer box while running */}
      {isActive && (
        <div style={{ display: 'flex', gap: '6px', marginBottom: '8px' }}>
          <input
            type="text"
            placeholder="Steer the agent mid-run…"
            value={steerDraft}
            onChange={(e) => setSteerDraft(e.target.value)}
            onKeyDown={(e) => {
              e.stopPropagation();
              if (e.key === 'Enter' && steerDraft.trim()) void steer();
            }}
            onClick={(e) => e.stopPropagation()}
            style={{ ...inputStyle, flex: 1 }}
          />
          <button type="button" style={smallBtn} onClick={steer} disabled={busy || !steerDraft.trim()}>
            Steer
          </button>
        </div>
      )}

      {/* Settled summary */}
      {run && !isActive && (run.summary || run.commitSha) && (
        <div style={summaryStyle}>
          {run.summary && <div style={{ whiteSpace: 'pre-wrap' }}>{run.summary}</div>}
          <div style={{ marginTop: '4px', fontSize: '0.65rem', color: 'var(--muted)', fontFamily: 'var(--font-mono)' }}>
            {run.commitSha && <>commit {run.commitSha}</>}
            {run.finishedAt && <> · finished {new Date(run.finishedAt).toLocaleTimeString()}</>}
          </div>
        </div>
      )}

      {/* Live event log */}
      {run && events.length > 0 && (
        <div ref={logRef} style={logStyle}>
          {events.slice(-200).map((ev, i) => (
            <EventRow key={`${run.id}-${ev.seq ?? i}`} ev={ev} />
          ))}
        </div>
      )}
    </div>
  );
}

function StatusPill({ status }: { status: string }) {
  const meta = STATUS_META[status] ?? STATUS_META.queued;
  const pulse = status === 'running';
  return (
    <span
      style={{
        display: 'inline-flex',
        alignItems: 'center',
        gap: '4px',
        fontSize: '0.65rem',
        padding: '2px 7px',
        borderRadius: 'var(--radius-pill)',
        border: `1px solid ${meta.color}`,
        background: `${meta.color}1a`,
        color: meta.color,
        textTransform: 'capitalize',
      }}
    >
      <span
        style={{
          width: '6px',
          height: '6px',
          borderRadius: '50%',
          background: meta.color,
          boxShadow: pulse ? `0 0 6px ${meta.color}` : 'none',
        }}
      />
      {meta.label}
    </span>
  );
}

function EventRow({ ev }: { ev: RunEvent }) {
  switch (ev.type) {
    case 'tool_start': {
      const tool = String(ev.data.tool ?? 'tool');
      const preview = String(ev.data.preview ?? '');
      return (
        <div style={evStyle('var(--cyan)')}>
          <span style={tagStyle}>▸ {tool}</span>{' '}
          <span style={previewStyle}>{preview}</span>
        </div>
      );
    }
    case 'tool_end': {
      const tool = String(ev.data.tool ?? 'tool');
      const ok = ev.data.ok !== false;
      const preview = String(ev.data.preview ?? '');
      return (
        <div style={evStyle(ok ? 'var(--fg-dim)' : 'var(--red)')}>
          <span style={tagStyle}>{ok ? '✓' : '✗'} {tool}</span>{' '}
          <span style={previewStyle}>{preview}</span>
        </div>
      );
    }
    case 'text':
      return (
        <div style={{ ...evStyle('var(--fg)'), background: 'rgba(255,255,255,0.03)', borderRadius: '4px', padding: '4px 6px' }}>
          <span style={{ whiteSpace: 'pre-wrap' }}>{String(ev.data.text ?? '')}</span>
        </div>
      );
    case 'done':
      return (
        <div style={evStyle('var(--green)')}>
          <span style={tagStyle}>✓ done</span>{' '}
          <span style={previewStyle}>{String(ev.data.summary ?? '')}</span>
        </div>
      );
    case 'error':
      return <div style={evStyle('var(--red)')}>⚠ {String(ev.data.message ?? '')}</div>;
    case 'log': {
      const level = String(ev.data.level ?? 'info');
      const color = level === 'error' ? 'var(--red)' : level === 'warn' ? 'var(--accent)' : 'var(--muted)';
      return <div style={evStyle(color)}>{String(ev.data.text ?? '')}</div>;
    }
    default:
      return null;
  }
}

// --- styles ----------------------------------------------------------------

const wrapStyle: React.CSSProperties = {
  marginTop: 'var(--sp-3)',
  padding: '10px',
  border: '1px solid var(--border)',
  borderRadius: 'var(--radius-md)',
  background: 'var(--surface-raised)',
};

const branchStyle: React.CSSProperties = {
  fontFamily: 'var(--font-mono)',
  fontSize: '0.62rem',
  color: 'var(--muted)',
  background: 'var(--surface)',
  padding: '1px 6px',
  borderRadius: 'var(--radius-sm)',
  border: '1px solid var(--border)',
  maxWidth: '160px',
  overflow: 'hidden',
  textOverflow: 'ellipsis',
  whiteSpace: 'nowrap',
};

const logStyle: React.CSSProperties = {
  maxHeight: '220px',
  overflowY: 'auto',
  fontFamily: 'var(--font-mono)',
  fontSize: '0.7rem',
  lineHeight: 1.45,
  background: 'var(--bg)',
  border: '1px solid var(--border)',
  borderRadius: 'var(--radius-sm)',
  padding: '6px 8px',
};

const summaryStyle: React.CSSProperties = {
  fontSize: '0.75rem',
  color: 'var(--fg-dim)',
  background: 'rgba(34,197,94,0.06)',
  border: '1px solid rgba(34,197,94,0.2)',
  borderRadius: 'var(--radius-sm)',
  padding: '6px 8px',
  marginBottom: '8px',
};

const inputStyle: React.CSSProperties = {
  padding: '4px 8px',
  fontSize: '0.78rem',
  background: 'var(--surface)',
  border: '1px solid var(--border)',
  borderRadius: 'var(--radius-sm)',
  color: 'var(--fg)',
  fontFamily: 'var(--font-mono)',
};

const primaryBtn: React.CSSProperties = {
  padding: '3px 10px',
  fontSize: '0.74rem',
  background: 'var(--accent)',
  border: 'none',
  borderRadius: 'var(--radius-sm)',
  cursor: 'pointer',
  color: 'var(--surface)',
  fontWeight: 500,
};

const dangerBtn: React.CSSProperties = {
  ...primaryBtn,
  background: 'var(--red)',
};

const ghostBtn: React.CSSProperties = {
  padding: '3px 10px',
  fontSize: '0.74rem',
  background: 'var(--surface)',
  border: '1px solid var(--border)',
  borderRadius: 'var(--radius-sm)',
  cursor: 'pointer',
  color: 'var(--fg-dim)',
};

const smallBtn: React.CSSProperties = {
  ...ghostBtn,
  padding: '3px 12px',
};

const hintStyle: React.CSSProperties = {
  fontSize: '0.62rem',
  color: 'var(--muted)',
  fontFamily: 'var(--font-mono)',
  alignSelf: 'center',
  flex: 1,
};

function evStyle(color: string): React.CSSProperties {
  return { color, marginBottom: '3px', wordBreak: 'break-word' };
}

const tagStyle: React.CSSProperties = {
  fontWeight: 600,
  opacity: 0.95,
};

const previewStyle: React.CSSProperties = {
  color: 'var(--fg-dim)',
  opacity: 0.85,
};
