using PSO2SERVER.Protocol;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using static PSO2SERVER.Models.CharacterStruct;

namespace PSO2SERVER.Models
{
    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct ShortItemId
    {
        public byte ItemType;
        public byte Id;
        public ushort Subid;
    }

    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct ItemId
    {
        public ushort ItemType;
        public ushort Id;
        public ushort Unk3;
        public ushort Subid;
    }

    [StructLayout(LayoutKind.Explicit)]
    public unsafe struct Items
    {
        [FieldOffset(0)]
        public PSO2ItemWeapon Weapon;
        [FieldOffset(0)]
        public PSO2ItemClothing Clothing;
        [FieldOffset(0)]
        public PSO2ItemConsumable Consumable;
        [FieldOffset(0)]
        public PSO2ItemCamo Camo;
        [FieldOffset(0)]
        public PSO2ItemUnit Unit;
        [FieldOffset(0)]
        public fixed byte Unknown[0x28];
        [FieldOffset(0)]
        public fixed byte Noitem[0x28];
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct PSO2Items
    {
        public ulong uuid;
        public ItemId id;
        public Items data;

        public byte[] ToByteArray()
        {
            using (var pkt = new PacketWriter())
            {
                pkt.Write(uuid);
                pkt.WriteStruct(id);
                pkt.WriteStruct(data);
                return pkt.ToArray();
            }
        }

        // 从字节流转换为结构体
        public static PSO2Items FromByteArray(byte[] byteArray)
        {
            using (var reader = new PacketReader(byteArray))
            {
                PSO2Items items = new PSO2Items
                {
                    uuid = reader.ReadUInt64(),
                    id = reader.ReadStruct<ItemId>(),
                    data = reader.ReadStruct<Items>()
                };
                return items;
            }
        }

        public ulong GetGUID()
        {
            return uuid;
        }

        public void SetGUID(ulong guid)
        {
            uuid = guid;
        }

    }

    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct PSO2ItemWeapon
    {
        /// Item flags.
        public byte flags;
        /// Item element.
        public byte element;
        /// Item force.
        public byte force;
        public byte grind;
        public byte grindPercent;
        public byte unk1;
        public ushort unk2;
        /// Item affix IDs.
        public fixed ushort affixes[8];
        /// Item potential.
        public uint potential;
        public byte extend;
        public byte unk4;
        public ushort unk5;
        public uint unk6;
        public uint unk7;
    }

    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct PSO2ItemClothing
    {
        public ushort flags;
        public fixed byte unk1[0x14];
        public HSVColor Color;
        public fixed byte unk2[0xA];
        public ushort Unk3;
    }

    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct PSO2ItemConsumable
    {
        public ushort flags;
        public fixed byte unk1[0x24];
        public ushort amount;
    }

    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct PSO2ItemCamo
    {
        public byte unk1;
        public byte unk2;
        public byte unk3;
        public fixed byte unk4[0x24];
        public byte unk5;
    }

    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct PSO2ItemUnit
    {
        public byte flags;
        public byte EnhLevel;
        public byte EnhPercent;
        public byte Unk1;

        // 使用 fixed 数组来存储附加信息
        public fixed ushort Affixes[8]; // Item affix IDs (0 to 4095)

        public fixed byte unk4[0x7];
        public uint Potential;

        // 使用 fixed 数组来存储未知字段
        public fixed byte Unk2[4];

        public uint Unk3;
        public ushort Unk4;
        public ushort Unk5;

        // 提供访问固定数组的属性
        public Span<ushort> AffixSpan
        {
            get
            {
                fixed (ushort* p = Affixes)
                {
                    return new Span<ushort>(p, 8);
                }
            }
        }
    }

    public struct Campaign
    {
        /// Campaign ID.
        public uint Id; // 对应 Rust 的 u32

        /// Start timestamp.
        public TimeSpan StartDate; // 对应 Rust 的 Duration

        /// End timestamp.
        public TimeSpan EndDate; // 对应 Rust 的 Duration

        /// Campaign title (固定长度 0x3E).
        public const int TitleLength = 0x3E;
        public byte[] titleBytes;

        public string Title
        {
            get => Encoding.ASCII.GetString(titleBytes).TrimEnd('\0');
            set
            {
                titleBytes = new byte[TitleLength];
                byte[] valueBytes = Encoding.ASCII.GetBytes(value);
                Array.Copy(valueBytes, titleBytes, Math.Min(valueBytes.Length, TitleLength));
            }
        }

        /// Campaign conditions (固定长度 0x102).
        public const int ConditionsLength = 0x102;
        public byte[] conditionsBytes;

        public string Conditions
        {
            get => Encoding.ASCII.GetString(conditionsBytes).TrimEnd('\0');
            set
            {
                conditionsBytes = new byte[ConditionsLength];
                byte[] valueBytes = Encoding.ASCII.GetBytes(value);
                Array.Copy(valueBytes, conditionsBytes, Math.Min(valueBytes.Length, ConditionsLength));
            }
        }

        // 从数据流中读取 Campaign
        public static Campaign FromStream(Stream stream)
        {
            using (BinaryReader reader = new BinaryReader(stream, Encoding.ASCII, true))
            {
                Campaign campaign = new Campaign
                {
                    Id = reader.ReadUInt32(),
                    StartDate = TimeSpan.FromTicks(reader.ReadInt64()),
                    EndDate = TimeSpan.FromTicks(reader.ReadInt64()),
                };
                campaign.titleBytes = reader.ReadBytes(TitleLength);
                campaign.conditionsBytes = reader.ReadBytes(ConditionsLength);
                return campaign;
            }
        }

