const std = @import("std");
const protocol = @import("protocol");
const Session = @import("../Session.zig");
const Packet = @import("../Packet.zig");
const Config = @import("config.zig");
const Res_config = @import("res_config.zig");
const Data = @import("../data.zig");
const ChallegeStageManager = @import("../manager/battle_mgr.zig").ChallegeStageManager;
const SceneManager = @import("../manager/scene_mgr.zig").SceneManager;
const ChallengeSceneManager = @import("../manager/scene_mgr.zig").ChallengeSceneManager;
const LineupManager = @import("../manager/lineup_mgr.zig").LineupManager;
const NodeCheck = @import("../commands/value.zig");

const ArrayList = std.ArrayList;
const Allocator = std.mem.Allocator;
const CmdID = protocol.CmdID;

pub fn UidGenerator() type {
    return struct {
        current_id: u32,

        const Self = @This();

        pub fn init() Self {
            return Self{ .current_id = 100000 };
        }

        pub fn nextId(self: *Self) u32 {
            self.current_id +%= 1; // Using wrapping addition
            return self.current_id;
        }
    };
}

fn contains(list: *const std.ArrayListAligned(u32, null), value: u32) bool {
    for (list.items) |item| {
        if (item == value) {
            return true;
        }
    }
    return false;
}
pub var challenge_stageID: u32 = 0;
pub var challenge_mode: u32 = 0;

pub var on_challenge: bool = false;

pub const ChallengeBlessing = ArrayList(u32);
pub var challenge_blessing: []const u32 = &.{};

