import type { FastifyInstance } from 'fastify';
import type { Sql } from '../db.js';
import type { Broker } from '../services/broker.js';
import type { Message } from '../types/api.js';

export function registerWebSocket(
  app: FastifyInstance,
  sql: Sql,
  broker: Broker
): void {
  app.get<{ Params: { id: string } }>(
    '/api/ws/sessions/:id',
    { websocket: true },
    async (socket, req) => {
      const sessionId = req.params.id;

      const session = await sql<{ id: string }[]>`SELECT id FROM sessions WHERE id = ${sessionId}`;
      if (session.length === 0) {
        socket.send(JSON.stringify({ type: 'error', error: 'session not found' }));
        socket.close(1008, 'session not found');
        return;
      }

      // v1.11: snapshot includes compaction fields so MessageBubble can
      // render the SummaryCard for summary=true rows on first connect.
      // v1.13.1-B: reads tool_calls/tool_results via the parts-merged view.
      const messages = await sql<Message[]>`
        SELECT id, session_id, chat_id, role, content, kind, tool_calls, tool_results, status, last_seq,
               tokens_used, ctx_used, ctx_max, started_at, finished_at, created_at, metadata,
               summary, tail_start_id, compacted_at, model
        FROM messages_with_parts
        WHERE session_id = ${sessionId}
        ORDER BY created_at ASC, id ASC
      `;
      socket.send(JSON.stringify({ type: 'snapshot', messages }));

      const unsubscribe = broker.subscribe(sessionId, (frame) => {
        if (socket.readyState !== socket.OPEN) return;
        try {
          socket.send(JSON.stringify(frame));
        } catch (err) {
          app.log.warn({ err, sessionId }, 'ws send failed');
        }
      });

      socket.on('close', () => unsubscribe());
      socket.on('error', () => unsubscribe());
    }
  );

  app.get('/api/ws/user', { websocket: true }, async (socket) => {
    const user = 'default';
    const unsubscribe = broker.subscribeUser(user, (frame) => {
      if (socket.readyState !== socket.OPEN) return;
      try {
        socket.send(JSON.stringify(frame));
      } catch (err) {
        app.log.warn({ err, user }, 'user ws send failed');
      }
    });
    socket.on('close', () => unsubscribe());
    socket.on('error', () => unsubscribe());
  });
}
