using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FiestaBot.Instances.Networking;
using FiestaBot.Manager.Networking;

namespace FiestaBot.Manager.Handlers
{
    internal class ManagerHandlers
    {
        [ManagerPacketHandler(2, 4)]
        public static void Ping(ManagerClient Socket, Packet Packet)
        {
            Packet.Dispose();

            Packet p = new Packet(2, 5);
            Socket.SendPacket(p);
        }

        [ManagerPacketHandler(2, 7)]
        public static void ReceiveXor(ManagerClient Socket, Packet Packet)
        {
            Packet.ReadShort(out short Xor);
            //Console.WriteLine("Received xor: {0}", Xor);

            Socket.Crypto = new FiestaCrypto(Xor);

            Packet.Dispose();

            Packet p = new Packet(3, 15);
            byte[] Unwanted = new byte[18];
            p.WriteBytes(Unwanted);
            p.WriteString(Program.TransferKey, 64);
            Socket.SendPacket(p);
        }

        [ManagerPacketHandler(3, 20)]
        public static void CharacterList(ManagerClient Socket, Packet Packet)
        {
            Socket.InCharSelect = true;
            Packet.ReadUShort(out ushort Unwanted00);
            Packet.ReadByte(out byte totalCharacters);
            if(totalCharacters > 0)
            {
                Console.WriteLine("You have {0} characters available:", totalCharacters);
                for(int i = 0; i < totalCharacters; i++)
                {
                    Packet.ReadInt(out int charID);
                    Packet.ReadString(out string charName, 16);
                    Packet.ReadUShort(out ushort charLevel);
                    Packet.ReadByte(out byte charSlot);
                    Socket.InUseCharSlots.Add(charSlot);
                    Packet.ReadString(out string charMapIndex, 12);
                    Packet.ReadByte(out byte Unk00);
                    Packet.ReadInt(out int Unwanted01);
                    //TODO: the rest of this packet?
                    //character looks
                    Packet.ReadByte(out byte charLookJobGender);
                    Packet.ReadByte(out byte charLookHair);
                    Packet.ReadByte(out byte charLookHairColor);
                    Packet.ReadByte(out byte charLookFace);
                    //character equipment
                    Packet.ReadUShort(out ushort charEqHelmet);
                    Packet.ReadUShort(out ushort charEqWeapon);
                    Packet.ReadUShort(out ushort charEqArmor);
                    Packet.ReadUShort(out ushort charEqShield);
                    Packet.ReadUShort(out ushort charEqPants);
                    Packet.ReadUShort(out ushort charEqBoots);
                    Packet.ReadUShort(out ushort charEqCosmeticBoots);
                    Packet.ReadUShort(out ushort charEqCosmeticPants);
                    Packet.ReadUShort(out ushort charEqCosmeticArmor);
                    for(int x = 0; x < 6; x++) { Packet.ReadByte(out byte Unk01); }
                    Packet.ReadUShort(out ushort charEqCosmeticGlasses);
                    Packet.ReadUShort(out ushort charEqCosmeticHelmet);
                    for (int x = 0; x < 2; x++) { Packet.ReadByte(out byte Unk02); }
                    Packet.ReadUShort(out ushort charEqCosmeticWeapon);
                    Packet.ReadUShort(out ushort charEqCosmeticBack);
                    for (int x = 0; x < 2; x++) { Packet.ReadByte(out byte Unk03); }
                    Packet.ReadUShort(out ushort charEqComseticTail);
                    Packet.ReadUShort(out ushort charEqCosmeticPet);
                    //???
                    for (int x = 0; x < 3; x++) { Packet.ReadByte(out byte Unk04); }
                    //continue normal data
                    for (int x = 0; x < 4; x++) { Packet.ReadByte(out byte Unk05); }
                    Packet.ReadString(out string charMapName, 12); //???
                    Packet.ReadInt(out int charPosX);
                    Packet.ReadInt(out int charPosY);
                    Packet.ReadInt(out int Unk06);
                    Packet.ReadByte(out byte Unk07);
                    Packet.ReadInt(out int Unk08);
                    Packet.ReadByte(out byte Unk09);

                    byte genderID = (byte)((charLookJobGender >> 7) & 0x01);
                    byte classID = (byte)((charLookJobGender >> 2) & 0x1F);
                    Console.WriteLine("ID: {0} | Name: {1} | Level: {2} | Slot: {3} | Map: {4} | Gender: {5} | Class: {6} | Hair: {7} | Color: {8} | Face: {9} | PosX: {10} | PosY: {11}", charID, charName, charLevel, charSlot, charMapIndex, (Gender)genderID, (Class)classID, FindName(FindType.HairInfo, charLookHair), FindName(FindType.HairColorInfo, charLookHairColor), FindName(FindType.FaceInfo, charLookFace), charPosX, charPosY);
                }
                Console.WriteLine("> Pick a character with: pickchar [ID] OR type createchar to start the creation of a new character");
            }
            else { Console.WriteLine("> You currently have no characters available, type createchar to start the creation of a charater"); }
        }

