import type { ServerWebSocket } from "bun";
import type { WsData } from "./channel";
import { hasPermission, findUserById } from "./db";
import { config } from "./config";
import { state } from "./state";
import { broadcastChannelList } from "./broadcast";

export const websocketHandlers = {
  open(ws: ServerWebSocket<WsData>) {
    const channel = state.channels.get(ws.data.channelId);
    if (channel) {
      channel.addClient(ws);
      broadcastChannelList();
    }
    // Track connection by user ID
    const userId = ws.data.userId;
    if (userId) {
      if (!state.userConnections.has(userId)) {
        state.userConnections.set(userId, new Set());
      }
      state.userConnections.get(userId)!.add(ws);
    }
  },

  close(ws: ServerWebSocket<WsData>) {
    const channel = state.channels.get(ws.data.channelId);
    if (channel) {
      channel.removeClient(ws);
      broadcastChannelList();
    }
    // Remove from user connections tracking
    const userId = ws.data.userId;
    if (userId && state.userConnections.has(userId)) {
      state.userConnections.get(userId)!.delete(ws);
      if (state.userConnections.get(userId)!.size === 0) {
        state.userConnections.delete(userId);
      }
    }
  },

  message(ws: ServerWebSocket<WsData>, message: string | Buffer) {
    try {
      const data = JSON.parse(String(message));

      // Handle channel switching
      if (data.action === "switch" && data.channelId) {
        const oldChannel = state.channels.get(ws.data.channelId);
        const newChannel = state.channels.get(data.channelId);
        if (!newChannel) {
          ws.send(JSON.stringify({ type: "error", message: "Channel not found" }));
          return;
        }
        if (oldChannel) oldChannel.removeClient(ws);
        ws.data.channelId = data.channelId;
        newChannel.addClient(ws);
        ws.send(JSON.stringify({ type: "switched", channelId: data.channelId }));
        broadcastChannelList();
        return;
      }

      const channel = state.channels.get(ws.data.channelId);
      if (!channel) {
        console.log("[WS] No channel found for:", ws.data.channelId);
        return;
      }

      // Check permission for control actions
      const userId = ws.data.userId;
      if (!userId) {
        console.log("[WS] No userId on connection");
        return;
      }

      const user = findUserById(userId);
      if (!user) {
        console.log("[WS] User not found:", userId);
        return;
      }

      // Guests can never control playback
      if (user.is_guest) {
        console.log("[WS] Guest cannot control playback");
        return;
      }

      // Check default permissions or user-specific permissions
      const canControl = user.is_admin
        || config.defaultPermissions?.includes("control")
        || hasPermission(userId, "channel", ws.data.channelId, "control");
      if (!canControl) {
        console.log("[WS] User lacks control permission:", user.username);
        return;
      }

      console.log("[WS] Control action:", data.action, "from", user.username);
      if (data.action === "pause") channel.pause();
      else if (data.action === "unpause") channel.unpause();
      else if (data.action === "seek" && typeof data.timestamp === "number") channel.seek(data.timestamp);
      else if (data.action === "jump" && typeof data.index === "number") channel.jumpTo(data.index);
    } catch {}
  },
};
