'use client';

/**
 * Background-watch management — a compact list of long-task watches with
 * cancel/delete. Reads GET /api/watches; cancel/delete via the [id] route.
 * Lives in the /chat sidebar so users can see and rein in background
 * pollers (avoid runaway / resource hogging). Pure backend otherwise —
 * the watch runner lives in chat-standalone.
 */

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

interface Watch {
  id: string;
  label: string;
  state: 'active' | 'done' | 'failed' | 'timed_out' | 'cancelled' | 'errored';
  polls: number;
  max_polls: number;
  last_text: string | null;
  updated_at: number;
}

const STATE_COLOR: Record<string, string> = {
  active: 'text-amber-400',
  done: 'text-green-400',
  failed: 'text-red-400',
  timed_out: 'text-red-400',
  errored: 'text-red-400',
  cancelled: 'text-[var(--text-secondary)]',
};

export default function WatchesPanel() {
  const [watches, setWatches] = useState<Watch[]>([]);
  const [open, setOpen] = useState(false);

  const load = useCallback(() => {
    fetch('/api/watches?limit=30')
      .then((r) => r.json())
      .then((j) => setWatches(Array.isArray(j.watches) ? j.watches : []))
      .catch(() => {});
  }, []);

  useEffect(() => {
    load();
    const t = setInterval(load, 10_000);
    return () => clearInterval(t);
  }, [load]);

  const act = async (id: string, method: 'POST' | 'DELETE') => {
    try {
      await fetch(`/api/watches/${id}`, {
        method,
        ...(method === 'POST' ? { headers: { 'content-type': 'application/json' }, body: JSON.stringify({ action: 'cancel' }) } : {}),
      });
    } catch { /* ignore */ }
    load();
  };

  const activeCount = watches.filter((w) => w.state === 'active').length;
  if (watches.length === 0) return null;

  return (
    <div className="px-4 py-2 border-t border-[var(--border)] text-xs text-[var(--text-secondary)]">
      <button
        type="button"
        onClick={() => setOpen((o) => !o)}
        className="flex items-center gap-2 w-full text-left hover:text-[var(--text-primary)] transition-colors"
      >
        <span>Background watches</span>
        {activeCount > 0 && (
          <span className="inline-block h-1.5 w-1.5 rounded-full bg-amber-400 animate-pulse" />
        )}
        <span className="ml-auto text-[10px] opacity-60">{activeCount} active · {open ? '▾' : '▸'}</span>
      </button>
      {open && (
        <div className="mt-1.5 space-y-1.5 max-h-56 overflow-y-auto">
          {watches.map((w) => (
            <div key={w.id} className="rounded border border-[var(--border)] px-2 py-1.5">
              <div className="flex items-center gap-2">
                <span className={`text-[10px] uppercase tracking-wide ${STATE_COLOR[w.state] || ''}`}>{w.state}</span>
                <span className="truncate font-medium text-[var(--text-primary)]" title={w.label}>{w.label}</span>
                <span className="ml-auto text-[10px] opacity-60">{w.polls}/{w.max_polls}</span>
              </div>
              {w.last_text && <div className="text-[10px] opacity-70 truncate mt-0.5" title={w.last_text}>{w.last_text}</div>}
              <div className="flex gap-2 mt-1">
                {w.state === 'active' && (
                  <button type="button" onClick={() => act(w.id, 'POST')} className="text-[10px] text-amber-400 hover:underline">cancel</button>
                )}
                <button type="button" onClick={() => act(w.id, 'DELETE')} className="text-[10px] opacity-60 hover:opacity-100 hover:underline">delete</button>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}
