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

/// <summary>
/// GAME 1303 Tier 1 — Counts everything the player has collected, by ItemType.   (v1.1)
///
/// v1.1 adds GetAllCounts() so Tier 7's SaveSystem can write every count to disk.
///
/// SETUP
///  - One empty GameObject in the scene with this script.
///  - Persist Across Scenes: ON for games where you carry items between levels
///    (Commission Witch, Zap Attack); OFF for single-level games.
///  - OnCountChanged(itemType, newCount) -> HUDController.UpdateItemCount
///  - OnScoreChanged(score) -> HUD score text
///
/// From other scripts:
///     CollectionTracker.Instance.GetCount(nightshade) >= 3   // Door/Lock, RecipeChecker
///     CollectionTracker.Instance.Spend(coin, 10)             // shops
/// </summary>
public class CollectionTracker : MonoBehaviour
{
    public static CollectionTracker Instance { get; private set; }

    public bool persistAcrossScenes = false;

    [Header("Events")]
    public UnityEvent<ItemType, int> OnCountChanged;
    public UnityEvent<int> OnScoreChanged;

    public int Score { get; private set; }

    private readonly Dictionary<ItemType, int> counts = new Dictionary<ItemType, int>();

    void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(gameObject); return; }
        Instance = this;
        if (persistAcrossScenes) DontDestroyOnLoad(gameObject);
    }

    public void Add(ItemType type, int amount = 1)
    {
        if (type == null) return;
        counts.TryGetValue(type, out int current);
        counts[type] = current + amount;
        OnCountChanged?.Invoke(type, counts[type]);

        if (type.scoreValue != 0)
        {
            Score += type.scoreValue * amount;
            OnScoreChanged?.Invoke(Score);
        }
    }

    /// <summary>Remove items. Returns false (and removes nothing) if you don't have enough.</summary>
    public bool Spend(ItemType type, int amount)
    {
        if (GetCount(type) < amount) return false;
        counts[type] -= amount;
        OnCountChanged?.Invoke(type, counts[type]);
        return true;
    }

    public int GetCount(ItemType type)
    {
        return type != null && counts.TryGetValue(type, out int c) ? c : 0;
    }

    public bool Has(ItemType type, int amount = 1) => GetCount(type) >= amount;

    /// <summary>Every item and its count — SaveSystem walks this to write the save file.</summary>
    public IReadOnlyDictionary<ItemType, int> GetAllCounts() => counts;

    public void ResetAll()
    {
        counts.Clear();
        Score = 0;
        OnScoreChanged?.Invoke(0);
    }
}