// Assets/_Project/Scripts/Gameplay/SelectionState.cs
using UnityEngine;

namespace TD.Gameplay
{
    /// <summary>
    /// Scene-local selection state. Holds a single <see cref="ISelectable"/> (the
    /// builder, a tower, or any future selectable type) and fires
    /// <see cref="OnSelectionChanged"/> when it changes.
    /// </summary>
    /// <remarks>
    /// <para><b>Local-only.</b> Selection is a UI concept — other clients have no
    /// business knowing whether you've selected something. The component is a plain
    /// MonoBehaviour and lives in the scene alongside other client-side controllers.</para>
    ///
    /// <para><b>Singleton.</b> One per scene, accessed via <see cref="Instance"/>.
    /// Selection drivers (input controller, minimap) and selection consumers
    /// (HUD, selection-ring visuals) all go through this single source of truth.</para>
    ///
    /// <para><b>Builder convenience.</b> <see cref="SelectedBuilder"/> returns the
    /// current selection cast to Builder (or null if non-builder). Lets the input
    /// controller and minimap keep the "is the local builder selected?" check
    /// short without re-type-testing.</para>
    /// </remarks>
    public class SelectionState : MonoBehaviour
    {
        // ----- Singleton --------------------------------------------------

        public static SelectionState Instance { get; private set; }

        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Debug.LogWarning("[SelectionState] Multiple instances detected. " +
                                 "Only one SelectionState should exist per scene.");
            }
            Instance = this;
        }

        private void OnDestroy()
        {
            if (Instance == this) Instance = null;
        }

        // ----- Selection state --------------------------------------------

        private ISelectable selected;

        /// <summary>The currently selected object, or null if nothing is selected.</summary>
        public ISelectable SelectedObject => selected;

        /// <summary>Convenience: the selected object if it's a Builder, else null.</summary>
        public Builder SelectedBuilder => selected as Builder;

        /// <summary>True if any object is currently selected.</summary>
        public bool HasSelection => selected != null;

        /// <summary>True if <paramref name="s"/> is the currently selected object.</summary>
        public bool IsSelected(ISelectable s) => s != null && (object)selected == (object)s;

        /// <summary>Builder overload — same semantics as <see cref="IsSelected(ISelectable)"/>.</summary>
        public bool IsSelected(Builder b) => b != null && (object)selected == (object)b;

        // ----- Events -----------------------------------------------------

        /// <summary>
        /// Fired when the selection changes. Argument is the new selection (may be null).
        /// Subscribe to drive selection-aware UI: highlights, context panels, hotkey hints.
        /// </summary>
        public event System.Action<ISelectable> OnSelectionChanged;

        // ----- Mutators ---------------------------------------------------

        /// <summary>
        /// Sets the selected object. Pass null to clear.
        /// Fires <see cref="OnSelectionChanged"/> only if the selection actually changes.
        /// </summary>
        public void Select(ISelectable s)
        {
            if ((object)selected == (object)s) return;
            selected = s;
            OnSelectionChanged?.Invoke(selected);
        }

        /// <summary>Clears the selection. Equivalent to Select(null).</summary>
        public void Clear() => Select((ISelectable)null);
    }
}
