import { Server } from "http";
import { Server as SocketIOServer, Socket } from "socket.io";
import { storage } from "./storage.js";

interface SocketData {
  userId?: string;
  isAdmin?: boolean;
}

export function setupWebSocket(httpServer: Server) {
  const io = new SocketIOServer(httpServer, {
    cors: {
      origin: "*",
      methods: ["GET", "POST"],
    },
    path: "/socket.io"
  });

  io.on("connection", async (socket: Socket) => {
    console.log("Socket.IO client connected:", socket.id);

    // Send initial connection message
    socket.emit("connected", {
      message: "AeThex OS WebSocket connected",
      timestamp: new Date().toISOString()
    });

    // Handle authentication
    socket.on("auth", async (data: { userId: string; isAdmin?: boolean }) => {
      const socketData = socket.data as SocketData;
      socketData.userId = data.userId;
      socketData.isAdmin = data.isAdmin || false;
      
      socket.emit("auth_success", {
        userId: data.userId,
        timestamp: new Date().toISOString()
      });

      // Join user-specific room
      socket.join(`user:${data.userId}`);
      
      if (data.isAdmin) {
        socket.join("admins");
      }

      // Send initial data after auth
      await sendInitialData(socket, socketData);
    });

    // Send initial notifications and alerts
    try {
      const [metrics, alerts, achievements] = await Promise.all([
        storage.getMetrics(),
        storage.getAlerts(),
        storage.getAchievements()
      ]);
      
      socket.emit("metrics", metrics);
      socket.emit("alerts", alerts.filter(a => !a.is_resolved).slice(0, 5));
      socket.emit("achievements", achievements.slice(0, 10));
    } catch (error) {
      console.error("Error sending initial data:", error);
    }

    // Listen for alert resolution events
    socket.on("resolveAlert", async (alertId: string) => {
      try {
        await storage.updateAlert(alertId, { is_resolved: true, resolved_at: new Date() });
        const alerts = await storage.getAlerts();
        io.to("admins").emit("alerts", alerts.filter(a => !a.is_resolved));
        io.to("admins").emit("alert_resolved", { alertId, timestamp: new Date().toISOString() });
      } catch (error) {
        console.error("Error resolving alert:", error);
        socket.emit("error", { message: "Failed to resolve alert" });
      }
    });

    // Listen for request to refresh notifications
    socket.on("refreshNotifications", async () => {
      try {
        const metrics = await storage.getMetrics();
        socket.emit("notifications", [
          { id: 1, message: `${metrics.totalProfiles} architects in network`, type: 'info' },
          { id: 2, message: `${metrics.totalProjects} active projects`, type: 'info' },
          { id: 3, message: 'Aegis security active', type: 'success' }
        ]);
      } catch (error) {
        console.error("Error refreshing notifications:", error);
      }
    });

    // Listen for metrics refresh
    socket.on("refreshMetrics", async () => {
      try {
        const metrics = await storage.getMetrics();
        socket.emit("metrics", metrics);
      } catch (error) {
        console.error("Error refreshing metrics:", error);
      }
    });

    // Listen for achievements refresh
    socket.on("refreshAchievements", async () => {
      try {
        const achievements = await storage.getAchievements();
        socket.emit("achievements", achievements);
      } catch (error) {
        console.error("Error refreshing achievements:", error);
      }
    });

    socket.on("disconnect", () => {
      console.log("Socket.IO client disconnected:", socket.id);
    });
  });

  // Start periodic updates
  startPeriodicUpdates(io);

  return io;
}

async function sendInitialData(socket: Socket, socketData: SocketData) {
  try {
    // Send recent alerts if admin
    if (socketData.isAdmin) {
      const alerts = await storage.getAlerts();
      const unresolved = alerts.filter(a => !a.is_resolved).slice(0, 5);
      socket.emit("admin_alerts", unresolved);
    }

    // Send metrics
    const metrics = await storage.getMetrics();
    socket.emit("metrics_update", metrics);

    // Send recent achievements
    const achievements = await storage.getAchievements();
    socket.emit("achievements_update", achievements.slice(0, 10));
  } catch (error) {
    console.error("Error sending initial data:", error);
  }
}

function startPeriodicUpdates(io: SocketIOServer) {
  // Send metrics updates every 30 seconds
  setInterval(async () => {
    try {
      const metrics = await storage.getMetrics();
      io.emit("metrics_update", metrics);
    } catch (error) {
      console.error("Error broadcasting metrics:", error);
    }
  }, 30000);

  // Check for new alerts every 10 seconds
  let lastAlertCheck = new Date();
  setInterval(async () => {
    try {
      const alerts = await storage.getAlerts();
      const newAlerts = alerts.filter(a => 
        !a.is_resolved && 
        a.created_at && !isNaN(new Date(a.created_at).getTime()) && new Date(a.created_at) > lastAlertCheck
      );

      if (newAlerts.length > 0) {
        io.to("admins").emit("new_alerts", {
          alerts: newAlerts,
          count: newAlerts.length,
          timestamp: new Date().toISOString()
        });
      }

      lastAlertCheck = new Date();
    } catch (error) {
      console.error("Error broadcasting alerts:", error);
    }
  }, 10000);
}

// Export helper functions for triggering broadcasts
export const websocket = {
  io: null as SocketIOServer | null,

  setIO(ioInstance: SocketIOServer) {
    this.io = ioInstance;
  },

  // Helper to notify about new achievements
  notifyAchievement(userId: string, achievement: any) {
    if (this.io) {
      this.io.to(`user:${userId}`).emit("achievement_unlocked", {
        data: achievement,
        timestamp: new Date().toISOString()
      });
    }
  },

  // Helper to notify about new alerts
  notifyAlert(alert: any) {
    if (this.io) {
      this.io.to("admins").emit("alert", {
        data: alert,
        timestamp: new Date().toISOString()
      });
    }
  },

  // Helper to notify about system events
  notifySystem(message: string, severity: "info" | "warning" | "error" = "info") {
    if (this.io) {
      this.io.emit("system_notification", {
        message,
        severity,
        timestamp: new Date().toISOString()
      });
    }
  },

  // Broadcast to all clients
  broadcast(event: string, data: any) {
    if (this.io) {
      this.io.emit(event, data);
    }
  }
};
