import net, { type Server } from 'net';
import type { InboundMessage } from '../types';
import { detectInboundFormat } from '../parsers/inboundParser';

/** Extract FIN messages from a TCP buffer (brace blocks or $...$ framed). */
export function extractFinMessages(buffer: string): { messages: string[]; remainder: string } {
  const messages: string[] = [];
  let rest = buffer;

  while (rest.length > 0) {
    const dollarStart = rest.indexOf('$');
    const braceStart = rest.indexOf('{1:');

    if (braceStart >= 0 && (dollarStart < 0 || braceStart < dollarStart)) {
      const end = rest.indexOf('-}', braceStart);
      if (end < 0) break;
      messages.push(rest.slice(braceStart, end + 2));
      rest = rest.slice(end + 2);
      continue;
    }

    if (dollarStart >= 0) {
      const end = rest.indexOf('$', dollarStart + 1);
      if (end < 0) break;
      messages.push(rest.slice(dollarStart + 1, end));
      rest = rest.slice(end + 1);
      continue;
    }

    break;
  }

  return { messages, remainder: rest };
}

export type SwiftFinTcpServerOptions = {
  host: string;
  port: number;
  onMessage: (msg: InboundMessage) => void;
};

export function startSwiftFinTcpServer(options: SwiftFinTcpServerOptions): Server {
  const buffers = new Map<string, string>();

  const server = net.createServer((socket) => {
    const key = `${socket.remoteAddress ?? 'unknown'}:${socket.remotePort ?? 0}`;
    buffers.set(key, '');

    socket.on('data', (chunk) => {
      const prev = buffers.get(key) ?? '';
      const combined = prev + chunk.toString('utf8');
      const { messages, remainder } = extractFinMessages(combined);
      buffers.set(key, remainder);

      for (const payload of messages) {
        if (!payload.trim()) continue;
        options.onMessage({
          source: `tcp:${key}:${Date.now()}`,
          format: detectInboundFormat(payload),
          payload,
          metadata: { remote: key },
        });
      }
    });

    socket.on('close', () => buffers.delete(key));
    socket.on('error', () => buffers.delete(key));
  });

  server.listen(options.port, options.host);
  return server;
}
