'use client';

import { useState } from 'react';
import { Loader2 } from 'lucide-react';
import type { Orchestration } from '../../lib/types';
import { MarkdownResponse } from '../../components/MarkdownResponse';

interface OrchestrationRunnerProps {
  orchestration: Orchestration;
  onClose: () => void;
}

interface StepResult {
  model: string;
  content: string;
  durationMs: number;
  done: boolean;
}

async function streamChat(
  model: string,
  messages: { role: string; content: string }[],
  signal?: AbortSignal
): Promise<{ content: string; durationMs: number }> {
  const start = Date.now();
  const res = await fetch('/api/ollama/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ model, messages }),
    signal,
  });

  if (!res.ok || !res.body) throw new Error('Stream failed');

  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  let buffer = '';
  let content = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split('\n');
    buffer = lines.pop() || '';
    for (const line of lines) {
      if (!line.trim()) continue;
      try {
        const chunk = JSON.parse(line) as { message?: { content?: string } };
        if (chunk.message?.content) content += chunk.message.content;
      } catch {
        /* skip */
      }
    }
  }

  return { content, durationMs: Date.now() - start };
}

export function OrchestrationRunner({ orchestration, onClose }: OrchestrationRunnerProps) {
  const [prompt, setPrompt] = useState('');
  const [running, setRunning] = useState(false);
  const [results, setResults] = useState<StepResult[]>([]);
  const [synthesis, setSynthesis] = useState('');

  const runChain = async (userPrompt: string) => {
    setRunning(true);
    setResults([]);
    setSynthesis('');

    let prevOutput = userPrompt;
    const allResults: StepResult[] = [];

    for (const step of orchestration.steps) {
      const systemContent = step.systemPrompt
        ? step.systemPrompt.replace(/\{prev\}/g, prevOutput)
        : undefined;

      const messages: { role: string; content: string }[] = [];
      if (systemContent) messages.push({ role: 'system', content: systemContent });
      messages.push({ role: 'user', content: prevOutput });

      const { content, durationMs } = await streamChat(step.model, messages);
      const stepResult: StepResult = { model: step.model, content, durationMs, done: true };
      allResults.push(stepResult);
      setResults([...allResults]);
      prevOutput = content;
    }

    setRunning(false);
  };

  const runRace = async (userPrompt: string) => {
    setRunning(true);
    setResults([]);
    setSynthesis('');

    const promises = orchestration.steps.map(async step => {
      const { content, durationMs } = await streamChat(step.model, [
        { role: 'user', content: userPrompt },
      ]);
      return { model: step.model, content, durationMs, done: true } as StepResult;
    });

    const settled = await Promise.allSettled(promises);
    const allResults = settled
      .filter((r): r is PromiseFulfilledResult<StepResult> => r.status === 'fulfilled')
      .map(r => r.value);

    setResults(allResults);
    setRunning(false);
  };

  const runVote = async (userPrompt: string) => {
    setRunning(true);
    setResults([]);
    setSynthesis('');

    const promises = orchestration.steps.map(async step => {
      const { content, durationMs } = await streamChat(step.model, [
        { role: 'user', content: userPrompt },
      ]);
      return { model: step.model, content, durationMs, done: true } as StepResult;
    });

    const settled = await Promise.allSettled(promises);
    const allResults = settled
      .filter((r): r is PromiseFulfilledResult<StepResult> => r.status === 'fulfilled')
      .map(r => r.value);

    setResults(allResults);

    if (orchestration.synthesizer && allResults.length > 0) {
      const synthPrompt = `You are a synthesizer. Multiple models responded to the user's question. Analyze their responses, find consensus, and highlight disagreements. Produce a final authoritative answer.

User question: ${userPrompt}

${allResults.map((r, i) => `--- Model ${i + 1} (${r.model}) ---\n${r.content}`).join('\n\n')}

Provide a synthesized consensus response:`;

      const { content } = await streamChat(orchestration.synthesizer, [
        { role: 'user', content: synthPrompt },
      ]);
      setSynthesis(content);
    }

    setRunning(false);
  };

  const handleRun = async () => {
    if (!prompt.trim() || running) return;
    if (orchestration.mode === 'chain') await runChain(prompt);
    else if (orchestration.mode === 'race') await runRace(prompt);
    else if (orchestration.mode === 'vote') await runVote(prompt);
  };

  return (
    <div className="fixed inset-0 z-50 flex flex-col bg-[var(--bg-canvas)]">
      <header className="flex items-center justify-between border-b border-white/10 bg-[var(--bg-elevated)] px-4 py-3">
        <div>
          <h2 className="text-lg font-semibold text-[var(--text-primary)]">{orchestration.name}</h2>
          <p className="text-xs text-[var(--text-tertiary)]">
            {orchestration.mode} · {orchestration.steps.length} models
          </p>
        </div>
        <button
          type="button"
          onClick={onClose}
          className="rounded border border-white/10 px-3 py-1 text-xs text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
        >
          Close
        </button>
      </header>

      <div className="flex-1 overflow-auto p-4">
        {synthesis && (
          <div className="mb-4 rounded-lg border border-[var(--accent-secondary)]/30 bg-[var(--surface-card)] p-4">
            <p className="mb-2 text-xs font-medium text-[var(--accent-secondary)]">
              Synthesized Consensus
            </p>
            <MarkdownResponse content={synthesis} isThinkModel={false} />
          </div>
        )}

        {results.length > 0 && (
          <div
            className={
              orchestration.mode === 'race' || orchestration.mode === 'vote'
                ? 'grid gap-3 md:grid-cols-2'
                : 'space-y-3'
            }
          >
            {results.map((r, idx) => (
              <div
                key={idx}
                className="rounded-lg border border-white/10 bg-[var(--surface-card)] p-3"
              >
                <div className="mb-2 flex items-center justify-between">
                  <span className="text-xs font-medium text-[var(--text-primary)]">
                    {orchestration.mode === 'chain' ? `Step ${idx + 1}` : ''} {r.model}
                  </span>
                  <span className="text-[10px] text-[var(--text-tertiary)]">
                    {(r.durationMs / 1000).toFixed(1)}s
                  </span>
                </div>
                <MarkdownResponse content={r.content} isThinkModel={false} />
              </div>
            ))}
          </div>
        )}

        {results.length === 0 && !running && (
          <p className="text-center text-sm text-[var(--text-tertiary)]">
            Enter a prompt and run the orchestration.
          </p>
        )}

        {running && (
          <div className="flex items-center justify-center gap-2 py-8 text-[var(--accent-primary)]">
            <Loader2 size={18} className="animate-spin" />
            <span className="text-sm">Running {orchestration.mode}...</span>
          </div>
        )}
      </div>

      <div className="border-t border-white/10 bg-[var(--bg-elevated)] p-3">
        <div className="flex gap-2">
          <textarea
            value={prompt}
            onChange={e => setPrompt(e.target.value)}
            onKeyDown={e => {
              if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
                e.preventDefault();
                void handleRun();
              }
            }}
            rows={2}
            disabled={running}
            placeholder="Enter your prompt... (Cmd+Enter to run)"
            className="min-h-[56px] flex-1 resize-y rounded-md border border-white/10 bg-[var(--surface-card)] px-3 py-2 text-sm text-[var(--text-primary)] outline-none placeholder:text-[var(--text-tertiary)]"
          />
          <button
            type="button"
            onClick={() => void handleRun()}
            disabled={running || !prompt.trim()}
            className="self-end rounded bg-[var(--accent-primary)] px-4 py-2 text-sm text-white disabled:opacity-50"
          >
            Run
          </button>
        </div>
      </div>
    </div>
  );
}
