using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Events;
using System.IO;

public class InventoryManager : MonoBehaviour
{
    public static InventoryManager Instance { get; private set; }

    [Header("Inventory Settings")]
    public int inventorySize = 36;
    public Slot[] slots;
    public Slot[] hotbarSlots;  // 9 слотов хотбара (индексы 0-8)

    [Header("Item Database")]
    public List<ItemData> itemDatabase;

    [Header("References")]
    public GameObject inventoryPanel;
    public Canvas inventoryCanvas;

    [Header("Events")]
    /// <param name="itemId">ID предмета</param>
    /// <param name="amount">Количество</param>
    public UnityEvent<string, int> OnItemAdded;
    public UnityEvent<string, int> OnItemRemoved;

    // Приватные поля
    private Dictionary<string, ItemData> _itemDict;
    private int _selectedHotbarSlot = 0;

    void Awake()
    {
        // Сделать этот объект корневым для DontDestroyOnLoad
        transform.SetParent(null);

        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
            return;
        }

        // Создаём InventoryItemFactory если его нет
        if (InventoryItemFactory.Instance == null)
        {
            var factoryGO = new GameObject("InventoryItemFactory");
            factoryGO.AddComponent<InventoryItemFactory>();
            DontDestroyOnLoad(factoryGO);
        }

