using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.IO;
using System.Runtime.InteropServices;
using MySql.Data.EntityFramework;
using PSO2SERVER.Models;
using PSO2SERVER.Protocol;
using static PSO2SERVER.Models.CharacterStruct;

namespace PSO2SERVER.Database
{
    public class Account
    {
        [Key]
        public int AccountId { get; set; }

        public string Username { get; set; }
        public string Password { get; set; }
        public string Nickname { get; set; }
        public string SettingsIni { get; set; }
        public int TextLang { get; set; }
        public int VoiceLang { get; set; }
        public int TextLang2 { get; set; }
        public int LangLang { get; set; }
        public string LanguageCode { get; set; }
    }

    public class AccountNetInterFace
    {
        [Key]
        public int id { get; set; }

        public int AccountId { get; set; }

        public string Username { get; set; }
        public int State { get; set; }
        public string Mac { get; set; }
    }
    public class AccountSystemInfo
    {
        [Key]
        public int id { get; set; }

        public int AccountId { get; set; }

        public string Username { get; set; }
        public string CpuInfo { get; set; }
        public string VideoInfo { get; set; }
        public long Vram { get; set; }
        public long TotalRam { get; set; }
        public int Unk1 { get; set; }
        public int Unk2 { get; set; }
        public string WindowsVersion { get; set; }
        public string WindowSize { get; set; }
        public string AudioDevices { get; set; }
        public string Unk4 { get; set; }
        public string VideoDriver { get; set; }
        public long TotalDiskSpace { get; set; }
        public long FreeDiskSpace { get; set; }
    }

    public class Character
    {
        // Probably more info than this
        [Key, Column(Order = 1)]
        public int CharacterID { get; set; }

        [Key, Column(Order = 2)]
        public int AccountID { get; set; }
        public int Unk1 { get; set; }
        public int VoiceType { get; set; }
        public short Unk2 { get; set; }
        public short VoicePitch { get; set; }

        public string Name { get; set; }

        public LooksParam Looks { get; set; }

        public byte[] LooksBinary
        {
            get
            {
                PacketWriter w = new PacketWriter();
                w.WriteStruct(Looks);
                return w.ToArray();
            }

            set
            {
                Looks = Helper.ByteArrayToStructure<LooksParam>(value);
            }
        }

        public int Unk3 { get; set; }

        public JobParam Jobs { get; set; }

        public byte[] JobsBinary
        {
            get
            {
                PacketWriter w = new PacketWriter();
                w.WriteStruct(Jobs);
                return w.ToArray();
            }

            set
            {
                Jobs = Helper.ByteArrayToStructure<JobParam>(value);
            }
        }

        public byte[] Unk4 { get; set; } = new byte[148];

        public byte[] Fulldata { get; set; }

        public PSO2Items[] EquipedItems { get; set; } = new PSO2Items[10];

        public byte[] EquipedItemsBinary
        {
            get
            {
                PacketWriter w = new PacketWriter();
                foreach (var item in EquipedItems)
                {
                    w.WriteStruct(item);
                }
                return w.ToArray();
            }

            set
            {
                // 每个PSO2Items的大小（包含uuid、ItemId、Items）
                int itemSize = Marshal.SizeOf(typeof(PSO2Items));

                // 计算字节数组中包含多少个PSO2Items对象
                int itemCount = value.Length / itemSize;

                // 创建一个新的数组来存储这些对象
                EquipedItems = new PSO2Items[itemCount];

                // 逐个反序列化
                for (int i = 0; i < itemCount; i++)
                {
                    // 提取对应的字节块
                    byte[] itemBytes = new byte[itemSize];
                    Array.Copy(value, i * itemSize, itemBytes, 0, itemSize);

                    // 使用Helper.ByteArrayToStructure来反序列化每个PSO2Items对象
                    EquipedItems[i] = Helper.ByteArrayToStructure<PSO2Items>(itemBytes);
                }
            }
        }

        public byte[] BuildCharacterByteArray()
        {
            PacketWriter writer = new PacketWriter();

            // 序列化字段：CharacterID, AccountID, Unk1, VoiceType, Unk2, VoicePitch
            writer.Write((uint)CharacterID);
            writer.Write((uint)AccountID);
            writer.Write((uint)Unk1);
            writer.Write((uint)VoiceType);
            writer.Write((ushort)Unk2);
            writer.Write(VoicePitch);

            // 序列化 Name (假设固定长度字符串16个字节，UTF-16 编码)
            writer.WriteFixedLengthUtf16(Name, 0x10);

            // 序列化 Looks
            writer.WriteStruct(Looks);

            // 序列化 Unk3
            writer.Write((uint)Unk3);

            // 序列化 Jobs
            writer.WriteStruct(Jobs);

            // 序列化 Unk4
            writer.WriteBytes(0, 148);

            // 最后返回字节流
            return writer.ToArray();
        }

