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

export class RedisIoAdapter extends IoAdapter {
  private adapterConstructor: ReturnType<typeof createAdapter> | null = null;
  private pubClient: Redis | null = null;
  private subClient: Redis | null = null;

  constructor(
    app: INestApplicationContext,
    private readonly redisService: RedisService,
  ) {
    super(app);
  }

  async connectToRedis(): Promise<void> {
    const clients = this.redisService.createPubSubClients();
    if (!clients) {
      return;
    }

    this.pubClient = clients.pubClient;
    this.subClient = clients.subClient;
    this.adapterConstructor = createAdapter(this.pubClient as any, this.subClient as any);
  }

  createIOServer(port: number, options?: ServerOptions) {
    const server = super.createIOServer(port, options);
    if (this.adapterConstructor) {
      server.adapter(this.adapterConstructor);
    }
    return server;
  }

  async close(): Promise<void> {
    await this.pubClient?.quit().catch(() => this.pubClient?.disconnect());
    await this.subClient?.quit().catch(() => this.subClient?.disconnect());
    this.pubClient = null;
    this.subClient = null;
  }
}
