import { GroupMember } from '@/entities/group-member.entity';
import { JwtService } from '@nestjs/jwt';
import { Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import {
  WebSocketGateway,
  WebSocketServer,
  OnGatewayConnection,
  OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { Repository } from 'typeorm';

@WebSocketGateway({
  cors: true,
})
export class NotificationGateway
  implements OnGatewayConnection, OnGatewayDisconnect
{
  private readonly logger = new Logger(NotificationGateway.name);

  @WebSocketServer()
  server: Server;

  constructor(
    private readonly jwtService: JwtService,
    @InjectRepository(GroupMember)
    private readonly groupMemberRepo: Repository<GroupMember>,
  ) {}

  async handleConnection(client: Socket) {
    try {
      const token = client.handshake.auth?.token;
      const payload = this.jwtService.verify(token, {
        secret: process.env.JWT_SECRET,
      });
      const userId = payload.sub;

      if (!userId) {
        client.disconnect();
        return;
      }

      client.join(`user_${userId}`);

      const groups = await this.groupMemberRepo.find({
        where: { user: { id: userId } },
        relations: ['group'],
      });

      groups.forEach((g) => {
        if (g.group?.id) {
          client.join(`group_${g.group.id}`);
        }
      });
    } catch (error) {
      const isExpiredToken =
        error instanceof Error && error.name === 'TokenExpiredError';

      client.emit('auth_error', {
        code: isExpiredToken ? 'TOKEN_EXPIRED' : 'INVALID_TOKEN',
      });

      if (!isExpiredToken) {
        this.logger.warn(
          `Rejected notification socket ${client.id}: invalid token`,
        );
      }

      client.disconnect();
    }
  }

  handleDisconnect(client: Socket) {}

  sendToUser(userId: string, payload: any) {
    this.server.to(`user_${userId}`).emit('notification', payload);
  }

  sendToGroup(groupId: string, payload: any) {
    this.server.to(`group_${groupId}`).emit('notification', payload);
  }
}
