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 { ChatService } from './chat.service';

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

  constructor(
    private readonly jwtService: JwtService,
    private readonly chatService: ChatService,
  ) {}

  // ... (handleConnection stays same)

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

      if (!token) {
        console.log(`Client ${client.id} rejected: No token provided`);
        client.emit('error', { message: 'Unauthorized: No token provided' });
        client.disconnect();
        return;
      }

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

      // User-Daten zum Socket hinzufügen
      client.data.user = payload;

      console.log(`Client connected: ${client.id}, User: ${payload.username}`);
      // Willkommensnachricht an den verbundenen Client senden
      client.emit('message', {
        type: 'system',
        text: `Willkommen im Chat, ${payload.username}!`,
        timestamp: Date.now(),
      });
    } catch (error) {
      console.log(`Client ${client.id} rejected: Invalid token`);
      client.emit('error', { message: 'Unauthorized: Invalid token' });
      client.disconnect();
    }
  }

  private extractTokenFromHandshake(client: Socket): string | null {
    // Token aus Cookie extrahieren
    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;
        }
      }
    }

    // Fallback: Token aus auth object
    const token = client.handshake.auth?.token;
    if (token) {
      return token;
    }

    // Fallback: Token aus query parameter
    const queryToken = client.handshake.query?.token as string;
    if (queryToken) {
      return queryToken;
    }

    return null;
  }

  handleDisconnect(client: Socket) {
    const user = client.data.user;
    if (user) {
      console.log(`Client disconnected: ${client.id} (${user.username})`);
      
      // Notify all rooms the user was in
      for (const room of client.rooms) {
        if (room.startsWith('group-')) {
            const groupId = parseInt(room.replace('group-', ''));
            if (!isNaN(groupId)) {
                this.server.to(room).emit('message', {
                    type: 'system',
                    text: `${user.username} hat den Chat verlassen`,
                    timestamp: Date.now(),
                    groupId,
                });
                // Also emit specific event if needed
                // client.to(room).emit('user-left', { userId: user.sub, groupId });
            }
        }
      }
    } else {
        console.log(`Client disconnected: ${client.id}`);
    }
  }

  @UseGuards(WsJwtGuard)
  @SubscribeMessage('join-group')
  async handleJoinGroup(
    @MessageBody() data: { groupId: number },
    @ConnectedSocket() client: Socket,
  ) {
    const user = client.data.user;
    const groupId = data.groupId;

    try {
      // Prüfen ob User Mitglied der Gruppe ist
      const group = await this.chatService.getGroupById(groupId);
      const isMember = group.members.some((m) => m.userId === user.sub);

      if (!isMember) {
        client.emit('error', { message: 'Sie sind kein Mitglied dieser Gruppe' });
        return;
      }

      // Socket der Gruppe beitreten (für Room-basierte Nachrichten)
      client.join(`group-${groupId}`);
      console.log(`User ${user.username} joined group ${groupId}`);

      // Bestätigung senden
      client.emit('joined-group', { groupId });

      // System-Nachricht an die Gruppe senden
      this.server.to(`group-${groupId}`).emit('message', {
        type: 'system',
        text: `${user.username} ist dem Chat beigetreten`,
        timestamp: Date.now(),
        groupId,
      });
    } catch (error) {
      console.error('Error joining group:', error);
      client.emit('error', { message: 'Fehler beim Beitreten zur Gruppe' });
    }
  }

  @UseGuards(WsJwtGuard)
  @SubscribeMessage('leave-group')
  handleLeaveGroup(
    @MessageBody() data: { groupId: number },
    @ConnectedSocket() client: Socket,
  ) {
    const user = client.data.user;
    const groupId = data.groupId;

    client.leave(`group-${groupId}`);
    console.log(`User ${user.username} left group ${groupId}`);

    // System-Nachricht an die Gruppe senden
    this.server.to(`group-${groupId}`).emit('message', {
      type: 'system',
      text: `${user.username} hat den Chat verlassen`,
      timestamp: Date.now(),
      groupId,
    });

    client.emit('left-group', { groupId });
  }

  @UseGuards(WsJwtGuard)
  @SubscribeMessage('message')
  async handleMessage(
    @MessageBody() data: { message: string; groupId: number },
    @ConnectedSocket() client: Socket,
  ): Promise<void> {
    const user = client.data.user;
    console.log(`Message from ${client.id} (${user?.username}) to group ${data.groupId}:`, data.message);

    try {
      // Nachricht in DB speichern
      const savedMessage = await this.chatService.createMessage(
        data.groupId,
        user.sub,
        data.message,
      );

      // Nachricht an alle Clients in der Gruppe senden
      this.server.to(`group-${data.groupId}`).emit('message', {
        type: 'chat',
        id: savedMessage.id,
        message: savedMessage.content,
        userId: savedMessage.userId,
        username: savedMessage.user.username,
        groupId: data.groupId,
        timestamp: savedMessage.createdAt.getTime(),
      });
    } catch (error) {
      console.error('Error saving message:', error);
      client.emit('error', {
        message: error.message || 'Fehler beim Senden der Nachricht',
      });
    }
  }

  @UseGuards(WsJwtGuard)
  @SubscribeMessage('typing')
  handleTyping(
    @MessageBody() data: { groupId: number; isTyping: boolean },
    @ConnectedSocket() client: Socket,
  ): void {
    const user = client.data.user;

    // Typing-Indikator an andere Clients in der Gruppe senden (nicht an sich selbst)
    client.to(`group-${data.groupId}`).emit('user-typing', {
      userId: user.sub,
      username: user.username,
      groupId: data.groupId,
      isTyping: data.isTyping,
    });
  }
}
