using PSO2SERVER.Database;
using PSO2SERVER.Models;
using PSO2SERVER.Zone;
using System.Runtime.InteropServices;
using static PSO2SERVER.Models.CharacterStruct;
using static PSO2SERVER.Protocol.Packets.CharacterSpawnPacket;

namespace PSO2SERVER.Protocol.Packets
{
    public class CharacterSpawnPacket : Packet
    {
        public enum CharacterSpawnType : byte
        {
            /// Spawned character is not related to the receiver.
            Other = 0x27,
            /// Spawned character is related to the receiver.
            Myself = 0x2F,

            Undefined = 0xFF,
        }

        //private readonly Character _character;
        //public byte IsItMe = (byte)CharacterSpawnType.Myself;
        //public uint IsGM = 0;

        /// <summary>
        /// CharacterSpawnPacket Struct
        /// </summary>
        /// Spawned character's player object.
        public ObjectHeader objHeader { get; set; } = new ObjectHeader();
        public PSOLocation objPosition { get; set; } = new PSOLocation();
        public ushort unk1 { get; set; } = 0;
        /// Always `Character`. (?)
        public string objName { get; set; } = "Character";//0x20
        public ushort unk3 { get; set; } = 1;
        public ushort unk4 { get; set; }
        public uint unk5 { get; set; }
        public uint unk6 { get; set; }
        public uint unk7 { get; set; }
        public uint unk8 { get; set; }
        public CharacterSpawnType spawn_type { get; set; }
        public byte unk9 { get; set; }
        public ushort unk10 { get; set; }
        public Character _character { get; set; }
        public uint unk11 { get; set; }
        /// Set to `1` if the player is a GM.
        public uint gm_flag { get; set; }
        public string nickname { get; set; }
        //#[SeekAfter(0x60)]
        public byte[] unk12 { get; set; } = new byte[0x40];

        public CharacterSpawnPacket(Character character, PSOLocation locatiion)
        {
            objHeader = new ObjectHeader((uint)character.Account.AccountId, ObjectType.Player);
            _character = character;
            objPosition = locatiion;
        }

        public CharacterSpawnPacket(Character character, PSOLocation locatiion, bool isme, bool isgm)
        {
            objHeader = new ObjectHeader((uint)character.Account.AccountId, ObjectType.Player);
            _character = character;
            spawn_type = isme ? CharacterSpawnType.Myself : CharacterSpawnType.Other;
            objPosition = locatiion;
            gm_flag = isgm ? (uint)1 : 0;
        }

        #region implemented abstract members of Packet

        public override byte[] Build()
        {
            var pkt = new PacketWriter();
            // Accounts header
            pkt.WriteStruct(objHeader);
            // Spawn position
            pkt.WritePosition(objPosition);
            pkt.Write(unk1);
            pkt.WriteFixedLengthASCII(objName, 0x20);
            pkt.Write(unk3); // 0x44
            pkt.Write(unk4);
            pkt.Write(unk5);
            pkt.Write(unk6);
            pkt.Write(unk7);
            pkt.Write(unk8);
            pkt.Write((byte)spawn_type);
            pkt.Write(unk9);
            pkt.Write(unk10);
            // Character data.
            pkt.Write((uint)_character.AccountID);
            pkt.Write((uint)_character.CharacterID);
            pkt.Write((uint)_character.Unk1);//4
            pkt.Write((uint)_character.VoiceType);//4
            pkt.Write((ushort)_character.Unk2);//2
            pkt.Write(_character.VoicePitch);//2
            pkt.WriteFixedLengthUtf16(_character.Name, 0x10);
            pkt.Write((uint)_character.Unk3); // 0x90
            pkt.WriteStruct(_character.Looks);
            pkt.WriteStruct(_character.Jobs);
            pkt.WriteBytes(0, 148);
            pkt.Write(unk11);
            pkt.Write(gm_flag);
            pkt.WriteFixedLengthUtf16(_character.Account.Nickname, 0x10);
            for (var i = 0; i < 0x60; i++)
                pkt.Write((byte)0);
            pkt.Write(unk12);

            //pkt.Write((ushort)0); // 0x46
            //pkt.Write((uint)602); // 0x48
            //pkt.Write((uint)1); // 0x4C
            //pkt.Write((uint)53); // 0x50
            //pkt.Write((uint)0); // 0x54

            //// Character spawn type.
            //pkt.Write(IsItMe); // 0x58
            //pkt.Write((byte)0x00);
            //pkt.Write((ushort)0x00);

            //////writer.write((ushort)0x022f); // 0x5c
            ////writer.write((byte)0x2f); // 0x5c
            ////writer.write((byte)0x02);
            //////writer.write((ushort)0x0132); // 0x5e
            ////writer.write((byte)0x32);
            ////writer.write((byte)0x01);

            ////JobParam jobParam = _character.Jobs;
            ////jobParam.mainClass = ClassType.Luster;
            ////jobParam.subClass = ClassType.Phantom;
            ////jobParam.entries.Luster.level = 100;

            //// Character data.
            //pkt.Write((uint)_character.AccountID);
            //pkt.Write((uint)_character.CharacterID);
            //pkt.Write((uint)_character.Unk1);//4
            //pkt.Write((uint)_character.VoiceType);//4
            //pkt.Write((ushort)_character.Unk2);//2
            //pkt.Write(_character.VoicePitch);//2
            //pkt.WriteFixedLengthUtf16(_character.Name, 16);
            //pkt.Write((uint)_character.Unk3); // 0x90
            //pkt.WriteStruct(_character.Looks);
            //pkt.WriteStruct(_character.Jobs);
            //pkt.WriteFixedLengthUtf16(_character.Account.Nickname, 16);
            //pkt.WriteBytes(0, 116);

            //pkt.Write((uint)0); // 0x204
            //pkt.Write(IsGM); // gmflag?


            //for (var i = 0; i < 0x60; i++)
            //    pkt.Write((byte)0);

            //for (var i = 0; i < 0x40; i++)
            //    writer.Write((byte)0);

            return pkt.ToArray();
        }

        public override PacketHeader GetHeader()
        {
            return new PacketHeader(0x08, 0x04, PacketFlags.None);
        }

        #endregion
    }
}