using Godot;
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace AvatarDoll
{
    /// <summary>
    /// Avatar作者的元信息
    /// </summary>
    [Serializable]
    public struct Metadata
    {
        [JsonInclude] public string Author { get; set; }
        [JsonInclude] public string Introduction { get; set; }
        [JsonInclude] public string Version { get; set; }
        [JsonInclude] public string Link { get; set; }
    }

    
    [Serializable]
    public struct PartState
    {
        public PartState() { }
        
        [JsonInclude] public string Name { get; set; } = "";
        [JsonInclude] public PartScope Scope { get; set; } = 0;
        [JsonInclude] public byte Default { get; set; } = 0;
        [JsonInclude] public List<string> Values { get; set; } = new();
        [JsonInclude] public List<bool> Required { get; set; } = new();
        
        public override bool Equals(object obj)
        {
            return obj is PartState state && Equals(state);
        }
        
        public bool Equals(PartState other)
        {
            return Name == other.Name &&
                   Scope == other.Scope &&
                   Default == other.Default &&
                   System.Linq.Enumerable.SequenceEqual(Values, other.Values) &&
                   System.Linq.Enumerable.SequenceEqual(Required, other.Required);
        }
    }
    
    /// <summary>
    /// Avatar配置项
    /// </summary>
    [Serializable]
    public struct ProjectSettings
    {
        public ProjectSettings() { }

        [JsonInclude] public int MaxBodySlotCost { get; set; } = 5;
        [JsonInclude] public List<PartState> States { get; set; } = new();
        
        public static int GetStatusesCode(ProjectSettings settings)
        {
            int finalHash = 0;
            foreach (var state in settings.States)
            {
                int listHash = 0;
                foreach (var value in state.Required)
                {
                    int valueHash = value ? 1 : 0;
                    listHash = CombineHashes(listHash, valueHash);
                }
                finalHash = CombineHashes(finalHash, listHash);
            }
            return finalHash;
        }

        private static int CombineHashes(int h1, int h2)
        {
            long hash = 2166136261L;
    
            hash = (hash ^ (h1 & 0xFF)) * 16777619;
            hash = (hash ^ ((h1 >> 8) & 0xFF)) * 16777619;
            hash = (hash ^ ((h1 >> 16) & 0xFF)) * 16777619;
            hash = (hash ^ ((h1 >> 24) & 0xFF)) * 16777619;
    
            hash = (hash ^ (h2 & 0xFF)) * 16777619;
            hash = (hash ^ ((h2 >> 8) & 0xFF)) * 16777619;
            hash = (hash ^ ((h2 >> 16) & 0xFF)) * 16777619;
            hash = (hash ^ ((h2 >> 24) & 0xFF)) * 16777619;
    
            return (int)(hash & 0x7FFFFFFF);
        }
        
        public override bool Equals(object obj)
        {
            return obj is ProjectSettings settings && Equals(settings);
        }
        
        public bool Equals(ProjectSettings other)
        {
            bool equal = MaxBodySlotCost == other.MaxBodySlotCost
                         && States.Count == other.States.Count;
            if (equal == false) return false;
            
            for (int i = 0; i < States.Count; i++)
                equal &= States[i].Equals(other.States[i]);
            return equal;
        }
        
        public override int GetHashCode()
        {
            return GetStatusesCode(this);
        }
    }
    
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public struct PaletteColor
    {
        [JsonInclude] public float R { get; set; }
        [JsonInclude] public float G { get; set; }
        [JsonInclude] public float B { get; set; }
        [JsonInclude] public float A { get; set; }
        
        public PaletteColor(float r, float g, float b, float a = 1.0f) { R = r; G = g; B = b; A = a; }
        public PaletteColor(Godot.Color color) { R = color.R; G = color.G; B = color.B; A = color.A; }
        
        public static implicit operator Godot.Color(PaletteColor color) { return new Godot.Color(color.R, color.G, color.B, color.A); }
        public static implicit operator PaletteColor(Godot.Color color) { return new PaletteColor(color); }
        
        public override bool Equals(object obj) 
        {
            if (obj is PaletteColor other)
            {
                return (double) this.R == (double) other.R && (double) this.G == (double) other.G && (double) this.B == (double) other.B && (double) this.A == (double) other.A;
            }
            return false;
        }
        
        public override int GetHashCode()
        {
            return HashCode.Combine(R, G, B, A);
        }
    }
    
    /// <summary>
    /// 图片调色参数
    /// </summary>
    [Serializable]
    public struct PaletteParam()
    {
        [JsonInclude] public int ElementIndex = -1;
        [JsonInclude] public PaletteColor BasicColor { get; set; } = new PaletteColor(0,0,0,0);
        [JsonInclude] public int Tolerance = 0;
        [JsonInclude] public PaletteColor ModulateColor { get; set; } = new PaletteColor(0,0,0,0);
        [JsonInclude] public int BlendMode = 0;
        
        public override bool Equals(object obj)
        {
            return obj is PaletteParam other && Equals(other);
        }

        public bool Equals(PaletteParam other)
        {
            return BasicColor.Equals(other.BasicColor) &&
                   ModulateColor.Equals(other.ModulateColor) &&
                   Tolerance == other.Tolerance &&
                   BlendMode == other.BlendMode;
        }
        
        public override int GetHashCode()
        {
            return HashCode.Combine(ElementIndex, Tolerance, BlendMode, BasicColor.GetHashCode(), ModulateColor.GetHashCode());
        }
    }

        
    /// <summary>
    /// 调色板。用于保存其他上色方案，且可以指定不同配色下的别名
    /// </summary>
    [Serializable]
    public struct Palette()
    {
        [JsonInclude] public uint Guid { get; set; } = 0;
        [JsonInclude] public string Name { get; set; }
        [JsonInclude] public string Introduction { get; set; }
        
        [JsonInclude] public List<ThemeColor> ThemeColors { get; set; } = [];
        [JsonInclude] public List<PaletteParam> IconPaletteParams { get; set; } = [];
        [JsonInclude] public List<PaletteParam> ElementPaletteParams { get; set; } = [];
    }

    
    /// <summary>
    /// Avatar的某个元素的集合，可以是一个身形，或者一个脸型，一件服装等
    /// 例如对于头发，就是一个发型在所有Pose下的样子的集合。脸型、服装等同理
    /// </summary>
    [Serializable]
    public class AvatarPart()
    {
        [JsonInclude] public uint Guid { get; set; } = 0;
        [JsonInclude] public string Name { get; set; }
        [JsonInclude] public int IconAssetId { get; set; }
        [JsonInclude] public string Introduction { get; set; }
        
        [JsonInclude] public List<ThemeColor> ThemeColors { get; set; } = [];

        /// <summary>
        /// 调色板。如果该服装有除了默认颜色外的其他上色方案，可以在这里保存
        /// </summary>
        [JsonInclude] public List<Palette> Palettes { get; set; } = [];
        
        /// <summary>
        /// 每个pose的数据
        /// key: PoseID
        /// value: AvatarPoses是个AvatarPosePart数组。 例如一个装备在站立状态下的pose图可能由多张图片组合而成
        /// </summary>
        [JsonInclude] public Dictionary<string, List<AvatarElement>> Elements { get; set; } = new();

        public override bool Equals(object obj)
        {
            return obj is AvatarPart other && Equals(other);
        }

        public bool Equals(AvatarPart obj)
        {
            bool equal = true;
            equal &= Name == obj.Name;
            equal &= IconAssetId == obj.IconAssetId;
            equal &= Introduction == obj.Introduction;
            equal &= Palettes.Count == obj.Palettes.Count;
            if (equal == false) return false;
            for (int i = 0; i < Palettes.Count; ++i)
            {
                equal &= Palettes[i].Guid == obj.Palettes[i].Guid;
                equal &= Palettes[i].Name == obj.Palettes[i].Name;
                equal &= Palettes[i].Introduction == obj.Palettes[i].Introduction;
                equal &= Palettes[i].IconPaletteParams.Count == obj.Palettes[i].IconPaletteParams.Count;
                equal &= Palettes[i].ElementPaletteParams.Count == obj.Palettes[i].ElementPaletteParams.Count;
                if (equal == false) return false;
                
                for (int j = 0; j < Palettes[i].IconPaletteParams.Count; ++j)
                    equal &= Palettes[i].IconPaletteParams[j].Equals(obj.Palettes[i].IconPaletteParams[j]);
                for (int j = 0; j < Palettes[i].ElementPaletteParams.Count; ++j)
                    equal &= Palettes[i].ElementPaletteParams[j].Equals(obj.Palettes[i].ElementPaletteParams[j]);
                
                if (equal == false) return false;
            }

            equal &= Elements.Count == obj.Elements.Count;
            foreach (var pair in Elements)
            {
                equal &= obj.Elements.ContainsKey(pair.Key);
                equal &= pair.Value.Count == obj.Elements[pair.Key].Count;
                if (equal == false) return false;
                
                for (int i = 0; i < pair.Value.Count; ++i)
                    equal &= obj.Elements[pair.Key][i].Equals(pair.Value[i]);
                if (equal == false) return false;
            }
            return equal;
        }
        
        public override int GetHashCode() { return (int)Guid; }
    }

    /// <summary>
    /// 一张Asset图片在pose中的偏移和层级等数据
    /// </summary>
    [Serializable]
    public struct AvatarElement
    {
        [JsonInclude] public int AssetId { get; set; }
        [JsonInclude] public int Layer { get; set; }
        [JsonInclude] public int LayerOffset { get; set; }

        [JsonInclude] public float PositionX { get; set; }
        [JsonInclude] public float PositionY { get; set; }
        [JsonInclude] public float Rotation { get; set; }
        [JsonInclude] public float ScaleX { get; set; }
        [JsonInclude] public float ScaleY { get; set; }
        [JsonInclude] public float Skew { get; set; }

    }
    
    [Serializable]
    public class AvatarBody() : AvatarPart { }
    
    [Serializable]
    public class AvatarHead(): AvatarPart { }
    
    [Serializable]
    public class AvatarHair(): AvatarPart { }
    
    [Serializable]
    public class AvatarFace() : AvatarPart { }
    
    [Serializable]
    public struct ClothClasses : IEquatable<ClothClasses>
    {
        [JsonInclude] public int Hash { get; set; }
		
        public EClothClasses_Type1 Type1()
        {
            return (EClothClasses_Type1)((Hash >> 16) & 0xFFFF);
        }

        public void SetType1(EClothClasses_Type1 value)
        {
            Hash = ((Hash & 0x0000FFFF) | (((short)value & 0xFFFF) << 16));
        }

        public short Type2()
        {
            return (short)(Hash & 0xFFFF);
        }
        
        public void SetType2(short value)
        {
            Hash = (int)((Hash & 0xFFFF0000u) | (uint)(value & 0xFFFF));
        }

        public ClothClasses(int hash)
        {
            Hash = hash;
        }
        
        public ClothClasses(EClothClasses_Type1 type1, short type2)
        {
            Hash = (((short)type1 & 0xFFFF) << 16) | (type2 & 0xFFFF);
        }

        public static implicit operator ClothClasses(int hash) => new ClothClasses(hash);
    
        public static implicit operator int(ClothClasses clothClasses) => clothClasses.Hash;
        
        public override bool Equals(object obj)
        {
            return obj is ClothClasses other && this.Hash == other.Hash;
        }
        public bool Equals(ClothClasses other)
        {
            return Hash == other.Hash;
        }
        public override int GetHashCode() => Hash;

        public static bool operator ==(ClothClasses left, ClothClasses right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(ClothClasses left, ClothClasses right)
        {
            return !(left == right);
        }
    }
    
    /// <summary>
    /// 角色服装数据
    /// </summary>
    [Serializable]
    public class AvatarCloth() : AvatarPart
    {
        /// <summary>
        /// 服装分类
        /// </summary>
        [JsonInclude] public ClothClasses ClothClasses = new();
        
        /// <summary>
        /// 占用的身体槽。例如连衣裙会同时占用上身和下身的槽位，使得不能再穿其他上衣。
        /// key: BodySlot.Hash
        /// value: cost
        /// </summary>
        [JsonInclude] public Dictionary<int, int> BodySlotCost { get; set; } = new();
        
        public override bool Equals(object obj) { return obj is AvatarCloth other && Equals(other); }
        public bool Equals(AvatarCloth obj)
        {
            bool equal = base.Equals(obj);
            equal &= ClothClasses.Equals(obj.ClothClasses);
            equal &= BodySlotCost.Count == obj.BodySlotCost.Count;
            if (equal == false) return false;
            
            equal &= BodySlotCost.Count == obj.BodySlotCost.Count;
            foreach (var pair in BodySlotCost)
            {
                equal &= obj.BodySlotCost.ContainsKey(pair.Key);
                if (equal == false) return false;
                
                equal &= obj.BodySlotCost[pair.Key] == pair.Value;
                if (equal == false) return false;
            }
            return equal;
        }
        
        public override int GetHashCode() { return (int)Guid; }

    }
    
    [Serializable]
    public struct AvatarDollData()
    {
        [JsonInclude] public int FormatVersion { get; set; } = 0;

        [JsonInclude] public Metadata Metadata = new();

        [JsonInclude] public ProjectSettings Settings = new();
        
        /// <summary>
        /// Asset资源映射表
        /// 把AssetID对应到文件
        /// </summary>
        [JsonInclude] public Dictionary<int, string> AssetMap { get; set; } = new();

        [JsonInclude] public List<AvatarBody> Bodies { get; set; } = [];
        [JsonInclude] public List<AvatarHead> Heads { get; set; } = [];
        [JsonInclude] public List<AvatarHair> Hairs { get; set; } = [];
        [JsonInclude] public List<AvatarFace> Faces { get; set; } = [];
        [JsonInclude] public List<AvatarCloth> Clothes { get; set; } = [];
        
        public override bool Equals(object obj)
        {
            return obj is AvatarDollData other && Equals(other);
        }

        public bool Equals(AvatarDollData data)
        {
            bool equal = true;
            equal &= FormatVersion == data.FormatVersion;
            equal &= Metadata.Equals(data.Metadata);

            equal &= AssetMap.Count == data.AssetMap.Count;
            foreach (var pair in AssetMap)
            {
                equal &= data.AssetMap.ContainsKey(pair.Key);
                equal &= pair.Value == data.AssetMap[pair.Key];
            }
            
            equal &= Bodies.Count == data.Bodies.Count;
            for (int i = 0; i < data.Bodies.Count; ++i)
                equal &= Bodies[i].Equals(data.Bodies[i]);
			
            equal &= Faces.Count == data.Faces.Count;
            for (int i = 0; i < data.Faces.Count; ++i)
                equal &= Faces[i].Equals(data.Faces[i]);

            equal &= Hairs.Count == data.Hairs.Count;
            for (int i = 0; i < data.Hairs.Count; ++i)
                equal &= Hairs[i].Equals(data.Hairs[i]);
			
            equal &= Clothes.Count == data.Clothes.Count;
            for (int i = 0; i < data.Clothes.Count; ++i)
                equal &= Clothes[i].Equals(data.Clothes[i]);
            return equal;
        }
        
        
    }
    
}

