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

namespace MosswartMassacre
{
    /// <summary>
    /// Tracks Prismatic Taper inventory counts using event-driven delta math.
    /// Avoids expensive inventory scans during gameplay.
    /// </summary>
    internal class InventoryMonitor
    {
        private readonly IPluginLogger _logger;
        private readonly Dictionary<int, int> _trackedTaperContainers = new Dictionary<int, int>();
        private readonly Dictionary<int, int> _lastKnownStackSizes = new Dictionary<int, int>();

        internal int CachedPrismaticCount { get; private set; }
        internal int LastPrismaticCount { get; private set; }

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

        internal void Initialize()
        {
            try
            {
                LastPrismaticCount = CachedPrismaticCount;
                CachedPrismaticCount = Utils.GetItemStackSize("Prismatic Taper");

                _trackedTaperContainers.Clear();
                _lastKnownStackSizes.Clear();

                foreach (WorldObject wo in CoreManager.Current.WorldFilter.GetInventory())
                {
                    if (wo.Name.Equals("Prismatic Taper", StringComparison.OrdinalIgnoreCase) &&
                        IsPlayerOwnedContainer(wo.Container))
                    {
                        int stackCount = wo.Values(LongValueKey.StackCount, 1);
                        _trackedTaperContainers[wo.Id] = wo.Container;
                        _lastKnownStackSizes[wo.Id] = stackCount;
                    }
                }
            }
            catch (Exception ex)
            {
                _logger?.Log($"[TAPER] Error initializing count: {ex.Message}");
                CachedPrismaticCount = 0;
                LastPrismaticCount = 0;
                _trackedTaperContainers.Clear();
                _lastKnownStackSizes.Clear();
            }
        }

        internal void OnInventoryCreate(object sender, CreateObjectEventArgs e)
        {
            try
            {
                var item = e.New;
                if (IsPlayerOwnedContainer(item.Container) &&
                    item.Name.Equals("Prismatic Taper", StringComparison.OrdinalIgnoreCase))
                {
                    LastPrismaticCount = CachedPrismaticCount;
                    int stackCount = item.Values(LongValueKey.StackCount, 1);
                    CachedPrismaticCount += stackCount;

                    _trackedTaperContainers[item.Id] = item.Container;
                    _lastKnownStackSizes[item.Id] = stackCount;
                }
            }
            catch (Exception ex)
            {
                _logger?.Log($"[TAPER] Error in OnInventoryCreate: {ex.Message}");
            }
        }

        internal void OnInventoryRelease(object sender, ReleaseObjectEventArgs e)
        {
            try
            {
                var item = e.Released;
                if (item.Name.Equals("Prismatic Taper", StringComparison.OrdinalIgnoreCase))
                {
                    if (_trackedTaperContainers.TryGetValue(item.Id, out int previousContainer))
                    {
                        if (IsPlayerOwnedContainer(previousContainer))
                        {
                            LastPrismaticCount = CachedPrismaticCount;
                            int stackCount = item.Values(LongValueKey.StackCount, 1);
                            CachedPrismaticCount -= stackCount;
                        }

                        _trackedTaperContainers.Remove(item.Id);
                        _lastKnownStackSizes.Remove(item.Id);
                    }
                    else
                    {
                        LastPrismaticCount = CachedPrismaticCount;
                        CachedPrismaticCount = Utils.GetItemStackSize("Prismatic Taper");
                    }
                }
            }
            catch (Exception ex)
            {
                _logger?.Log($"[TAPER] Error in OnInventoryRelease: {ex.Message}");
            }
        }

        internal void OnInventoryChange(object sender, ChangeObjectEventArgs e)
        {
            try
            {
                var item = e.Changed;
                if (item.Name.Equals("Prismatic Taper", StringComparison.OrdinalIgnoreCase))
                {
                    bool isInPlayerContainer = IsPlayerOwnedContainer(item.Container);

                    if (isInPlayerContainer)
                    {
                        bool wasAlreadyTracked = _trackedTaperContainers.ContainsKey(item.Id);
                        _trackedTaperContainers[item.Id] = item.Container;

                        int currentStack = item.Values(LongValueKey.StackCount, 1);

                        if (!wasAlreadyTracked)
                        {
                            LastPrismaticCount = CachedPrismaticCount;
                            CachedPrismaticCount += currentStack;
                        }
                        else if (_lastKnownStackSizes.TryGetValue(item.Id, out int previousStack))
                        {
                            int stackDelta = currentStack - previousStack;
                            if (stackDelta != 0)
                            {
                                LastPrismaticCount = CachedPrismaticCount;
                                CachedPrismaticCount += stackDelta;
                            }
                        }

                        _lastKnownStackSizes[item.Id] = currentStack;
                    }
                }
            }
            catch (Exception ex)
            {
                _logger?.Log($"[TAPER] Error in OnInventoryChange: {ex.Message}");
            }
        }

        internal void Cleanup()
        {
            _trackedTaperContainers.Clear();
            _lastKnownStackSizes.Clear();
        }

        internal int TrackedTaperCount => _trackedTaperContainers.Count;
        internal int KnownStackSizesCount => _lastKnownStackSizes.Count;

        private static bool IsPlayerOwnedContainer(int containerId)
        {
            try
            {
                if (containerId == CoreManager.Current.CharacterFilter.Id)
                    return true;

                WorldObject container = CoreManager.Current.WorldFilter[containerId];
                if (container != null &&
                    container.ObjectClass == ObjectClass.Container &&
                    container.Container == CoreManager.Current.CharacterFilter.Id)
                {
                    return true;
                }

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