import { setAgentState, setSpeechBubble, applyAgentStates, setMood } from './agents.js';
import { appendSystemMessage } from './ui.js';
import { sentiment } from './edge-worker-client.js';
import { setLabelState } from './hud-labels.js';

function resolveWsUrl() {
  const explicit = import.meta.env.VITE_WS_URL;
  if (explicit) return explicit;
  const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
  return `${proto}//${window.location.host}/api/ws`;
}

const WS_URL = resolveWsUrl();

let ws = null;
let connectionState = 'disconnected';
let jobCount = 0;
let reconnectTimer = null;
let visitorId = null;
const RECONNECT_DELAY_MS = 5000;

export function initWebSocket(_scene) {
  visitorId = crypto.randomUUID();
  connect();
}

function connect() {
  if (ws) { ws.onclose = null; ws.close(); }
  connectionState = 'connecting';

  try {
    ws = new WebSocket(WS_URL);
  } catch {
    connectionState = 'disconnected';
    scheduleReconnect();
    return;
  }

  ws.onopen = () => {
    connectionState = 'connected';
    clearTimeout(reconnectTimer);
    send({ type: 'visitor_enter', visitorId, visitorName: 'visitor' });
  };

  ws.onmessage = event => {
    try { handleMessage(JSON.parse(event.data)); } catch { /* ignore */ }
  };

  ws.onerror = () => { connectionState = 'disconnected'; };
  ws.onclose = () => { connectionState = 'disconnected'; scheduleReconnect(); };
}

function scheduleReconnect() {
  clearTimeout(reconnectTimer);
  reconnectTimer = setTimeout(connect, RECONNECT_DELAY_MS);
}

function send(payload) {
  if (ws && ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify(payload));
  }
}

function handleMessage(msg) {
  switch (msg.type) {
    case 'ping':
      send({ type: 'pong' });
      break;

    case 'world_state': {
      if (msg.agentStates) applyAgentStates(msg.agentStates);
      if (msg.recentEvents) {
        const last = msg.recentEvents.slice(-3);
        last.forEach(ev => appendSystemMessage(ev.summary || ev.type));
      }
      break;
    }

    case 'timmy_state': {
      break;
    }

    case 'agent_state': {
      if (msg.agentId && msg.state) {
        setAgentState(msg.agentId, msg.state);
        setLabelState(msg.agentId, msg.state);
      }
      break;
    }

    case 'job_started': {
      jobCount++;
      if (msg.agentId) {
        setAgentState(msg.agentId, 'active');
        setLabelState(msg.agentId, 'active');
      }
      appendSystemMessage(`job ${(msg.jobId || '').slice(0, 8)} started`);
      break;
    }

    case 'job_completed': {
      if (jobCount > 0) jobCount--;
      if (msg.agentId) {
        setAgentState(msg.agentId, 'idle');
        setLabelState(msg.agentId, 'idle');
      }
      appendSystemMessage(`job ${(msg.jobId || '').slice(0, 8)} complete`);
      break;
    }

    case 'chat': {
      if (msg.agentId === 'timmy') {
        // Timmy's AI reply: show in speech bubble + event log
        if (msg.text) setSpeechBubble(msg.text);
        appendSystemMessage('Timmy: ' + (msg.text || '').slice(0, 80));
        // Sentiment-driven facial expression on inbound Timmy messages
        if (msg.text) {
          sentiment(msg.text).then(s => {
            setMood(s.label);
            setTimeout(() => setMood(null), 10_000);
          }).catch(() => {});
        }
      } else if (msg.agentId === 'visitor') {
        // Another visitor's message: event log only (don't hijack the speech bubble)
        appendSystemMessage((msg.text || '').slice(0, 80));
      } else {
        // System agent messages (delta payment confirmations, etc.): speech bubble
        if (msg.text) setSpeechBubble(msg.text);
      }
      break;
    }

    case 'agent_count':
    case 'visitor_count':
      break;

    default:
      break;
  }
}

export function sendVisitorMessage(text) {
  send({ type: 'visitor_message', visitorId, text });
}

export function getConnectionState() { return connectionState; }
export function getJobCount() { return jobCount; }
