using System;
using System.Collections.Generic;
using UnityEngine;
using YachtDice.Modifiers.Definition;

namespace YachtDice.Modifiers.Runtime
{
    public class ModifierRegistry
    {
        private readonly List<ModifierInstance> instances = new();
        private readonly List<ModifierInstance> activeCache = new();
        private int maxActiveSlots;
        private bool activeCacheDirty = true;

        public event Action OnChanged;
        public event Action<IReadOnlyList<ModifierInstance>> OnActiveModifiersChanged;

        public IReadOnlyList<ModifierInstance> All => instances;
        public int MaxActiveSlots => maxActiveSlots;

        public ModifierRegistry(int maxActiveSlots = 5)
        {
            this.maxActiveSlots = maxActiveSlots;
        }

        public IReadOnlyList<ModifierInstance> Active
        {
            get
            {
                if (activeCacheDirty)
                    RebuildActiveCache();
                return activeCache;
            }
        }

        public int ActiveCount
        {
            get
            {
                int count = 0;
                for (int i = 0; i < instances.Count; i++)
                    if (instances[i].IsActive) count++;
                return count;
            }
        }

        public void SetMaxActiveSlots(int slots)
        {
            maxActiveSlots = slots;
        }

        public ModifierInstance Add(ModifierDefinition definition)
        {
            var instance = new ModifierInstance(definition);
            instances.Add(instance);
            activeCacheDirty = true;
            OnChanged?.Invoke();
            return instance;
        }

        public void Remove(ModifierInstance instance)
        {
            if (!instances.Contains(instance)) return;

            bool wasActive = instance.IsActive;
            instance.IsActive = false;
            instances.Remove(instance);
            activeCacheDirty = true;

            if (wasActive)
                OnActiveModifiersChanged?.Invoke(Active);

            OnChanged?.Invoke();
        }

        public bool TryActivate(ModifierInstance instance)
        {
            if (instance.IsActive) return false;
            if (!instances.Contains(instance)) return false;
            if (ActiveCount >= maxActiveSlots) return false;

            instance.IsActive = true;
            activeCacheDirty = true;
            OnActiveModifiersChanged?.Invoke(Active);
            OnChanged?.Invoke();
            return true;
        }

        public void Deactivate(ModifierInstance instance)
        {
            if (!instance.IsActive) return;

            instance.IsActive = false;
            activeCacheDirty = true;
            OnActiveModifiersChanged?.Invoke(Active);
            OnChanged?.Invoke();
        }

        public void ConsumeChargesOnActive()
        {
            bool changed = false;

            for (int i = instances.Count - 1; i >= 0; i--)
            {
                var inst = instances[i];
                if (!inst.IsActive) continue;
                if (!inst.Definition.HasLimitedUses) continue;

                inst.ConsumeCharge();

                if (inst.IsExpired)
                {
                    instances.RemoveAt(i);
                    changed = true;
                }
            }

            if (changed)
            {
                activeCacheDirty = true;
                OnActiveModifiersChanged?.Invoke(Active);
                OnChanged?.Invoke();
            }
        }

        public List<ModifierSaveEntry> GetSaveData()
        {
            var entries = new List<ModifierSaveEntry>();
            for (int i = 0; i < instances.Count; i++)
            {
                var inst = instances[i];
                var entry = new ModifierSaveEntry
                {
                    ModifierId = inst.Definition.Id,
                    IsActive = inst.IsActive,
                    RemainingUses = inst.RemainingUses,
                    Stacks = inst.Stacks,
                };

                foreach (var kvp in inst.CustomState)
                {
                    entry.CustomState.Add(new CustomStateEntry
                    {
                        Key = kvp.Key,
                        Value = kvp.Value,
                    });
                }

                entries.Add(entry);
            }
            return entries;
        }

        public void LoadSaveData(List<ModifierSaveEntry> entries, ModifierCatalog catalog)
        {
            instances.Clear();
            activeCacheDirty = true;

            if (entries == null) return;

            for (int i = 0; i < entries.Count; i++)
            {
                var entry = entries[i];
                var definition = catalog.FindById(entry.ModifierId);

                if (definition == null)
                {
                    Debug.LogWarning($"Modifier '{entry.ModifierId}' not found in catalog, skipping.");
                    continue;
                }

                var instance = new ModifierInstance(definition)
                {
                    IsActive = entry.IsActive,
                    RemainingUses = entry.RemainingUses,
                    Stacks = entry.Stacks,
                };

                if (entry.CustomState != null)
                {
                    foreach (var cs in entry.CustomState)
                        instance.CustomState[cs.Key] = cs.Value;
                }

                instances.Add(instance);
            }

            OnActiveModifiersChanged?.Invoke(Active);
            OnChanged?.Invoke();
        }

        public void Clear()
        {
            instances.Clear();
            activeCacheDirty = true;
            OnActiveModifiersChanged?.Invoke(Active);
            OnChanged?.Invoke();
        }

        private void RebuildActiveCache()
        {
            activeCache.Clear();
            for (int i = 0; i < instances.Count; i++)
            {
                if (instances[i].IsActive)
                    activeCache.Add(instances[i]);
            }
            activeCacheDirty = false;
        }
    }
}
