using System;
using System.Collections.Generic;
using Decal.Adapter;
using Decal.Adapter.Wrappers;
using Mag.Shared;

namespace MosswartMassacre
{
    /// <summary>
    /// Sends inventory delta events (add/remove/update) via WebSocket
    /// whenever items change in the player's inventory.
    /// </summary>
    internal class LiveInventoryTracker
    {
        private readonly IPluginLogger _logger;
        private readonly HashSet<int> _trackedItemIds = new HashSet<int>();

        internal LiveInventoryTracker(IPluginLogger logger)
        {
            _logger = logger;
        }

        /// <summary>
        /// Initialize tracking for all current inventory items.
        /// Called after login or hot reload, after the full inventory dump.
        /// </summary>
        internal void Initialize()
        {
            _trackedItemIds.Clear();
            try
            {
                foreach (WorldObject wo in CoreManager.Current.WorldFilter.GetInventory())
                {
                    _trackedItemIds.Add(wo.Id);
                }
            }
            catch (Exception ex)
            {
                _logger?.Log($"[LiveInv] Error initializing: {ex.Message}");
            }
        }

        internal void OnCreateObject(object sender, CreateObjectEventArgs e)
        {
            try
            {
                var item = e.New;
                if (!IsPlayerInventory(item)) return;
                if (_trackedItemIds.Contains(item.Id)) return;

                _trackedItemIds.Add(item.Id);
                var mwo = MyWorldObjectCreator.Create(item);
                _ = WebSocket.SendInventoryDeltaAsync("add", mwo);

                // Request appraisal if item needs full ID data (spells, combat stats, etc.)
                if (!item.HasIdData && ObjectClassNeedsIdent(item.ObjectClass, item.Name))
                {
                    CoreManager.Current.Actions.RequestId(item.Id);
                }
            }
            catch (Exception ex)
            {
                _logger?.Log($"[LiveInv] Error in OnCreate: {ex.Message}");
            }
        }

        internal void OnReleaseObject(object sender, ReleaseObjectEventArgs e)
        {
            try
            {
                var item = e.Released;
                if (!_trackedItemIds.Contains(item.Id)) return;

                _trackedItemIds.Remove(item.Id);
                _ = WebSocket.SendInventoryRemoveAsync(item.Id);
            }
            catch (Exception ex)
            {
                _logger?.Log($"[LiveInv] Error in OnRelease: {ex.Message}");
            }
        }

        internal void OnChangeObject(object sender, ChangeObjectEventArgs e)
        {
            try
            {
                var item = e.Changed;
                if (!IsPlayerInventory(item))
                {
                    // Item left our inventory
                    if (_trackedItemIds.Contains(item.Id))
                    {
                        _trackedItemIds.Remove(item.Id);
                        _ = WebSocket.SendInventoryRemoveAsync(item.Id);
                    }
                    return;
                }

                if (!_trackedItemIds.Contains(item.Id))
                {
                    // New item appeared via ChangeObject
                    _trackedItemIds.Add(item.Id);
                    var mwo = MyWorldObjectCreator.Create(item);
                    _ = WebSocket.SendInventoryDeltaAsync("add", mwo);

                    // Request appraisal if item needs full ID data
                    if (!item.HasIdData && ObjectClassNeedsIdent(item.ObjectClass, item.Name))
                    {
                        CoreManager.Current.Actions.RequestId(item.Id);
                    }
                }
                else
                {
                    // Existing item changed (equip/unequip, stack change, container move)
                    var mwo = MyWorldObjectCreator.Create(item);
                    _ = WebSocket.SendInventoryDeltaAsync("update", mwo);
                }
            }
            catch (Exception ex)
            {
                _logger?.Log($"[LiveInv] Error in OnChange: {ex.Message}");
            }
        }

        internal void Cleanup()
        {
            _trackedItemIds.Clear();
        }

        private static bool ObjectClassNeedsIdent(ObjectClass oc, string name)
        {
            return oc == ObjectClass.Armor
                || oc == ObjectClass.Clothing
                || oc == ObjectClass.MeleeWeapon
                || oc == ObjectClass.MissileWeapon
                || oc == ObjectClass.WandStaffOrb
                || oc == ObjectClass.Jewelry
                || (oc == ObjectClass.Gem && !string.IsNullOrEmpty(name) && name.Contains("Aetheria"))
                || (oc == ObjectClass.Misc && !string.IsNullOrEmpty(name) && name.Contains("Essence"));
        }

        private static bool IsPlayerInventory(WorldObject item)
        {
            try
            {
                int containerId = item.Container;
                int charId = CoreManager.Current.CharacterFilter.Id;

                // Directly in character's inventory
                if (containerId == charId) return true;

                // In a side pack owned by the character
                WorldObject container = CoreManager.Current.WorldFilter[containerId];
                if (container != null &&
                    container.ObjectClass == ObjectClass.Container &&
                    container.Container == charId)
                {
                    return true;
                }

                return false;
            }
            catch
            {
                return false;
            }
        }
    }
}