        public virtual Account Account { get; set; }
    }

    public class NPC
    {
        [Key, Column(Order = 1)]
        public int EntityID { get; set; }
        [Key, Column(Order = 2)]
        public string ZoneName { get; set; }

        public string NPCName { get; set; }

        public float RotX { get; set; }
        public float RotY { get; set; }
        public float RotZ { get; set; }
        public float RotW { get; set; }

        public float PosX { get; set; }
        public float PosY { get; set; }
        public float PosZ { get; set; }
        public int is_active { get; set; }
    }

    public class GameObject
    {
        [Key, Column(Order = 1)]
        public int ObjectID { get; set; }
        [Key, Column(Order = 2)]
        public string ZoneName { get; set; }

        public string ObjectName { get; set; }

        public byte[] ObjectFlags { get; set; }

        public float RotX { get; set; }
        public float RotY { get; set; }
        public float RotZ { get; set; }
        public float RotW { get; set; }

        public float PosX { get; set; }
        public float PosY { get; set; }
        public float PosZ { get; set; }
    }

    public class ServerInfo
    {
        [Key, MaxLength(255)]
        public string Info { get; set; }

        public string Setting { get; set; }
    }

    public class Teleport
    {
        [Key, Column(Order = 1)]
        public string ZoneName { get; set; }

        [Key, Column(Order = 2)]
        public int ObjectID { get; set; }

        public float RotX { get; set; }
        public float RotY { get; set; }
        public float RotZ { get; set; }
        public float RotW { get; set; }

        public float PosX { get; set; }
        public float PosY { get; set; }
        public float PosZ { get; set; }
    }

    [DbConfigurationType(typeof(MySqlEFConfiguration))]
    public class ServerEf : DbContext
    {
        public DbSet<Account> Accounts { get; set; }
        public DbSet<AccountNetInterFace> AccountsNetInterFaces { get; set; }
        public DbSet<AccountSystemInfo> AccountsSystemInfoes { get; set; }
        public DbSet<Character> Characters { get; set; }
        public DbSet<GameObject> GameObjects { get; set; }
        public DbSet<NPC> NPCs { get; set; }
        public DbSet<ServerInfo> ServerInfoes { get; set; }
        public DbSet<Teleport> Teleports { get; set; }

        public ServerEf()
            : base(
                string.Format("server={0};port={1};database={2};username={3};password={4}",
                                         ServerApp.Config.DatabaseAddress,
                                         ServerApp.Config.DatabasePort,
                                         ServerApp.Config.DatabaseName,
                                         ServerApp.Config.DatabaseUsername,
                                         ServerApp.Config.DatabasePassword)
                  )
        {
        }

        public void SetupDB()
        {
            try
            {
                foreach (
                    var f in
                        Directory.EnumerateFiles(Directory.GetCurrentDirectory() + "/Resources/sql/scripts/", "*.sql"))
                {
                    Logger.WriteInternal("[DBC] 执行数据库脚本 {0}", f);
                    Database.ExecuteSqlCommand(File.ReadAllText(f));
                }
                var revision = ServerInfoes.Find("Revision");
                if (revision == null)
                {
                    revision = new ServerInfo { Info = "Revision", Setting = "0" };
                    ServerInfoes.Add(revision);

                    //TODO Possibly move this somewhere else?
                    Database.ExecuteSqlCommand("ALTER TABLE Accounts AUTO_INCREMENT=10000000");
                }
                SaveChanges();

                Logger.WriteInternal("[DBC] 加载数据集修订的数据库 {0}", revision.Setting);
            }
            catch (Exception ex)
            {
                Logger.WriteException("数据库异常", ex);
            }
        }

        public bool TestDatabaseConnection2()
        {
            try
            {
                using (var context = new ServerEf())
                {
                    // 执行一个简单的查询来测试数据库连接
                    context.Database.ExecuteSqlCommand("SELECT 1");

                    Logger.WriteInternal("[DBT] 数据库连接成功。");
                    return true;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteException("数据库连接异常", ex);
                return false;
            }
        }

        public bool TestDatabaseConnection()
        {
            try
            {
                using (var context = new ServerEf())
                {
                    context.Database.Initialize(force: false);

                    Logger.WriteInternal("[DBT] 数据库连接成功。");
                    return true;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteException("数据库连接异常", ex);
                return false;
            }
        }
    }
}