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

/// <summary>
/// GAME 1303 Tier 4 — A bag of named true/false facts about the playthrough:
/// "met_the_ghost", "generator_powered", "boss_defeated", "took_the_left_path".
/// Doors, switches, dialogue and endings all read from here.
///
/// (This lands in Tier 4 because Door needs it. Tier 6's narrative scripts —
/// DialogueRunner, EndingSelector, WorldStateSwapper — use the same component.)
///
/// SETUP
///  - One empty GameObject "FlagManager" with this script. Tick Persist Across Scenes
///    for any game where progress spans levels.
///  - Set a flag from any UnityEvent: pick ChoiceFlagManager -> SetFlag (string).
///    e.g. BossController.OnBossDefeated -> SetFlag("boss1_defeated")
///  - Counters are for "how many times" questions: AddCount("ingredients_burned", 1).
///
/// From code:
///     ChoiceFlagManager.Instance.SetFlag("door_opened");
///     if (ChoiceFlagManager.Instance.HasFlag("has_key")) ...
///     int n = ChoiceFlagManager.Instance.GetCount("ghosts_freed");
/// </summary>
public class ChoiceFlagManager : MonoBehaviour
{
    public static ChoiceFlagManager Instance { get; private set; }

    public bool persistAcrossScenes = true;

    [Tooltip("Flags that start set (useful for testing a later part of the game).")]
    public List<string> startingFlags = new List<string>();

    [Header("Events")]
    public UnityEvent<string> OnFlagSet;
    public UnityEvent<string> OnFlagCleared;
    public UnityEvent<string, int> OnCountChanged;

    private readonly HashSet<string> flags = new HashSet<string>();
    private readonly Dictionary<string, int> counters = new Dictionary<string, int>();

    void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(gameObject); return; }
        Instance = this;
        if (persistAcrossScenes) DontDestroyOnLoad(gameObject);
        foreach (var f in startingFlags) flags.Add(f);
    }

    // ---- Flags ----
    public void SetFlag(string flag)
    {
        if (string.IsNullOrEmpty(flag) || !flags.Add(flag)) return;
        OnFlagSet?.Invoke(flag);
    }

    public void ClearFlag(string flag)
    {
        if (!flags.Remove(flag)) return;
        OnFlagCleared?.Invoke(flag);
    }

    public bool HasFlag(string flag) => !string.IsNullOrEmpty(flag) && flags.Contains(flag);

    /// <summary>True only if every name in the comma-separated list is set. Prefix a name
    /// with ! to require it NOT be set: "has_key, !alarm_tripped".</summary>
    public bool HasAll(string commaSeparated)
    {
        if (string.IsNullOrWhiteSpace(commaSeparated)) return true;
        foreach (var raw in commaSeparated.Split(','))
        {
            string s = raw.Trim();
            if (s.Length == 0) continue;
            bool negate = s[0] == '!';
            if (negate) s = s.Substring(1).Trim();
            if (HasFlag(s) == negate) return false;
        }
        return true;
    }

    // ---- Counters ----
    public void AddCount(string key, int amount = 1)
    {
        counters.TryGetValue(key, out int c);
        counters[key] = c + amount;
        OnCountChanged?.Invoke(key, counters[key]);
    }

    public int GetCount(string key) => counters.TryGetValue(key, out int c) ? c : 0;

    // ---- Bookkeeping ----
    public void ResetAll()
    {
        flags.Clear();
        counters.Clear();
        foreach (var f in startingFlags) flags.Add(f);
    }

    /// <summary>All set flags, for a Tier 7 SaveSystem.</summary>
    public List<string> GetAllFlags() => new List<string>(flags);

    public void LoadFlags(IEnumerable<string> saved)
    {
        flags.Clear();
        foreach (var f in saved) flags.Add(f);
    }
}