import {
  WebSocketGateway,
  WebSocketServer,
  SubscribeMessage,
  MessageBody,
  ConnectedSocket,
  OnGatewayConnection,
  OnGatewayDisconnect,
} from '@nestjs/websockets';
import { UseGuards } from '@nestjs/common';
import { Server, Socket } from 'socket.io';
import { JwtService } from '@nestjs/jwt';
import { WsJwtGuard } from '../auth/guards';
import { ClassroomService } from './classroom.service';

@WebSocketGateway({
  namespace: '/api/classroom',
  cors: {
    origin: [
      'http://localhost:5173',
      'http://127.0.0.1:5173',
      'http://localhost:5500',
      'http://127.0.0.1:5500',
      'http://localhost:3000'
    ],
    credentials: true,
  },
})
export class ClassroomGateway implements OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer()
  server: Server;

  constructor(
    private readonly jwtService: JwtService,
    private readonly classroomService: ClassroomService,
  ) {}

  handleConnection(client: Socket) {
    try {
      const token = this.extractTokenFromHandshake(client);

      if (!token) {
        console.log(`Classroom: Client ${client.id} rejected: No token`);
        client.disconnect();
        return;
      }

      const payload = this.jwtService.verify(token, {
        secret: process.env.JWT_SECRET || 'your-super-secret-jwt-key-change-this-in-production',
      });

      client.data.user = payload;
      
      // Send current state to newly connected user
      client.emit('state-update', {
        raisedHands: this.classroomService.getRaisedHands(),
        activeStudent: this.classroomService.getActiveStudent(),
      });
      
    } catch (error) {
      console.log(`Classroom: Client ${client.id} rejected: Invalid token`);
      client.disconnect();
    }
  }

  handleDisconnect(client: Socket) {
    // Optional: automatically lower hand on disconnect? 
    // For now, let's keep it persistent for 10 mins as per requirements.
  }

  private extractTokenFromHandshake(client: Socket): string | null {
    const cookies = client.handshake.headers.cookie;
    if (cookies) {
      const cookieArray = cookies.split(';');
      for (const cookie of cookieArray) {
        const [name, value] = cookie.trim().split('=');
        if (name === 'access_token') {
          return value;
        }
      }
    }
    return client.handshake.auth?.token || (client.handshake.query?.token as string) || null;
  }

  private broadcastState() {
    this.server.emit('state-update', {
      raisedHands: this.classroomService.getRaisedHands(),
      activeStudent: this.classroomService.getActiveStudent(),
    });
  }

  @UseGuards(WsJwtGuard)
  @SubscribeMessage('raise-hand')
  handleRaiseHand(
    @MessageBody() data: { type: 'normal' | 'question' },
    @ConnectedSocket() client: Socket,
  ) {
    const user = client.data.user;
    this.classroomService.raiseHand(user.sub, user.username, data.type, (userId) => {
        // Callback for timeout
        this.classroomService.lowerHand(userId);
        this.broadcastState();
    });
    this.broadcastState();
  }

  @UseGuards(WsJwtGuard)
  @SubscribeMessage('lower-hand')
  handleLowerHand(@ConnectedSocket() client: Socket) {
    const user = client.data.user;
    this.classroomService.lowerHand(user.sub);
    this.broadcastState();
  }

  @UseGuards(WsJwtGuard)
  @SubscribeMessage('lower-all-hands')
  handleLowerAllHands(@ConnectedSocket() client: Socket) {
    const user = client.data.user;
    if (user.role !== 'Lehrer') {
        client.emit('error', { message: 'Nur Lehrer können alle Hände senken.' });
        return; 
    }
    this.classroomService.lowerAllHands();
    this.broadcastState();
  }

  @UseGuards(WsJwtGuard)
  @SubscribeMessage('pick-student')
  handlePickStudent(
    @MessageBody() data: { userId: number },
    @ConnectedSocket() client: Socket,
  ) {
    const user = client.data.user;
    if (user.role !== 'Lehrer') {
      client.emit('error', { message: 'Nur Lehrer können Schüler aufrufen.' });
      return;
    }

    const hands = this.classroomService.getRaisedHands();
    const target = hands.find(h => h.userId === data.userId);
    
    if (target) {
        this.classroomService.setActiveStudent(target.userId, target.username);
        this.broadcastState();
    }
  }

  @UseGuards(WsJwtGuard)
  @SubscribeMessage('pick-random')
  handlePickRandom(@ConnectedSocket() client: Socket) {
    const user = client.data.user;
    if (user.role !== 'Lehrer') {
      client.emit('error', { message: 'Nur Lehrer können Zufallsauswahl nutzen.' });
      return;
    }

    this.classroomService.pickRandomStudent();
    this.broadcastState();
  }
  
  @UseGuards(WsJwtGuard)
  @SubscribeMessage('reset-active')
  handleResetActive(@ConnectedSocket() client: Socket) {
     const user = client.data.user;
     const activeStudent = this.classroomService.getActiveStudent();
     
     // Allow if teacher OR if the requesting user is the active student
     const isActiveStudent = activeStudent && activeStudent.userId === user.sub;
     
     if (user.role !== 'Lehrer' && !isActiveStudent) {
       client.emit('error', { message: 'Nur Lehrer oder der aktive Schüler können die Auswahl zurücksetzen.' });
       return;
     }
     
     this.classroomService.clearActiveStudent();
     this.broadcastState();
  }
}
