import { Server as HTTPServer } from "http";
import { Server as SocketIOServer, Socket } from "socket.io";

export interface AdminAlert {
  id: string;
  type: "large_bet" | "fraud_flag" | "system_error" | "payment_issue" | "user_complaint" | "game_issue";
  severity: "low" | "medium" | "high" | "critical";
  title: string;
  description: string;
  data: Record<string, unknown>;
  timestamp: number;
  read: boolean;
  actionRequired: boolean;
}

export interface AdminAlertSubscriber {
  adminId: number;
  socket: Socket;
  subscriptions: Set<AdminAlert["type"]>;
}

class AdminAlertManager {
  private io: SocketIOServer;
  private subscribers: Map<number, AdminAlertSubscriber> = new Map();
  private alertHistory: AdminAlert[] = [];
  private maxHistorySize = 1000;

  constructor(httpServer: HTTPServer) {
    this.io = new SocketIOServer(httpServer, {
      cors: {
        origin: process.env.FRONTEND_URL || "*",
        credentials: true,
      },
      transports: ["websocket", "polling"],
    });

    this.setupEventHandlers();
  }

  private setupEventHandlers() {
    this.io.on("connection", (socket: Socket) => {
      console.log(`[AdminAlerts] Admin connected: ${socket.id}`);

      socket.on("admin:subscribe", (data: { adminId: number; alertTypes: string[] }) => {
        const { adminId, alertTypes } = data;

        // Store subscriber
        const subscriber: AdminAlertSubscriber = {
          adminId,
          socket,
          subscriptions: new Set(alertTypes as AdminAlert["type"][]),
        };

        this.subscribers.set(adminId, subscriber);

        // Send recent alerts
        const recentAlerts = this.alertHistory.slice(-50);
        socket.emit("admin:alert:history", recentAlerts);

        console.log(`[AdminAlerts] Admin ${adminId} subscribed to alerts: ${alertTypes.join(", ")}`);
      });

      socket.on("admin:alert:acknowledge", (alertId: string) => {
        const alert = this.alertHistory.find((a) => a.id === alertId);
        if (alert) {
          alert.read = true;
          this.io.emit("admin:alert:acknowledged", alertId);
        }
      });

      socket.on("admin:alert:action", (data: { alertId: string; action: string; details?: Record<string, unknown> }) => {
        console.log(`[AdminAlerts] Action on alert ${data.alertId}: ${data.action}`);
        this.io.emit("admin:alert:action:completed", data);
      });

      socket.on("disconnect", () => {
        // Remove subscriber
        for (const [adminId, subscriber] of this.subscribers.entries()) {
          if (subscriber.socket.id === socket.id) {
            this.subscribers.delete(adminId);
            console.log(`[AdminAlerts] Admin ${adminId} disconnected`);
            break;
          }
        }
      });
    });
  }

  /**
   * Broadcast alert to subscribed admins
   */
  public broadcastAlert(alert: AdminAlert) {
    // Store in history
    this.alertHistory.push(alert);
    if (this.alertHistory.length > this.maxHistorySize) {
      this.alertHistory.shift();
    }

    // Send to subscribed admins
    for (const subscriber of this.subscribers.values()) {
      if (subscriber.subscriptions.has(alert.type)) {
        subscriber.socket.emit("admin:alert:new", alert);
      }
    }

    console.log(`[AdminAlerts] Broadcast alert: ${alert.type} - ${alert.title}`);
  }

  /**
   * Create and broadcast large bet alert
   */
  public alertLargeBet(userId: number, amount: number, currency: string, gameId: string) {
    const alert: AdminAlert = {
      id: `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      type: "large_bet",
      severity: amount > 100 ? "high" : "medium",
      title: `Large Bet: ${amount} ${currency}`,
      description: `User ${userId} placed a ${amount} ${currency} bet on game ${gameId}`,
      data: { userId, amount, currency, gameId },
      timestamp: Date.now(),
      read: false,
      actionRequired: false,
    };

    this.broadcastAlert(alert);
  }

  /**
   * Create and broadcast fraud flag alert
   */
  public alertFraudFlag(userId: number, reason: string, severity: "low" | "medium" | "high" | "critical") {
    const alert: AdminAlert = {
      id: `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      type: "fraud_flag",
      severity,
      title: `Fraud Alert: User ${userId}`,
      description: reason,
      data: { userId, reason },
      timestamp: Date.now(),
      read: false,
      actionRequired: true,
    };

    this.broadcastAlert(alert);
  }

  /**
   * Create and broadcast system error alert
   */
  public alertSystemError(error: string, component: string) {
    const alert: AdminAlert = {
      id: `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      type: "system_error",
      severity: "critical",
      title: `System Error: ${component}`,
      description: error,
      data: { component, error },
      timestamp: Date.now(),
      read: false,
      actionRequired: true,
    };

    this.broadcastAlert(alert);
  }

  /**
   * Create and broadcast payment issue alert
   */
  public alertPaymentIssue(userId: number, amount: number, reason: string) {
    const alert: AdminAlert = {
      id: `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      type: "payment_issue",
      severity: "high",
      title: `Payment Issue: ${amount} for User ${userId}`,
      description: reason,
      data: { userId, amount, reason },
      timestamp: Date.now(),
      read: false,
      actionRequired: true,
    };

    this.broadcastAlert(alert);
  }

  /**
   * Get alert statistics
   */
  public getAlertStats() {
    const stats = {
      total: this.alertHistory.length,
      unread: this.alertHistory.filter((a) => !a.read).length,
      actionRequired: this.alertHistory.filter((a) => a.actionRequired).length,
      byCritical: this.alertHistory.filter((a) => a.severity === "critical").length,
      byType: {} as Record<string, number>,
    };

    for (const alert of this.alertHistory) {
      stats.byType[alert.type] = (stats.byType[alert.type] || 0) + 1;
    }

    return stats;
  }

  /**
   * Get connected admin count
   */
  public getConnectedAdminCount(): number {
    return this.subscribers.size;
  }
}

let adminAlertManager: AdminAlertManager;

export function initializeAdminAlerts(httpServer: HTTPServer): AdminAlertManager {
  if (!adminAlertManager) {
    adminAlertManager = new AdminAlertManager(httpServer);
  }
  return adminAlertManager;
}

export function getAdminAlertManager(): AdminAlertManager {
  if (!adminAlertManager) {
    throw new Error("AdminAlertManager not initialized");
  }
  return adminAlertManager;
}
