import {
  WebSocketGateway,
  WebSocketServer,
  OnGatewayConnection,
  OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { JwtService } from '@nestjs/jwt';
import { Injectable } from '@nestjs/common';

@Injectable()
@WebSocketGateway({
  namespace: '/notifications',
  cors: {
    origin: '*',
    credentials: true,
  },
})
export class NotificationGateway
  implements OnGatewayConnection, OnGatewayDisconnect
{
  @WebSocketServer()
  server: Server;

  constructor(private readonly jwtService: JwtService) {}

  async handleConnection(client: Socket) {
    console.log('🔌 [NotificationGateway] New socket connection attempt');
    try {
      const token =
        client.handshake.auth?.token ||
        client.handshake.headers?.token ||
        client.handshake.headers?.authorization?.replace('Bearer ', '');

      console.log(
        '🔑 [NotificationGateway] Token received:',
        token ? token.substring(0, 20) + '...' : 'NONE',
      );

      if (!token) {
        console.log('❌ [NotificationGateway] No token provided');
        client.disconnect();
        return;
      }

      // ← TEMPORARY: skip verify, decode only to get userId and roleIds
      const parts = token.split('.');
      const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString());

      console.log('📦 [NotificationGateway] Payload decoded:', payload);

      // ✅ FIX — this app's JWT payload uses `sub` for the user id, while
      // the rest of the app maps it to `id`. Resolve from id first, then
      // fall back to sub / userId so the socket ALWAYS joins the correct
      // `user:<id>` room regardless of which field the token carries.
      const userId = payload.id ?? payload.sub ?? payload.userId;

      if (!userId) {
        console.log(
          '❌ [NotificationGateway] No userId in token payload — cannot join room',
        );
        client.disconnect();
        return;
      }

      client.data.userId = userId;
      client.data.roleIds = payload.roleIds || [];

      client.join(`user:${userId}`);

      for (const roleId of payload.roleIds || []) {
        client.join(`role:${roleId}`);
      }

      console.log(
        `✅ [NotificationGateway] Connected: user:${userId} | roles: ${(payload.roleIds || []).map((id: number) => `role:${id}`).join(', ')}`,
      );
    } catch (err: any) {
      console.log('❌ [NotificationGateway] Connection failed:', err.message);
      client.disconnect();
    }
  }

  handleDisconnect(client: Socket) {
    console.log(
      `🔌 [NotificationGateway] Client disconnected: user:${client.data.userId}`,
    );
  }

  emitToRoles(roleIds: number[], event: string, payload: any) {
    for (const roleId of roleIds) {
      this.server.to(`role:${roleId}`).emit(event, payload);
    }
  }

  emitToUsers(userIds: number[], event: string, payload: any) {
    for (const userId of userIds) {
      this.server.to(`user:${userId}`).emit(event, payload);
    }
  }
}