        [ManagerPacketHandler(3, 21)]
        public static void InvalidworldTransfer(ManagerClient Socket, Packet Packet)
        {
            Console.WriteLine("World transfer failed: invalid transferkey specified");
            Packet.Dispose();
            Socket.Disconnect();
        }

        [ManagerPacketHandler(4, 2)]
        public static void ServerError(ManagerClient Socket, Packet Packet)
        {
            Packet.ReadShort(out short Error);
            Packet.Dispose();
            Console.WriteLine("A server error occurred: {0}", (ConnectErrors)Error);
        }

        private static string FindName(FindType Type, byte ID)
        {
            switch((byte)Type)
            {
                case 1: return Program.ResSystem.ItemInfo.Find(x => x.ItemID == ID).ItemName;
                case 2: return Program.ResSystem.MobInfo.Find(x => x.MobID == ID).MobName;
                case 3: return Program.ResSystem.MapInfo.Find(x => x.MapID == ID).MapName;
                case 4: return Program.ResSystem.HairInfo.Find(x => x.HairID == ID).HairName;
                case 5: return Program.ResSystem.HairColorInfo.Find(x => x.HairColorID == ID).HairColorName;
                case 6: return Program.ResSystem.FaceInfo.Find(x => x.FaceID == ID).FaceName;
                default: return "Unknown";
            }
        }

        private static string FindName(FindType Type, ushort ID)
        {
            switch ((byte)Type)
            {
                case 1: return Program.ResSystem.ItemInfo.Find(x => x.ItemID == ID).ItemName;
                case 2: return Program.ResSystem.MobInfo.Find(x => x.MobID == ID).MobName;
                case 3: return Program.ResSystem.MapInfo.Find(x => x.MapID == ID).MapName;
                case 4: return Program.ResSystem.HairInfo.Find(x => x.HairID == ID).HairName;
                case 5: return Program.ResSystem.HairColorInfo.Find(x => x.HairColorID == ID).HairColorName;
                case 6: return Program.ResSystem.FaceInfo.Find(x => x.FaceID == ID).FaceName;
                default: return "Unknown";
            }
        }
    }

    public enum FindType : byte
    {
        ItemInfo = 1,
        MobInfo = 2,
        MapInfo = 3,
        HairInfo = 4,
        HairColorInfo = 5,
        FaceInfo = 6
    }

    public enum ConnectErrors : ushort
    {
        FailedToConnectToWorldServer = 321,
        FailedToConnectToMapServer = 322, // 323 too
        ThereIsNoCharacterInTheSlot = 324,
        MapUnderMaintenance = 325,

        ErrorInCharacterInfo = 1410,
        ErrorInAppearance = 1411,
        ErrorInOptions = 1412,
        ErrorInStatus = 1413,
        ErrorInSkill = 1414,
        ErrorInQuest = 1415,
        ErrorInHouse = 1416,
        ErrorInFriendInfo = 1417,
        ErrorInMasterAndApprentice = 1418,
        ErrorInGuild = 1419,
        ErrorInEmblem = 1420,
        ErrorInMover = 1421,
        ErrorInArena = 1422,
        ErrorInMarineBatter = 1423, // Lol. wut
        RequestedCharacterIDNotMatching = 1424,
        ErrorInItem = 1425,
        ErrorInTreasureChest = 1426,
        ErrorInTitle = 1427,
        ErrorInKingdomQuest = 1428,
        ErrorInPremiumItem = 1429,

        //MapUnderMaintenance = 1430
    }

    public enum Class : byte
    {
        Unknown = 0,
        Fighter = 1,
        CleverFighter = 2,
        Warrior = 3,
        Gladiator = 4,
        Knight = 5,
        Cleric = 6,
        HighCleric = 7,
        Paladin = 8,
        HolyKnight = 9,
        Guardian = 10,
        Archer = 11,
        HawkArcher = 12,
        Scout = 13,
        SharpShooter = 14,
        Ranger = 15,
        Mage = 16,
        WizMage = 17,
        Enchanter = 18,
        Warlock = 19,
        Wizard = 20,
        Trickster = 21,
        Gambit = 22,
        Renegade = 23,
        Spectre = 24,
        Reaper = 25,
        None = 255
    }

    public enum Gender : byte
    {
        Male = 1,
        Female = 0
    }
}