const std = @import("std");
const protocol = @import("protocol");
const Session = @import("../Session.zig");
const Packet = @import("../Packet.zig");
const Config = @import("config.zig");
const Data = @import("../data.zig");

const UidGenerator = @import("item.zig").UidGenerator;
const ArrayList = std.ArrayList;
const Allocator = std.mem.Allocator;
const CmdID = protocol.CmdID;

pub var m7th: bool = true;
pub var mg: bool = true;
pub var mac: u32 = 4;

// function to check the list if true
fn isInList(id: u32, list: []const u32) bool {
    for (list) |item| {
        if (item == id) {
            return true;
        }
    }
    return false;
}

pub fn onGetAvatarData(session: *Session, packet: *const Packet, allocator: Allocator) !void {
    const config = try Config.loadGameConfig(allocator, "config.json");
    var generator = UidGenerator().init();
    const req = try packet.getProto(protocol.GetAvatarDataCsReq, allocator);
    var rsp = protocol.GetAvatarDataScRsp.init(allocator);
    rsp.is_get_all = req.is_get_all;
    for (Data.AllAvatars) |id| {
        var avatar = protocol.Avatar.init(allocator);
        avatar.base_avatar_id = id;
        avatar.level = 80;
        avatar.promotion = 6;
        avatar.rank = 6;
        avatar.has_taken_promotion_reward_list = ArrayList(u32).init(allocator);
        for (1..6) |i| {
            try avatar.has_taken_promotion_reward_list.append(@intCast(i));
        }
        var talentLevel: u32 = 0;
        const skill_list: []const u32 = if (isInList(avatar.base_avatar_id, &Data.Rem)) &Data.skills else &Data.skills_old;
        for (skill_list) |elem| {
            talentLevel = switch (elem) {
                1 => 6,
                2...4 => 10,
                301, 302 => if (isInList(avatar.base_avatar_id, &Data.Rem)) 6 else 1,
                else => 1,
            };
            const talent = protocol.AvatarSkillTree{ .point_id = avatar.base_avatar_id * 1000 + elem, .level = talentLevel };
            try avatar.skilltree_list.append(talent);
        }
        try rsp.avatar_list.append(avatar);
    }

    for (config.avatar_config.items) |avatarConf| { // rewrite data of avatar in config
        var avatar = protocol.Avatar.init(allocator);
        avatar.base_avatar_id = switch (avatarConf.id) {
            8001...8008 => 8001,
            1224 => 1001,
            else => avatarConf.id,
        };
        avatar.level = avatarConf.level;
        avatar.promotion = avatarConf.promotion;
        avatar.rank = avatarConf.rank;
        avatar.equipment_unique_id = generator.nextId();
        avatar.equip_relic_list = ArrayList(protocol.EquipRelic).init(allocator);
        for (0..6) |i| {
            try avatar.equip_relic_list.append(.{
                .relic_unique_id = generator.nextId(), // uid
                .type = @intCast(i), // slot
            });
        }
        var talentLevel: u32 = 0;
        const skill_list: []const u32 = if (isInList(avatar.base_avatar_id, &Data.Rem)) &Data.skills else &Data.skills_old;
        for (skill_list) |elem| {
            talentLevel = switch (elem) {
                1 => 6,
                2...4 => 10,
                301, 302 => if (isInList(avatar.base_avatar_id, &Data.Rem)) 6 else 1,
                else => 1,
            };
            const talent = protocol.AvatarSkillTree{ .point_id = avatar.base_avatar_id * 1000 + elem, .level = talentLevel };
            try avatar.skilltree_list.append(talent);
        }
        try rsp.avatar_list.append(avatar);
        const avatarType: protocol.MultiPathAvatarType = @enumFromInt(avatarConf.id);
        if (@intFromEnum(avatarType) > 1) {
            try session.send(CmdID.CmdSetAvatarPathScRsp, protocol.SetAvatarPathScRsp{
                .retcode = 0,
                .avatar_id = avatarType,
            });
        }
    }

    try session.send(CmdID.CmdGetAvatarDataScRsp, rsp);
}

pub fn onGetBasicInfo(session: *Session, _: *const Packet, allocator: Allocator) !void {
    var rsp = protocol.GetBasicInfoScRsp.init(allocator);
    rsp.Gender = 2;
    rsp.IsGenderSet = true;
    rsp.PlayerSettingInfo = .{};
    try session.send(CmdID.CmdGetBasicInfoScRsp, rsp);
}

