import { useState, useEffect, useRef, useCallback } from 'react';

type Phase = 'ready' | 'running' | 'done';

type ServerMessage =
  | { type: 'started'; taskName: string }
  | { type: 'stdout'; data: string }
  | { type: 'stderr'; data: string }
  | { type: 'exit'; code: number }
  | { type: 'error'; message: string };

export function useTaskRunner() {
  const [phase, setPhase] = useState<Phase>('ready');
  const [output, setOutput] = useState<Array<{ stream: 'stdout' | 'stderr' | 'system'; text: string }>>([]);
  const [exitCode, setExitCode] = useState<number | null>(null);
  const [isConnected, setIsConnected] = useState(false);
  const wsRef = useRef<WebSocket | null>(null);

  useEffect(() => {
    const token = localStorage.getItem('BEARER_TOKEN');
    if (!token) return;

    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    const url = `${protocol}//${window.location.host}/api/tasks/run/ws?token=${token}`;
    const ws = new WebSocket(url);
    wsRef.current = ws;

    ws.addEventListener('open', () => setIsConnected(true));
    ws.addEventListener('close', () => setIsConnected(false));

    ws.addEventListener('message', (ev) => {
      try {
        const msg = JSON.parse(ev.data) as ServerMessage;

        switch (msg.type) {
          case 'started':
            setOutput((prev) => [...prev, { stream: 'system', text: `Running: ${msg.taskName}\n` }]);
            break;
          case 'stdout':
            setOutput((prev) => [...prev, { stream: 'stdout', text: msg.data }]);
            break;
          case 'stderr':
            setOutput((prev) => [...prev, { stream: 'stderr', text: msg.data }]);
            break;
          case 'exit':
            setExitCode(msg.code);
            setPhase('done');
            break;
          case 'error':
            setOutput((prev) => [...prev, { stream: 'stderr', text: `Error: ${msg.message}\n` }]);
            setPhase('done');
            setExitCode(-1);
            break;
        }
      } catch {
        // ignore
      }
    });

    return () => {
      ws.close();
      wsRef.current = null;
    };
  }, []);

  const run = useCallback((taskDirName: string, inputs: Record<string, string>, cwd?: string) => {
    if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) return;

    setPhase('running');
    setOutput([]);
    setExitCode(null);

    wsRef.current.send(JSON.stringify({ type: 'run', taskDirName, inputs, cwd }));
  }, []);

  const stop = useCallback(() => {
    if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) return;
    wsRef.current.send(JSON.stringify({ type: 'stop' }));
  }, []);

  return { phase, output, exitCode, isConnected, run, stop };
}
