import { INestApplicationContext } from "@nestjs/common";
import { IoAdapter } from "@nestjs/platform-socket.io";
import { createAdapter } from "@socket.io/redis-adapter";
import Redis from "ioredis";
import { ServerOptions } from "socket.io";

/**
 * Cross-node fanout via the Socket.IO Redis adapter (ADR-013). No
 * application-level fanout code — `server.to(room).emit(...)` is propagated
 * to every gateway node subscribed to the same Redis pub/sub pair.
 */
export class RedisIoAdapter extends IoAdapter {
  private pubClient?: Redis;
  private subClient?: Redis;

  constructor(app: INestApplicationContext) {
    super(app);
  }

  async connectToRedis(): Promise<void> {
    const url = process.env.REDIS_URL ?? "redis://localhost:6379";
    this.pubClient = new Redis(url);
    this.subClient = this.pubClient.duplicate();
  }

  createIOServer(port: number, options?: ServerOptions): any {
    // Allow polling + websocket. Production Apache often drops Upgrade headers
    // (Engine.IO code 3), so the web client may stay on long-polling. A single
    // gateway process + Redis adapter is fine without sticky sessions for emit
    // fanout; enable both so neither side gets "unknown transport".
    const server = super.createIOServer(port, {
      ...options,
      transports: ["polling", "websocket"],
      cors: { origin: true },
    });
    if (this.pubClient && this.subClient) {
      server.adapter(createAdapter(this.pubClient, this.subClient));
    }
    return server;
  }
}