pub fn onSetAvatarPath(session: *Session, packet: *const Packet, allocator: Allocator) !void {
    var rsp = protocol.SetAvatarPathScRsp.init(allocator);

    const req = try packet.getProto(protocol.SetAvatarPathCsReq, allocator);
    rsp.avatar_id = req.avatar_id;
    if (rsp.avatar_id == protocol.MultiPathAvatarType.Mar_7thKnightType) {
        m7th = false;
    } else if (rsp.avatar_id == protocol.MultiPathAvatarType.Mar_7thRogueType) {
        m7th = true;
    } else if (rsp.avatar_id == protocol.MultiPathAvatarType.BoyWarriorType) {
        mac = 1;
        mg = false;
    } else if (rsp.avatar_id == protocol.MultiPathAvatarType.BoyKnightType) {
        mac = 2;
        mg = false;
    } else if (rsp.avatar_id == protocol.MultiPathAvatarType.BoyShamanType) {
        mac = 3;
        mg = false;
    } else if (rsp.avatar_id == protocol.MultiPathAvatarType.BoyMemoryType) {
        mac = 4;
        mg = false;
    } else if (rsp.avatar_id == protocol.MultiPathAvatarType.GirlWarriorType) {
        mac = 1;
        mg = true;
    } else if (rsp.avatar_id == protocol.MultiPathAvatarType.GirlKnightType) {
        mac = 2;
        mg = true;
    } else if (rsp.avatar_id == protocol.MultiPathAvatarType.GirlShamanType) {
        mac = 3;
        mg = true;
    } else if (rsp.avatar_id == protocol.MultiPathAvatarType.GirlMemoryType) {
        mac = 4;
        mg = true;
    }

    var sync = protocol.AvatarPathChangedNotify.init(allocator);

    if (req.avatar_id == protocol.MultiPathAvatarType.GirlMemoryType) {
        sync.base_avatar_id = 8008;
    } else if (req.avatar_id == protocol.MultiPathAvatarType.GirlShamanType) {
        sync.base_avatar_id = 8006;
    } else if (req.avatar_id == protocol.MultiPathAvatarType.GirlKnightType) {
        sync.base_avatar_id = 8004;
    } else if (req.avatar_id == protocol.MultiPathAvatarType.GirlWarriorType) {
        sync.base_avatar_id = 8002;
    }
    sync.cur_multi_path_avatar_type = req.avatar_id;

    try session.send(CmdID.CmdAvatarPathChangedNotify, sync);
    try session.send(CmdID.CmdSetAvatarPathScRsp, rsp);
}
pub fn onDressAvatarSkin(session: *Session, _: *const Packet, allocator: Allocator) !void {
    var rsp = protocol.DressAvatarSkinScRsp.init(allocator);
    rsp.retcode = 0;
    try session.send(CmdID.CmdDressAvatarSkinScRsp, rsp);
}
pub fn onTakeOffAvatarSkin(session: *Session, _: *const Packet, allocator: Allocator) !void {
    var rsp = protocol.TakeOffAvatarSkinScRsp.init(allocator);
    rsp.retcode = 0;
    try session.send(CmdID.CmdTakeOffAvatarSkinScRsp, rsp);
}
pub fn onGetBigDataAll(session: *Session, packet: *const Packet, allocator: Allocator) !void {
    const req = try packet.getProto(protocol.GetBigDataAllRecommendCsReq, allocator);
    var rsp = protocol.GetBigDataAllRecommendScRsp.init(allocator);
    rsp.retcode = 0;
    rsp.IANNEEIJAKH = req.IANNEEIJAKH;
    try session.send(CmdID.CmdGetBigDataAllRecommendScRsp, rsp);
}
pub fn onGetBigData(session: *Session, packet: *const Packet, allocator: Allocator) !void {
    const req = try packet.getProto(protocol.GetBigDataRecommendCsReq, allocator);
    var rsp = protocol.GetBigDataRecommendScRsp.init(allocator);
    rsp.retcode = 0;
    rsp.IANNEEIJAKH = req.IANNEEIJAKH;
    rsp.EIGPMIBCIKG = req.EIGPMIBCIKG;
    try session.send(CmdID.CmdGetBigDataRecommendScRsp, rsp);
}
pub fn onGetPreAvatarGrowthInfo(session: *Session, packet: *const Packet, allocator: Allocator) !void {
    const req = try packet.getProto(protocol.GetPreAvatarGrowthInfoCsReq, allocator);
    var rsp = protocol.GetPreAvatarGrowthInfoScRsp.init(allocator);
    rsp.retcode = 0;
    rsp.KJAEOJBJOJD = req.KJAEOJBJOJD;
    try session.send(CmdID.CmdGetPreAvatarGrowthInfoScRsp, rsp);
}