pub fn onGetChallenge(session: *Session, _: *const Packet, allocator: Allocator) !void {
    const challenge_config = try Config.loadChallengeConfig(allocator, "resources/ChallengeMazeConfig.json");
    var rsp = protocol.GetChallengeScRsp.init(allocator);

    rsp.retcode = 0;
    for (challenge_config.challenge_config.items) |ids| {
        var challenge = protocol.Challenge.init(allocator);
        challenge.challenge_id = ids.id;
        challenge.star = 1;
        if (ids.id > 20000 and ids.id < 30000) {
            challenge.score_id = 40000;
            challenge.score_two = 40000;
        }
        try rsp.challenge_list.append(challenge);
    }

    try session.send(CmdID.CmdGetChallengeScRsp, rsp);
}
pub fn onGetChallengeGroupStatistics(session: *Session, packet: *const Packet, allocator: Allocator) !void {
    const req = try packet.getProto(protocol.GetChallengeGroupStatisticsCsReq, allocator);
    var rsp = protocol.GetChallengeGroupStatisticsScRsp.init(allocator);
    rsp.retcode = 0;
    rsp.group_id = req.group_id;

    try session.send(CmdID.CmdGetChallengeGroupStatisticsScRsp, rsp);
}
pub fn onLeaveChallenge(session: *Session, _: *const Packet, allocator: Allocator) !void {
    var lineup_mgr = LineupManager.init(allocator);
    const lineup = try lineup_mgr.createLineup();
    var scene_manager = SceneManager.init(allocator);
    const scene_info = try scene_manager.createScene(20432, 20432001, 2043201, 1213);
    try session.send(CmdID.CmdQuitBattleScNotify, protocol.QuitBattleScNotify{});
    try session.send(CmdID.CmdEnterSceneByServerScNotify, protocol.EnterSceneByServerScNotify{
        .reason = protocol.EnterSceneReason.ENTER_SCENE_REASON_NONE,
        .lineup = lineup,
        .scene = scene_info,
    });
    on_challenge = false;
    challenge_mode = 0;
    try session.send(CmdID.CmdLeaveChallengeScRsp, protocol.LeaveChallengeScRsp{
        .retcode = 0,
    });
}
pub fn onStartChallenge(session: *Session, packet: *const Packet, allocator: Allocator) !void {
    var challenge_blessing_list = ChallengeBlessing{
        .allocator = std.heap.page_allocator,
        .items = &.{},
        .capacity = 0,
    };
    const req = try packet.getProto(protocol.StartChallengeCsReq, allocator);
    var rsp = protocol.StartChallengeScRsp.init(allocator);
    const challenge_config = try Config.loadChallengeConfig(allocator, "resources/ChallengeMazeConfig.json");
    const entrance_config = try Config.loadMapEntranceConfig(allocator, "resources/MapEntrance.json");
    const maze_config = try Config.loadMazePlaneConfig(allocator, "resources/MazePlane.json");

    var avatarList = std.ArrayList(u32).init(allocator);
    var lineup = protocol.LineupInfo.init(allocator);
    lineup.mp = 5;
    lineup.max_mp = 5;
    lineup.extra_lineup_type = if (NodeCheck.challenge_node == 0) protocol.ExtraLineupType.LINEUP_CHALLENGE else protocol.ExtraLineupType.LINEUP_CHALLENGE_2;

    if (NodeCheck.challenge_node == 0) {
        for (req.first_lineup.items, 0..) |avt, idx| {
            var list = protocol.LineupAvatar.init(allocator);
            try avatarList.append(avt);
            list.id = avt;
            list.slot = @intCast(idx);
            list.satiety = 0;
            list.avatar_type = protocol.AvatarType.AVATAR_FORMAL_TYPE;
            list.hp = 10000;
            list.sp_bar = .{ .sp_cur = 10000, .sp_max = 10000 };
            try lineup.avatar_list.append(list);
        }
        try rsp.lineup_list.append(lineup);
    } else {
        for (req.second_lineup.items, 0..) |avt, idx| {
            var list = protocol.LineupAvatar.init(allocator);
            try avatarList.append(avt);
            list.id = avt;
            list.slot = @intCast(idx);
            list.satiety = 0;
            list.avatar_type = protocol.AvatarType.AVATAR_FORMAL_TYPE;
            list.hp = 10000;
            list.sp_bar = .{ .sp_cur = 10000, .sp_max = 10000 };
            try lineup.avatar_list.append(list);
        }
        try rsp.lineup_list.append(lineup);
    }

    var cur_challenge_info = protocol.CurChallenge.init(allocator);
    cur_challenge_info.challenge_id = req.challenge_id;
    cur_challenge_info.score_id = if (req.challenge_id > 20000 and req.challenge_id < 30000) 40000 else 0;
    cur_challenge_info.score_two = 0;
    cur_challenge_info.status = protocol.ChallengeStatus.CHALLENGE_DOING;
    cur_challenge_info.extra_lineup_type = if (NodeCheck.challenge_node == 0) protocol.ExtraLineupType.LINEUP_CHALLENGE else protocol.ExtraLineupType.LINEUP_CHALLENGE_2;
    var planeID: u32 = 0;
    var floorID: u32 = 0;
    var entryID: u32 = 0;
    var worldID: u32 = 0;
    var monsterID: u32 = 0;
    var eventID: u32 = 0;
    var groupID: u32 = 0;
    var maze_groupID: u32 = 0;
    if (NodeCheck.challenge_node == 0) {
        for (challenge_config.challenge_config.items) |challengeConf| {
            if (challengeConf.id == req.challenge_id) {
                std.debug.print("TRACING CONFIG ID {} WITH CHALLENGE ID {}\n", .{ challengeConf.id, req.challenge_id });
                for (entrance_config.map_entrance_config.items) |entrance| {
                    if (entrance.id == challengeConf.map_entrance_id) {
                        for (maze_config.maze_plane_config.items) |maze| {
                            if (contains(&maze.floor_id_list, entrance.floor_id)) {
                                if (req.challenge_id > 20000 and req.challenge_id < 30000) {
                                    var story_buff = protocol.ChallengeStoryBuffList{
                                        .buff_list = ArrayList(u32).init(allocator),
                                    };
                                    try story_buff.buff_list.append(challengeConf.maze_buff_id);
                                    try story_buff.buff_list.append(req.stage_info.?.IEICDGGELNE.?.story_info.buff_one);
                                    try challenge_blessing_list.appendSlice(story_buff.buff_list.items);
                                    cur_challenge_info.stage_info = .{
                                        .IEICDGGELNE = .{
                                            .cur_story_buffs = story_buff,
                                        },
                                    };
                                    challenge_mode = 1;
                                } else if (req.challenge_id > 30000) {
                                    var boss_buff = protocol.ChallengeBossBuffList{
                                        .buff_list = ArrayList(u32).init(allocator),
                                        .challenge_boss_const = 1,
                                    };
                                    try boss_buff.buff_list.append(challengeConf.maze_buff_id);
                                    try boss_buff.buff_list.append(req.stage_info.?.IEICDGGELNE.?.boss_info.buff_one);
                                    try challenge_blessing_list.appendSlice(boss_buff.buff_list.items);
                                    cur_challenge_info.stage_info = .{
                                        .IEICDGGELNE = .{
                                            .cur_boss_buffs = boss_buff,
                                        },
                                    };
                                    challenge_mode = 2;
                                }
                                floorID = entrance.floor_id;
                                worldID = maze.world_id;
                                monsterID = challengeConf.npc_monster_id_list1.items[challengeConf.npc_monster_id_list1.items.len - 1];
                                eventID = challengeConf.event_id_list1.items[challengeConf.event_id_list1.items.len - 1];
                                groupID = challengeConf.maze_group_id1;
                                maze_groupID = challengeConf.maze_group_id1;
                                planeID = maze.challenge_plane_id;
                                entryID = challengeConf.map_entrance_id;
                            }
                        }
                    }
                }
            }
        }
    } else {
        for (challenge_config.challenge_config.items) |challengeConf| {
            if (challengeConf.id == req.challenge_id) {
                std.debug.print("TRACING CONFIG ID {} WITH CHALLENGE ID {}\n", .{ challengeConf.id, req.challenge_id });
                for (entrance_config.map_entrance_config.items) |entrance| {
                    if (entrance.id == challengeConf.map_entrance_id2) {
                        for (maze_config.maze_plane_config.items) |maze| {
                            if (contains(&maze.floor_id_list, entrance.floor_id)) {
                                if (challengeConf.maze_group_id2) |id| {
                                    if (req.challenge_id > 20000 and req.challenge_id < 30000) {
                                        var story_buff = protocol.ChallengeStoryBuffList{
                                            .buff_list = ArrayList(u32).init(allocator),
                                        };
                                        try story_buff.buff_list.append(challengeConf.maze_buff_id);
                                        try story_buff.buff_list.append(req.stage_info.?.IEICDGGELNE.?.story_info.buff_two);
                                        try challenge_blessing_list.appendSlice(story_buff.buff_list.items);
                                        cur_challenge_info.stage_info = .{
                                            .IEICDGGELNE = .{
                                                .cur_story_buffs = story_buff,
                                            },
                                        };
                                        challenge_mode = 1;
                                    } else if (req.challenge_id > 30000) {
                                        var boss_buff = protocol.ChallengeBossBuffList{
                                            .buff_list = ArrayList(u32).init(allocator),
                                            .challenge_boss_const = 1,
                                        };
                                        try boss_buff.buff_list.append(challengeConf.maze_buff_id);
                                        try boss_buff.buff_list.append(req.stage_info.?.IEICDGGELNE.?.boss_info.buff_two);
                                        try challenge_blessing_list.appendSlice(boss_buff.buff_list.items);
                                        cur_challenge_info.stage_info = .{
                                            .IEICDGGELNE = .{
                                                .cur_boss_buffs = boss_buff,
                                            },
                                        };
                                        challenge_mode = 2;
                                    }
                                    floorID = entrance.floor_id;
                                    worldID = maze.world_id;
                                    monsterID = challengeConf.npc_monster_id_list2.items[challengeConf.npc_monster_id_list2.items.len - 1];
                                    eventID = challengeConf.event_id_list2.items[challengeConf.event_id_list2.items.len - 1];
                                    groupID = id;
                                    maze_groupID = id;
                                    planeID = maze.challenge_plane_id;
                                    entryID = challengeConf.map_entrance_id2;
                                } else {
                                    std.debug.print("THIS CHALLENGE ID: {} DOES NOT SUPPORT 2ND NODE. PLEASE DO COMMAND /node TO SWITCH BACK TO FIRST NODE\n", .{req.challenge_id});
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    var scene_PF_manager = ChallengeSceneManager.init(allocator);
    const scene_info = try scene_PF_manager.createScene(
        avatarList,
        planeID,
        floorID,
        entryID,
        worldID,
        monsterID,
        eventID,
        groupID,
        maze_groupID,
    );
    rsp.retcode = 0;
    rsp.scene = scene_info;
    rsp.cur_challenge = cur_challenge_info;

    on_challenge = true;
    challenge_stageID = eventID;
    challenge_blessing = challenge_blessing_list.items[0..challenge_blessing_list.items.len];
    try session.send(CmdID.CmdStartChallengeScRsp, rsp);
    std.debug.print("SEND PLANE ID {} FLOOR ID {} ENTRY ID {} GROUP ID {} MAZE GROUP ID {}\n", .{ planeID, floorID, entryID, groupID, maze_groupID });
}
