import type { ServerWebSocket } from 'bun';
import { spawn, type Subprocess } from 'bun';

type WSData = {
  userId: number;
  email: string;
  username: string;
  role: string;
};

type AudioSession = {
  proc: Subprocess;
  closed: boolean;
};

const sessions = new Map<ServerWebSocket<WSData>, AudioSession>();

export const cliampAudioWebsocket = {
  async open(ws: ServerWebSocket<WSData>) {
    const parecPath = Bun.which('parec');
    if (!parecPath) {
      ws.close(4000, 'parec not found on host');
      return;
    }

    let proc: Subprocess<'ignore', 'pipe', 'ignore'>;
    try {
      proc = spawn({
        cmd: [parecPath, '--format=s16le', '--rate=44100', '--channels=2', '-d', 'virtual_out.monitor'],
        stdout: 'pipe',
        stderr: 'ignore',
        stdin: 'ignore',
      });
    } catch {
      ws.close(4000, 'Failed to start audio capture');
      return;
    }

    const session: AudioSession = { proc, closed: false };
    sessions.set(ws, session);
    console.log('[cliamp-audio] parec started, streaming to WS');

    // Stream stdout chunks as binary WS frames
    const reader = proc.stdout.getReader();
    let totalBytes = 0;
    const pump = async () => {
      try {
        while (!session.closed) {
          const { done, value } = await reader.read();
          if (done) break;
          if (value && !session.closed) {
            totalBytes += value.byteLength;
            if (totalBytes <= value.byteLength) {
              console.log(`[cliamp-audio] first chunk: ${value.byteLength} bytes`);
            }
            try {
              ws.sendBinary(value);
            } catch {
              break;
            }
          }
        }
      } catch {
        // stream ended or error
      } finally {
        if (!session.closed) {
          session.closed = true;
          try { ws.close(); } catch { /* ignore */ }
        }
      }
    };

    pump();
  },

  message() {
    // No client-to-server messages expected
  },

  close(ws: ServerWebSocket<WSData>) {
    console.log('[cliamp-audio] WS closed');
    const session = sessions.get(ws);
    if (session) {
      session.closed = true;
      try { session.proc.kill(); } catch { /* ignore */ }
      sessions.delete(ws);
    }
  },

  drain() {},
};
