using PSO2SERVER.Database;
using PSO2SERVER.Models;
using PSO2SERVER.Zone;
using System.IO;
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";//Ascii 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; }
        /// Character spawn type.
        public CharacterSpawnType SpawnType { get; set; }
        public byte Unk9 { get; set; }
        public ushort Unk10 { get; set; }
        /// Character data.
        public Character Character { get; set; }
        public uint Unk11 { get; set; }
        /// Set to `1` if the player is a GM.
        public uint GmFlag { get; set; }
        /// Player's nickname.
        public string Nickname { get; set; }//0x10
        //#[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);
            ObjPosition = locatiion;
            Character = character;
        }

        public CharacterSpawnPacket(Character character, PSOLocation locatiion, bool isme, bool isgm)
        {
            ObjHeader = new ObjectHeader((uint)character.Account.AccountId, ObjectType.Player);
            ObjPosition = locatiion;
            Character = character;
            SpawnType = isme ? CharacterSpawnType.Myself : CharacterSpawnType.Other;
            GmFlag = 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)SpawnType);
            pkt.Write(Unk9);
            pkt.Write(Unk10);
            // Character data.
            pkt.Write(Character.BuildCharacterByteArray());
            pkt.Write(Unk11);
            pkt.Write(GmFlag);
            pkt.WriteFixedLengthUtf16(Character.Account.Nickname, 0x10);
            pkt.BaseStream.Seek(0x60, SeekOrigin.Current);
            pkt.Write(Unk12);

            return pkt.ToArray();
        }

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

        #endregion
    }
}