using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Decal.Interop.Core;
using Decal.Interop.SpellFilter;

namespace Decal.SpellFilter
{
    [ComVisible(true)]
    [Guid("C2D43735-BE7E-4829-AF73-F2E7E820EB16")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(_ISpellsEvents))]
    [ProgId("SpellFilter.Spells")]
    public class SpellsImpl : ISpells, IDecalService
    {
        private readonly Dictionary<int, SpellImpl> _spellsById = new Dictionary<int, SpellImpl>();
        private readonly Dictionary<string, SpellImpl> _spellsByName = new Dictionary<string, SpellImpl>(StringComparer.OrdinalIgnoreCase);
        private readonly Dictionary<int, ComponentImpl> _componentsById = new Dictionary<int, ComponentImpl>();
        private readonly Dictionary<string, ComponentImpl> _componentsByName = new Dictionary<string, ComponentImpl>(StringComparer.OrdinalIgnoreCase);
        private readonly HashSet<int> _knownSpells = new HashSet<int>();
        private int _lastSpellId;
        private string _server = string.Empty;

        // COM events
        public event _ISpellsEvents_LoginEventHandler Login;
        public event _ISpellsEvents_Spellbook_AddEventHandler Spellbook_Add;
        public event _ISpellsEvents_Spellbook_DeleteEventHandler Spellbook_Delete;

        // ISpells parameterized properties - accessed via IDispatch
        public Spell SpellByID => null;
        public Spell SpellByName => null;

        public bool SpellKnown => false;

        public int LastSpellID => _lastSpellId;

        public string Server => _server;

        public Component ComponentByID => null;
        public Component ComponentByName => null;

        // Internal accessors for parameterized property dispatch
        internal SpellImpl GetSpellByID(int id)
        {
            _spellsById.TryGetValue(id, out var spell);
            return spell;
        }

        internal SpellImpl GetSpellByName(string name)
        {
            _spellsByName.TryGetValue(name, out var spell);
            return spell;
        }

        internal bool IsSpellKnown(int id)
        {
            return _knownSpells.Contains(id);
        }

        internal ComponentImpl GetComponentByID(int id)
        {
            _componentsById.TryGetValue(id, out var comp);
            return comp;
        }

        internal ComponentImpl GetComponentByName(string name)
        {
            _componentsByName.TryGetValue(name, out var comp);
            return comp;
        }

        // Registration methods
        internal void RegisterSpell(SpellImpl spell)
        {
            _spellsById[spell.SpellID] = spell;
            if (!string.IsNullOrEmpty(spell.Name))
                _spellsByName[spell.Name] = spell;
            if (spell.SpellID > _lastSpellId)
                _lastSpellId = spell.SpellID;
        }

        internal void RegisterComponent(ComponentImpl component)
        {
            _componentsById[component.ComponentID] = component;
            if (!string.IsNullOrEmpty(component.Name))
                _componentsByName[component.Name] = component;
        }

        internal void OnLogin(int characterId)
        {
            _knownSpells.Clear();
            Login?.Invoke(characterId);
        }

        internal void OnSpellbookAdd(int spellId)
        {
            _knownSpells.Add(spellId);
            Spellbook_Add?.Invoke(spellId);
        }

        internal void OnSpellbookDelete(int spellId)
        {
            _knownSpells.Remove(spellId);
            Spellbook_Delete?.Invoke(spellId);
        }

        // IDecalService
        public void Initialize(DecalCore pDecal)
        {
            // Spell data would be loaded from the portal.dat via the DatService
            // The spell table is at file ID 0x0E00000E in portal.dat
        }

        public void BeforePlugins()
        {
        }

        public void AfterPlugins()
        {
        }

        public void Terminate()
        {
            _spellsById.Clear();
            _spellsByName.Clear();
            _componentsById.Clear();
            _componentsByName.Clear();
            _knownSpells.Clear();
        }
    }
}
