import { Server } from "socket.io";
import db from "./db.js";
import { rollDice } from "./dice.js";

export function setupSocket(io: Server) {
  io.on("connection", (socket) => {
    socket.on("join-campaign", (campaignId: string) => {
      socket.join(`campaign:${campaignId}`);
    });

    socket.on("leave-campaign", (campaignId: string) => {
      socket.leave(`campaign:${campaignId}`);
    });

    socket.on(
      "roll:request",
      (data: {
        campaignId: number;
        characterId?: number;
        characterName?: string;
        characterColor?: string;
        type: string;
        dice: string;
        label: string;
        modifier?: number;
        advantage?: boolean;
        disadvantage?: boolean;
      }) => {
        const result = rollDice(data.dice, {
          advantage: data.advantage,
          disadvantage: data.disadvantage,
        });

        if (result.error) {
          socket.emit("roll:error", { error: result.error });
          return;
        }

        // Detect nat 20
        const isD20Roll = data.dice.match(/d20/i);
        let nat20 = false;
        if (isD20Roll && result.rolls.length > 0) {
          if (data.advantage) {
            // With advantage, nat20 if the chosen (higher) die is 20
            nat20 = Math.max(...result.rolls) === 20;
          } else if (data.disadvantage) {
            // With disadvantage, nat20 if the chosen (lower) die is 20
            nat20 = Math.min(...result.rolls) === 20;
          } else {
            nat20 = result.rolls[0] === 20;
          }
        }

        const row = db
          .prepare(
            `
                INSERT INTO roll_log (campaign_id, character_id, character_name, character_color, type, label, dice_expression, rolls, modifier, total, advantage, disadvantage, nat20)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            `,
          )
          .run(
            data.campaignId,
            data.characterId ?? null,
            data.characterName || "Roll",
            data.characterColor || "",
            data.type || "custom",
            data.label,
            data.dice,
            JSON.stringify(result.rolls),
            result.modifier,
            result.total,
            data.advantage ? 1 : 0,
            data.disadvantage ? 1 : 0,
            nat20 ? 1 : 0,
          );

        const saved = db
          .prepare("SELECT * FROM roll_log WHERE id = ?")
          .get(row.lastInsertRowid) as Record<string, unknown>;

        const broadcast = {
          ...saved,
          rolls: result.rolls,
          advantage: data.advantage || false,
          disadvantage: data.disadvantage || false,
          nat20,
        };

        io.to(`campaign:${data.campaignId}`).emit("roll:result", broadcast);
      },
    );

    interface EffectState {
      active: boolean;
      intensity: number;
    }

    interface AtmosphereUpdateData {
      campaignId: number;
      fog: EffectState;
      fire: EffectState;
      rain: EffectState;
      embers: EffectState;
    }

    socket.on("atmosphere:update", (data: AtmosphereUpdateData) => {
      const { campaignId, ...atmosphere } = data;
      io.to(`campaign:${campaignId}`).emit("atmosphere:update", atmosphere);
    });

    socket.on("disconnect", () => {
      // Rooms are cleaned up automatically by Socket.IO
    });
  });
}

export function broadcastToCampaign(
  io: Server,
  campaignId: number,
  event: string,
  data: unknown,
) {
  io.to(`campaign:${campaignId}`).emit(event, data);
}