        // Словарь создаём лениво
        RebuildItemDictionary();
    }

    /// <summary>
    /// Пересоздать словарь предметов из itemDatabase
    /// </summary>
    public void RebuildItemDictionary()
    {
        _itemDict = new Dictionary<string, ItemData>();
        if (itemDatabase != null)
        {
            foreach (var item in itemDatabase)
            {
                if (!string.IsNullOrEmpty(item?.id))
                {
                    _itemDict[item.id] = item;
                }
            }
        }
        Debug.Log($"[InventoryManager] Loaded {_itemDict.Count} items into dictionary");
    }

    void Start()
    {
        // Слоты созданы editor-инструментом и назначены в Inspector
        if (slots == null || slots.Length == 0)
            Debug.LogWarning("[InventoryManager] Slots not assigned! Run Tools > Setup Complete Scene first.");
        else
            foreach (var slot in slots) slot?.UpdateSlotUI();

        if (hotbarSlots != null)
            foreach (var slot in hotbarSlots) slot?.UpdateSlotUI();

        // Скрыть инвентарь по умолчанию
        if (inventoryPanel != null)
            inventoryPanel.SetActive(false);

        // Подписка на ввод
        if (PlayerInput.Instance != null)
        {
            PlayerInput.Instance.OnToggleInventory += ToggleInventory;
            PlayerInput.Instance.OnDropPressed     += DropSelectedItem;
            PlayerInput.Instance.OnHotbarSelect    += SelectHotbarSlot;
        }
        else
        {
            Debug.LogWarning("[InventoryManager] PlayerInput not found. Run Tools > Setup Complete Scene first.");
        }

        // Загрузить сохранённый инвентарь (слоты уже существуют)
        LoadFromFile();
    }
    

    public void ToggleInventory()
    {
        if (inventoryPanel != null)
        {
            bool wasActive = inventoryPanel.activeSelf;
            inventoryPanel.SetActive(!wasActive);

            if (!wasActive)
            {
                // Открытие инвентаря
                Cursor.lockState = CursorLockMode.None;
                Cursor.visible   = true;
                InventoryEvents.Instance?.OnInventoryOpened?.Invoke();
                if (PlayerInput.Instance != null)
                    PlayerInput.Instance.Enabled = false;
            }
            else
            {
                // Закрытие инвентаря
                Cursor.lockState = CursorLockMode.Locked;
                Cursor.visible   = false;
                InventoryEvents.Instance?.OnInventoryClosed?.Invoke();
                if (PlayerInput.Instance != null)
                    PlayerInput.Instance.Enabled = true;
            }
        }
    }

    public void SelectHotbarSlot(int index)
    {
        if (index < 0 || index >= 9 || hotbarSlots == null || hotbarSlots.Length < 9)
            return;

        // Снимаем выделение со старого
        if (_selectedHotbarSlot >= 0 && _selectedHotbarSlot < hotbarSlots.Length)
        {
            hotbarSlots[_selectedHotbarSlot].SetSelected(false);
        }

        _selectedHotbarSlot = index;
        hotbarSlots[index].SetSelected(true);

        // Получаем выбранный предмет
        var selectedItem = hotbarSlots[index].item;
        Debug.Log($"[Inventory] Selected hotbar slot: {index} - {selectedItem?.itemName ?? "Empty"}");

        // TODO: Эвент для использования предмета
    }

    /// <summary>
    /// Получить предмет в выбранном слоте хотбара
    /// </summary>
    public ItemData GetSelectedHotbarItem()
    {
        if (hotbarSlots != null && _selectedHotbarSlot >= 0 && _selectedHotbarSlot < hotbarSlots.Length)
        {
            return hotbarSlots[_selectedHotbarSlot].item;
        }
        return null;
    }

    /// <summary>
    /// Выбросить выбранный предмет из хотбара
    /// </summary>
    public void DropSelectedItem()
    {
        if (hotbarSlots == null || _selectedHotbarSlot >= hotbarSlots.Length)
            return;

        var slot = hotbarSlots[_selectedHotbarSlot];
        if (slot.IsEmpty) return;

        var item = slot.item;
        int amount = slot.amount;

        // Создаём предмет в мире через factory
        if (InventoryItemFactory.Instance != null)
        {
            // Используем позицию игрока
            Vector3 dropPos = Vector3.zero; // Заменить на позицию игрока
            if (Camera.main != null)
            {
                dropPos = Camera.main.transform.position + Camera.main.transform.forward * 2f;
            }

            InventoryItemFactory.Instance.DropItem(item, amount, dropPos);
        }

        // Очищаем слот
        slot.Clear();

        Debug.Log($"[Inventory] Dropped {item.itemName} x{amount}");
    }

    // ==================== ОСНОВНЫЕ ОПЕРАЦИИ ====================

    /// <summary>
    /// Добавить предмет в инвентарь
    /// </summary>
    /// <returns>Количество не поместившихся предметов</returns>
    public int AddItem(string itemId, int amount = 1)
    {
        if (!_itemDict.TryGetValue(itemId, out ItemData item))
        {
            Debug.LogWarning($"Item not found: {itemId}");
            return amount;
        }

        return AddItem(item, amount);
    }

    public int AddItem(ItemData item, int amount = 1)
    {
        if (item == null)
        {
            Debug.LogWarning("[AddItem] item is null!");
            return amount;
        }

        Debug.Log($"[AddItem] Adding {item.itemName} x{amount}, slots count: {slots?.Length ?? 0}");

        if (slots == null || slots.Length == 0)
        {
            Debug.LogWarning("[AddItem] Slots not initialized!");
            return amount;
        }

        // Сначала пытаемся доложить в существующие стеки (основной инвентарь)
        foreach (var slot in slots)
        {
            if (slot.IsEmpty) continue;
            if (slot.item.id == item.id)
            {
                amount = slot.AddItems(item, amount);
                if (amount <= 0)
                {
                    OnItemAdded?.Invoke(item.id, amount);
                    InventoryEvents.Instance?.InvokeItemAdded(item.id, slot.amount);
                    return 0;
                }
            }
        }

        // Добавляем в пустые слоты (основной инвентарь)
        foreach (var slot in slots)
        {
            if (slot.IsEmpty)
            {
                amount = slot.AddItems(item, amount);
                if (amount <= 0)
                {
                    OnItemAdded?.Invoke(item.id, amount);
                    InventoryEvents.Instance?.InvokeItemAdded(item.id, slot.amount);
                    return 0;
                }
            }
        }

        // Пробуем хотбар
        foreach (var slot in hotbarSlots)
        {
            if (!slot.IsEmpty && slot.item.id == item.id)
            {
                amount = slot.AddItems(item, amount);
                if (amount <= 0)
                {
                    OnItemAdded?.Invoke(item.id, amount);
                    InventoryEvents.Instance?.InvokeItemAdded(item.id, slot.amount);
                    return 0;
                }
            }
        }

        foreach (var slot in hotbarSlots)
        {
            if (slot.IsEmpty)
            {
                amount = slot.AddItems(item, amount);
                if (amount <= 0)
                {
                    OnItemAdded?.Invoke(item.id, amount);
                    InventoryEvents.Instance?.InvokeItemAdded(item.id, slot.amount);
                    return 0;
                }
            }
        }

        return amount;
    }

    /// <summary>
    /// Удалить предмет из инвентаря
    /// </summary>
    public bool RemoveItem(string itemId, int amount = 1)
    {
        int remaining = amount;

        foreach (var slot in slots)
        {
            if (slot.item != null && slot.item.id == itemId)
            {
                if (slot.amount >= remaining)
                {
                    var (item, taken) = slot.TakeItems(remaining);
                    OnItemRemoved?.Invoke(itemId, taken);
                    InventoryEvents.Instance?.InvokeItemRemoved(itemId, taken);
                    return true;
                }
                else
                {
                    remaining -= slot.amount;
                    slot.Clear();
                    OnItemRemoved?.Invoke(itemId, slot.amount);
                    InventoryEvents.Instance?.InvokeItemRemoved(itemId, slot.amount);
                }
            }
        }

        // Пробуем хотбар
        if (remaining > 0)
        {
            foreach (var slot in hotbarSlots)
            {
                if (slot.item != null && slot.item.id == itemId)
                {
                    if (slot.amount >= remaining)
                    {
                        var (item, taken) = slot.TakeItems(remaining);
                        OnItemRemoved?.Invoke(itemId, taken);
                        InventoryEvents.Instance?.InvokeItemRemoved(itemId, taken);
                        return true;
                    }
                    else
                    {
                        remaining -= slot.amount;
                        slot.Clear();
                        OnItemRemoved?.Invoke(itemId, slot.amount);
                        InventoryEvents.Instance?.InvokeItemRemoved(itemId, slot.amount);
                    }
                }
            }
        }

        return remaining <= 0;
    }

    /// <summary>
    /// Получить количество предмета в инвентаре
    /// </summary>
    public int GetItemCount(string itemId)
    {
        int count = 0;

        if (slots != null)
        {
            foreach (var slot in slots)
            {
                if (slot.item != null && slot.item.id == itemId)
                {
                    count += slot.amount;
                }
            }
        }

        if (hotbarSlots != null)
        {
            foreach (var slot in hotbarSlots)
            {
                if (slot.item != null && slot.item.id == itemId)
                {
                    count += slot.amount;
                }
            }
        }

        return count;
    }

    /// <summary>
    /// Есть ли предмет в инвентаре
    /// </summary>
    public bool HasItem(string itemId, int amount = 1)
    {
        return GetItemCount(itemId) >= amount;
    }

    /// <summary>
    /// Получить слот по индексу
    /// </summary>
    public Slot GetSlot(int index)
    {
        if (index >= 0 && index < slots.Length)
            return slots[index];
        return null;
    }

    /// <summary>
    /// Найти первый слот с указанным предметом
    /// </summary>
    public Slot FindSlotWithItem(string itemId)
    {
        foreach (var slot in slots)
        {
            if (slot.item != null && slot.item.id == itemId)
                return slot;
        }
        return null;
    }

    /// <summary>
    /// Найти все слоты с указанным предметом
    /// </summary>
    public List<Slot> FindAllSlotsWithItem(string itemId)
    {
        var result = new List<Slot>();

        foreach (var slot in slots)
        {
            if (slot.item != null && slot.item.id == itemId)
                result.Add(slot);
        }

        return result;
    }

    /// <summary>
    /// Найти первый пустой слот
    /// </summary>
    public Slot FindEmptySlot()
    {
        foreach (var slot in slots)
        {
            if (slot.IsEmpty)
                return slot;
        }
        return null;
    }

    /// <summary>
    /// Поменять предметы между двумя слотами
    /// </summary>
    public void SwapSlots(int fromIndex, int toIndex)
    {
        if (fromIndex < 0 || fromIndex >= slots.Length ||
            toIndex < 0 || toIndex >= slots.Length)
            return;

        var fromSlot = slots[fromIndex];
        var toSlot = slots[toIndex];

        // Сохраняем данные
        var tempItem = fromSlot.item;
        var tempAmount = fromSlot.amount;

        // Меняем
        if (toSlot.IsEmpty)
        {
            fromSlot.Clear();
            toSlot.SetItem(tempItem, tempAmount);
        }
        else
        {
            fromSlot.SetItem(toSlot.item, toSlot.amount);
            toSlot.SetItem(tempItem, tempAmount);
        }
    }

    /// <summary>
    /// Очистить инвентарь
    /// </summary>
    public void ClearInventory()
    {
        foreach (var slot in slots)
        {
            slot?.Clear();
        }
    }

    /// <summary>
    /// Вызывается когда слот очищен (внутренний метод)
    /// </summary>
    public void OnSlotCleared(int slotIndex)
    {
        // Можно добавить дополнительную логику
    }

    // ==================== ТЕСТОВЫЕ МЕТОДЫ ====================

    /// <summary>
    /// Создать тестовый предмет в мире (для отладки)
    /// </summary>
    [ContextMenu("Spawn Test Item")]
    public void SpawnTestItem()
    {
        if (itemDatabase == null || itemDatabase.Count == 0)
        {
            Debug.LogWarning("No items in database!");
            return;
        }

        // Создаём предмет напротив игрока
        Vector3 spawnPos = Vector3.zero;
        var player = GameObject.FindGameObjectWithTag("Player");
        if (player != null)
        {
            spawnPos = player.transform.position + player.transform.forward * 2f;
            spawnPos.y = 0.5f;
        }

        var item = itemDatabase[0];
        if (InventoryItemFactory.Instance != null)
        {
            InventoryItemFactory.Instance.CreateWorldItem(item, 5, spawnPos);
            Debug.Log($"Spawned test item: {item.itemName}");
        }
    }

    // ==================== РАБОТА С JSON ====================

    public string ExportToJson()
    {
        var inventoryData = new InventorySaveData();
        inventoryData.slots = new SlotData[slots.Length];

        for (int i = 0; i < slots.Length; i++)
        {
            inventoryData.slots[i] = new SlotData
            {
                itemId = slots[i].item?.id,
                amount = slots[i].amount
            };
        }

        return JsonUtility.ToJson(inventoryData, true);
    }

    /// <summary>
    /// Сохранить инвентарь в файл (Application.persistentDataPath).
    /// Доступно через правый клик на компоненте в Inspector во время Play Mode.
    /// </summary>
    [ContextMenu("Save Inventory")]
    public void SaveToFile()
    {
        try
        {
            string json = ExportToJson();
            string path = Path.Combine(Application.persistentDataPath, "inventory_save.json");
            File.WriteAllText(path, json);
            Debug.Log($"[InventoryManager] Saved inventory to: {path}");
        }
        catch (System.Exception ex)
        {
            Debug.LogError($"[InventoryManager] Failed to save inventory: {ex}");
        }
    }

    /// <summary>
    /// Загрузить инвентарь из файла (если есть).
    /// Вызывается из InventoryUIBuilder после создания слотов.
    /// Доступно через правый клик на компоненте в Inspector во время Play Mode.
    /// </summary>
    [ContextMenu("Load Inventory")]
    public void LoadFromFile()
    {
        try
        {
            string path = Path.Combine(Application.persistentDataPath, "inventory_save.json");
            if (File.Exists(path))
            {
                string json = File.ReadAllText(path);
                ImportFromJson(json);
                Debug.Log($"[InventoryManager] Loaded inventory from: {path}");
            }
            else
            {
                Debug.Log("[InventoryManager] No save file found.");
            }
        }
        catch (System.Exception ex)
        {
            Debug.LogError($"[InventoryManager] Failed to load inventory: {ex}");
        }
    }

    public void ImportFromJson(string json)
    {
        var inventoryData = JsonUtility.FromJson<InventorySaveData>(json);

        for (int i = 0; i < Mathf.Min(inventoryData.slots.Length, slots.Length); i++)
        {
            var slotData = inventoryData.slots[i];
            if (!string.IsNullOrEmpty(slotData.itemId) && _itemDict.TryGetValue(slotData.itemId, out ItemData item))
            {
                slots[i].SetItem(item, slotData.amount);
            }
            else
            {
                slots[i].Clear();
            }
        }
    }

    [System.Serializable]
    class InventorySaveData
    {
        public SlotData[] slots;
    }

    [System.Serializable]
    class SlotData
    {
        public string itemId;
        public int amount;
    }

    void OnApplicationQuit()
    {
        SaveToFile();
    }
}