import {
  WebSocketGateway,
  WebSocketServer,
  SubscribeMessage,
  OnGatewayConnection,
  OnGatewayDisconnect,
  ConnectedSocket,
  MessageBody,
} from '@nestjs/websockets';
import { Logger } from '@nestjs/common';
import { Server, Socket } from 'socket.io';

/**
 * ContentGen AI — Gerçek Zamanlı WebSocket Gateway
 *
 * Frontend'e render ilerleme bildirimlerini iletir.
 * C# Worker → RenderCallbackController → EventsGateway → Frontend
 *
 * Room yapısı: "project:{projectId}" — her proje kendi room'una abone olur
 */
@WebSocketGateway({
  cors: {
    origin: ['http://localhost:3001', 'http://localhost:3000', process.env.FRONTEND_URL || '*'],
    credentials: true,
  },
  namespace: '/ws',
  transports: ['websocket', 'polling'],
})
export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer()
  server: Server;

  private readonly logger = new Logger(EventsGateway.name);
  private connectedClients = 0;

  handleConnection(client: Socket) {
    this.connectedClients++;
    this.logger.log(`Client bağlandı: ${client.id} (toplam: ${this.connectedClients})`);
  }

  handleDisconnect(client: Socket) {
    this.connectedClients--;
    this.logger.log(`Client ayrıldı: ${client.id} (toplam: ${this.connectedClients})`);
  }

  /**
   * Frontend, proje detay sayfasına girdiğinde bu event'i gönderir.
   * Client ilgili proje room'una katılır.
   */
  @SubscribeMessage('join:project')
  handleJoinProject(
    @ConnectedSocket() client: Socket,
    @MessageBody() data: { projectId: string },
  ) {
    const room = `project:${data.projectId}`;
    client.join(room);
    this.logger.debug(`Client ${client.id} → room: ${room}`);
    return { event: 'joined', data: { room, projectId: data.projectId } };
  }

  /**
   * Frontend, proje sayfasından ayrıldığında bu event'i gönderir.
   */
  @SubscribeMessage('leave:project')
  handleLeaveProject(
    @ConnectedSocket() client: Socket,
    @MessageBody() data: { projectId: string },
  ) {
    const room = `project:${data.projectId}`;
    client.leave(room);
    this.logger.debug(`Client ${client.id} ← room: ${room}`);
    return { event: 'left', data: { room } };
  }

  /**
   * Kullanıcı kendi bildirim room'una katılır.
   * Frontend login sonrası bu event'i göndererek anlık bildirimleri alır.
   */
  @SubscribeMessage('join:user')
  handleJoinUser(
    @ConnectedSocket() client: Socket,
    @MessageBody() data: { userId: string },
  ) {
    const room = `user:${data.userId}`;
    client.join(room);
    this.logger.debug(`Client ${client.id} → user room: ${room}`);
    return { event: 'joined', data: { room, userId: data.userId } };
  }

  /**
   * Kullanıcı bildirim room'undan ayrılır.
   */
  @SubscribeMessage('leave:user')
  handleLeaveUser(
    @ConnectedSocket() client: Socket,
    @MessageBody() data: { userId: string },
  ) {
    const room = `user:${data.userId}`;
    client.leave(room);
    this.logger.debug(`Client ${client.id} ← user room: ${room}`);
    return { event: 'left', data: { room } };
  }

  // ═══════════════════════════════════════════════════════
  // Server → Client Events (RenderCallbackController tarafından tetiklenir)
  // ═══════════════════════════════════════════════════════

  /**
   * Render ilerleme bildirimi gönder.
   * Stage: 'tts' | 'image_generation' | 'music_generation' | 'compositing' | 'encoding'
   */
  emitRenderProgress(
    projectId: string,
    payload: {
      progress: number;
      stage: string;
      stageLabel: string;
      currentScene?: number;
      totalScenes?: number;
      eta?: number; // Tahmini kalan saniye
    },
  ) {
    this.server.to(`project:${projectId}`).emit('render:progress', {
      projectId,
      ...payload,
      timestamp: new Date().toISOString(),
    });
  }

  /**
   * Render tamamlandı bildirimi.
   */
  emitRenderCompleted(
    projectId: string,
    payload: {
      finalVideoUrl: string;
      thumbnailUrl?: string;
      processingTimeMs: number;
      fileSize: number;
    },
  ) {
    this.server.to(`project:${projectId}`).emit('render:completed', {
      projectId,
      ...payload,
      timestamp: new Date().toISOString(),
    });
  }

  /**
   * Render hatası bildirimi.
   */
  emitRenderFailed(
    projectId: string,
    payload: {
      error: string;
      stage: string;
      attemptNumber: number;
      canRetry: boolean;
    },
  ) {
    this.server.to(`project:${projectId}`).emit('render:failed', {
      projectId,
      ...payload,
      timestamp: new Date().toISOString(),
    });
  }

  /**
   * Proje durum değişikliği bildirimi (status change).
   */
  emitProjectStatusChanged(projectId: string, status: string) {
    this.server.to(`project:${projectId}`).emit('project:status', {
      projectId,
      status,
      timestamp: new Date().toISOString(),
    });
  }

  /**
   * Kullanıcıya anlık bildirim gönder.
   * NotificationsService.createNotification() tarafından çağrılır.
   */
  emitNotification(
    userId: string,
    payload: {
      id: string;
      type: string;
      title: string;
      message?: string | null;
      metadata?: unknown;
      isRead: boolean;
      createdAt: string;
    },
  ) {
    this.server.to(`user:${userId}`).emit('notification:new', {
      ...payload,
      timestamp: new Date().toISOString(),
    });
  }

  /** Bağlı client sayısını döndür (health check için) */
  getConnectedClientsCount(): number {
    return this.connectedClients;
  }
}