        // 将 Campaign 写入数据流
        public void WriteToStream(Stream stream)
        {
            using (BinaryWriter writer = new BinaryWriter(stream, Encoding.ASCII, true))
            {
                writer.Write(Id);
                writer.Write(StartDate.Ticks);
                writer.Write(EndDate.Ticks);
                writer.Write(titleBytes);
                writer.Write(conditionsBytes);
            }
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct NamedId
    {
        public string Name { get; set; }
        public ItemId Id { get; set; }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct CampaignItemDefinition
    {
        /// <summary>
        /// Campaign ID.
        /// </summary>
        public uint CampaignId;  // Equivalent to u32

        /// <summary>
        /// Number of items in the following array.
        /// </summary>
        public uint ItemAmount;  // Equivalent to u32

        /// <summary>
        /// Campaign items.
        /// </summary>
        public List<CampaignItem> Items;  // Using List instead of fixed-size array
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct CampaignItem
    {
        /// <summary>
        /// Item ID.
        /// </summary>
        public ItemId Id;  // Assuming ItemId is a type, use it as-is

        /// <summary>
        /// Item amount.
        /// </summary>
        public uint Amount;  // Equivalent to u32

        /// <summary>
        /// Unknown field.
        /// </summary>
        public uint Unk;  // Equivalent to u32
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct StorageInfo
    {
        /// <summary>
        /// Total space in the storage.
        /// </summary>
        public uint TotalSpace;  // Equivalent to u32

        /// <summary>
        /// Used space in the storage.
        /// </summary>
        public uint UsedSpace;  // Equivalent to u32

        /// <summary>
        /// Storage ID.
        /// </summary>
        public byte StorageId;  // Equivalent to u8

        /// <summary>
        /// Storage type (?).
        /// </summary>
        public byte StorageType;  // Equivalent to u8

        /// <summary>
        /// Is the storage locked (?).
        /// </summary>
        public byte IsLocked;  // Equivalent to u8

        /// <summary>
        /// Is the storage enabled (?).
        /// </summary>
        public byte IsEnabled;  // Equivalent to u8
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MaterialStorageItem
    {
        /// <summary>
        /// Item category.
        /// </summary>
        public ushort Id;  // Equivalent to u16

        /// <summary>
        /// Item ID.
        /// </summary>
        public ushort Subid;  // Equivalent to u16

        /// <summary>
        /// Item amount.
        /// </summary>
        public ushort Amount;  // Equivalent to u16

        /// <summary>
        /// Unknown field.
        /// </summary>
        public ushort Unk4;  // Equivalent to u16
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct UUIDAmount
    {
        public ulong Uuid { get; set; }
        public ushort Amount { get; set; }
        public ushort Unk { get; set; }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct EquipedItem
    {
        public PSO2Items Item { get; set; }
        public uint Unk { get; set; }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MoveStorageItemRequest
    {
        public ulong Uuid { get; set; }
        public byte Amount { get; set; }
        public byte Unk { get; set; }
        public ushort StorageId { get; set; }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct NewStorageItem
    {
        public PSO2Items Item { get; set; }
        public uint StorageId { get; set; }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct NewInventoryItem
    {
        public PSO2Items Item { get; set; }
        public ushort Amount { get; set; }
        public ushort IsNew { get; set; }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct UpdatedItem
    {
        public ulong Uuid { get; set; }
        public uint NewAmount { get; set; }
        public uint StorageId { get; set; }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct UpdatedInventoryItem
    {
        public ulong Uuid { get; set; }
        public ushort NewAmount { get; set; }
        public ushort Moved { get; set; }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct UpdatedStorageItem
    {
        public ulong Uuid { get; set; }
        public ushort NewAmount { get; set; }
        public ushort Moved { get; set; }
        public uint StorageId { get; set; }
    }

    public static class AffixUtils
    {
        public static ushort[] ReadPackedAffixes(Stream reader)
        {
            byte[] packed = new byte[12];
            reader.Read(packed, 0, packed.Length);

            ushort[] affixes = new ushort[8];
            for (int i = 0; i < 4; i++)
            {
                affixes[i * 2] = BitConverter.ToUInt16(new byte[] { packed[i * 3], (byte)((packed[i * 3 + 2] & 0xF0) >> 4) }, 0);
                affixes[i * 2 + 1] = BitConverter.ToUInt16(new byte[] { packed[i * 3 + 1], (byte)(packed[i * 3 + 2] & 0xF) }, 0);
            }
            return affixes;
        }

        public static void WritePackedAffixes(ushort[] affixes, Stream writer)
        {
            byte[] packed = new byte[12];
            for (int i = 0; i < 4; i++)
            {
                byte[] affix1 = BitConverter.GetBytes(affixes[i * 2]);
                byte[] affix2 = BitConverter.GetBytes(affixes[i * 2 + 1]);

                packed[i * 3] = affix1[0];
                packed[i * 3 + 1] = affix2[0];
                packed[i * 3 + 2] = (byte)((affix1[1] << 4) | (affix2[1] & 0xF));
            }
            writer.Write(packed, 0, packed.Length);
        }
    }
}