import { Server, Socket } from "socket.io";
import type { Express } from "express";
import { getDb } from "./db.ts";
import { gameChat, users } from "../drizzle/schema.ts";
import { eq, and } from "drizzle-orm";

export interface ChatMessage {
  id: number;
  gameId: number;
  userId: number;
  username: string;
  message: string;
  isSystemMessage: boolean;
  createdAt: Date;
}

export interface GameChatRoom {
  gameId: number;
  activeUsers: Map<string, { userId: number; username: string; socketId: string }>;
  messages: ChatMessage[];
}

const gameChatRooms = new Map<number, GameChatRoom>();

export function initializeGameChat(io: Server) {
  io.on("connection", (socket: Socket) => {
    const userId = socket.handshake.auth.userId as number;
    const username = socket.handshake.auth.username as string;

    socket.on("join-game-chat", async (gameId: number) => {
      const roomName = `game-${gameId}`;
      socket.join(roomName);

      // Initialize room if not exists
      if (!gameChatRooms.has(gameId)) {
        gameChatRooms.set(gameId, {
          gameId,
          activeUsers: new Map(),
          messages: [],
        });

        // Load recent messages from DB
        const db = await getDb();
        if (db) {
          const recentMessages = await db
            .select()
            .from(gameChat)
            .where(eq(gameChat.userId, userId))
            .limit(50);

          const room = gameChatRooms.get(gameId)!;
          room.messages = recentMessages.map((m) => ({
            id: m.id,
            gameId,
            userId: m.userId,
            username: username,
            message: m.message,
            isSystemMessage: false,
            createdAt: m.createdAt,
          }));
        }
      }

      const room = gameChatRooms.get(gameId)!;
      room.activeUsers.set(socket.id, { userId, username, socketId: socket.id });

      // Send recent messages to joining user
      socket.emit("chat-history", room.messages);

      // Notify others
      io.to(roomName).emit("user-joined", {
        username,
        activeCount: room.activeUsers.size,
      });
    });

    socket.on("send-message", async (gameId: number, message: string) => {
      if (!message.trim() || message.length > 500) return;

      const roomName = `game-${gameId}`;
      const room = gameChatRooms.get(gameId);

      if (!room) return;

      const chatMessage: ChatMessage = {
        id: Date.now(),
        gameId,
        userId,
        username,
        message: message.trim(),
        isSystemMessage: false,
        createdAt: new Date(),
      };

      // Save to DB
      const db = await getDb();
      if (db) {
        try {
          await db.insert(gameChat).values({
            userId,
            message: message.trim(),
          });
        } catch (error) {
          console.error("Failed to save chat message:", error);
        }
      }

      // Add to room and broadcast
      room.messages.push(chatMessage);
      if (room.messages.length > 100) room.messages.shift();

      io.to(roomName).emit("new-message", chatMessage);
    });

    socket.on("leave-game-chat", (gameId: number) => {
      const roomName = `game-${gameId}`;
      const room = gameChatRooms.get(gameId);

      if (room) {
        room.activeUsers.delete(socket.id);
        io.to(roomName).emit("user-left", {
          username,
          activeCount: room.activeUsers.size,
        });

        // Clean up empty rooms
        if (room.activeUsers.size === 0) {
          gameChatRooms.delete(gameId);
        }
      }

      socket.leave(roomName);
    });

    socket.on("disconnect", () => {
      // Clean up from all rooms
      const roomsToDelete: number[] = [];
      gameChatRooms.forEach((room, gameId) => {
        if (room.activeUsers.has(socket.id)) {
          room.activeUsers.delete(socket.id);
          const roomName = `game-${gameId}`;
          io.to(roomName).emit("user-left", {
            username,
            activeCount: room.activeUsers.size,
          });

          if (room.activeUsers.size === 0) {
            roomsToDelete.push(gameId);
          }
        }
      });
      roomsToDelete.forEach((gameId) => gameChatRooms.delete(gameId));
    });
  });
}

export async function saveSystemMessage(message: string) {
  const db = await getDb();
  if (!db) return;

  try {
    await db.insert(gameChat).values({
      userId: 0, // System message
      message,
    });
  } catch (error) {
    console.error("Failed to save system message:", error);
  }
}
