import { GeminiLiveProvider } from './gemini-live';
import { OBSControlClient } from './obs-control';
import { OpenVTControlClient } from './openvt-control';
import { CharacterRuntime, StubResponseProvider, type ResponseProvider } from './runtime';
import { StreamplaceChatAdapter } from './streamplace-chat';

function buildProvider(): ResponseProvider {
  if (process.env.GEMINI_API_KEY) {
    return new GeminiLiveProvider();
  }
  return new StubResponseProvider();
}

export async function runLiveLoop() {
  const runtime = new CharacterRuntime(buildProvider());
  const adapter = new StreamplaceChatAdapter();
  const openvt = new OpenVTControlClient();
  const obs = new OBSControlClient();

  console.log(`[live-loop] subscribing ${adapter.createUrl()}`);
  console.log(`[live-loop] provider=${process.env.GEMINI_API_KEY ? 'gemini-live' : 'stub'}`);
  console.log(`[live-loop] collections=${(process.env.STREAMPLACE_CHAT_NSID ?? 'app.bsky.feed.post')}`);

  const ws = adapter.subscribe(async ({ message }) => {
    try {
      await openvt.sendTalkState('start');
      await openvt.sendEmotion('curious');
    } catch (error) {
      console.warn('[live-loop] openvt pre-response control send failed', error);
    }

    const result = await runtime.handleMessage(message);
    console.log(JSON.stringify({ input: message, output: result }, null, 2));

    try {
      await openvt.sendText(result.reply);
      await obs.setText(result.reply);
      await obs.setProgramScene();
      await openvt.sendResponse({
        ...result,
        actions: result.actions.filter((action) => action.type !== 'talk:start'),
      });
    } catch (error) {
      console.warn('[live-loop] openvt control send failed', error);
    }
  });

  ws.onopen = () => {
    console.log('[live-loop] websocket open');
  };

  ws.onerror = (event) => {
    console.error('[live-loop] websocket error', event);
  };

  ws.onclose = (event) => {
    console.log(`[live-loop] websocket close code=${event.code} reason=${event.reason}`);
  };
}
