import { useEffect, useState } from 'react';
import { sessionEvents } from './sessionEvents';

export type RawStatus = 'streaming' | 'tool_running' | 'waiting_for_input' | 'idle' | 'error';
export type DerivedStatus =
  | 'streaming'
  | 'tool_running'
  | 'waiting_for_input'
  | 'idle_warm'
  | 'idle_cold'
  | 'error';

// Window during which an idle dot stays green; after this, it fades to gray.
const WARM_WINDOW_MS = 30_000;
const TICK_MS = 5_000;

interface Entry {
  status: RawStatus;
  at: string;
}

// Module-scope shared state so every StatusDot in the app shares one map
// (mirrors useSidebar's singleton pattern). The map is ephemeral — cleared on
// page reload; WS reconnect repopulates as new frames arrive.
const statuses = new Map<string, Entry>();
const subscribers = new Set<() => void>();

function notify(): void {
  for (const s of subscribers) {
    try { s(); } catch { /* swallow */ }
  }
}

// Guard against duplicate listeners during Vite HMR.
const G = globalThis as Record<string, unknown>;
if (!G.__boocode_chat_status_subscribed) {
  G.__boocode_chat_status_subscribed = true;
  sessionEvents.subscribe((ev) => {
    if (ev.type !== 'chat_status') return;
    statuses.set(ev.chat_id, { status: ev.status, at: ev.at });
    notify();
  });
  // Single shared ticker: re-notify so any green dot whose 30s window just
  // expired re-renders as gray. We only notify if there's something warm —
  // avoids waking sleeping components for nothing.
  setInterval(() => {
    const now = Date.now();
    for (const entry of statuses.values()) {
      if (entry.status === 'idle') {
        const age = now - new Date(entry.at).getTime();
        if (age < WARM_WINDOW_MS + TICK_MS) {
          notify();
          return;
        }
      }
    }
  }, TICK_MS);
}

function derive(entry: Entry | undefined): DerivedStatus {
  if (!entry) return 'idle_cold';
  if (entry.status === 'streaming') return 'streaming';
  if (entry.status === 'tool_running') return 'tool_running';
  if (entry.status === 'waiting_for_input') return 'waiting_for_input';
  if (entry.status === 'error') return 'error';
  const age = Date.now() - new Date(entry.at).getTime();
  return age < WARM_WINDOW_MS ? 'idle_warm' : 'idle_cold';
}

export function useChatStatus(chatId: string | null | undefined): DerivedStatus {
  const [, force] = useState({});
  useEffect(() => {
    const sub = () => force({});
    subscribers.add(sub);
    return () => { subscribers.delete(sub); };
  }, []);
  if (!chatId) return 'idle_cold';
  return derive(statuses.get(chatId));
}
