const { Player, Inventory } = require("../../models");
const DatapackLoader = require("../../game/DatapackLoader");
const dungeonManager = require("../../game/DungeonManager");

module.exports = (io, socket) => {
  const userId = socket.user?.id;

  socket.on("dungeon:start", async ({ dungeonId }) => {
    try {
      if (!userId) return;
      const dungeon = DatapackLoader.getDungeon(dungeonId);
      const player = await Player.findByPk(userId);
      const energyCost = dungeon?.meta?.energyCost || 0;

      if (!dungeon)
        return socket.emit("error", { message: "Dungeon not found" });
      if (player.energy < energyCost)
        return socket.emit("error", { message: "Insufficient energy" });

      await player.decrement("energy", { by: energyCost });
      const startData = await dungeonManager.startDungeon(userId, dungeonId);
      socket.emit("dungeon:started", {
        dungeonId: dungeon.id,
        room: startData.config,
        hostiles: startData.hostiles,
        battle: startData.battle,
        roomIndex: startData.roomIndex,
        totalRooms: startData.totalRooms,
        remainingEnergy: player.energy - energyCost,
      });
    } catch (err) {
      console.log(err);
      socket.emit("error", { message: "Deployment failure" });
    }
  });

  socket.on("dungeon:combat_action", async ({ targetInstanceId }) => {
    try {
      if (!userId) return;
      const result = dungeonManager.processCombatAction(
        userId,
        targetInstanceId,
      );
      if (!result) return;

      socket.emit("dungeon:battle_update", {
        battle: result.battle,
        log: result.log,
        status: result.status,
      });

      if (result.status === "defeat") {
        dungeonManager.leaveDungeon(userId);
        socket.emit("dungeon:failed", { message: "Neural link severed." });
      }
    } catch (err) {
      socket.emit("error", { message: "Synchronization error" });
    }
  });

  socket.on("dungeon:next_room", async () => {
    try {
      if (!userId) return;
      const nextRoom = await dungeonManager.moveToNextRoom(userId);
      if (!nextRoom)
        return socket.emit("error", { message: "Navigation error" });

      if (nextRoom.status === "completed") {
        await finalizeDungeon(socket, nextRoom.rewards);
      } else {
        socket.emit("dungeon:room_update", nextRoom);
      }
    } catch (err) {
      socket.emit("error", { message: "Navigation error" });
    }
  });

  socket.on("dungeon:leave", () => {
    if (userId) dungeonManager.leaveDungeon(userId);
  });
};

async function finalizeDungeon(socket, sessionRewards) {
  const userId = socket.user.id;
  try {
    const player = await Player.findByPk(userId);

    if (sessionRewards.credits > 0)
      await player.increment("credits", { by: sessionRewards.credits });
    if (sessionRewards.xp > 0)
      await player.increment("experience", { by: sessionRewards.xp });

    if (sessionRewards.items.length > 0) {
      const consolidated = sessionRewards.items.reduce((acc, curr) => {
        acc[curr.id] = (acc[curr.id] || 0) + curr.count;
        return acc;
      }, {});

      for (const [itemId, totalCount] of Object.entries(consolidated)) {
        const [invItem] = await Inventory.findOrCreate({
          where: { playerId: userId, itemId: itemId },
          defaults: { quantity: 0 },
        });
        await invItem.increment("quantity", { by: totalCount });
      }

      // Оновлюємо масив для фронтенда, щоб не було дублікатів у списку
      sessionRewards.items = Object.entries(consolidated).map(
        ([id, count]) => ({ id, count }),
      );
    }

    console.log("FINAL REWARDS SAVED:", sessionRewards);
    socket.emit("dungeon:completed", { rewards: sessionRewards });
  } catch (err) {
    console.error(err);
    socket.emit("error", { message: "Failed to save rewards" });
  } finally {
    dungeonManager.leaveDungeon(userId);
  }
}
