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

/// <summary>
/// GAME 1303 Tier 4 — A door that can be locked. Opens when its requirement is met, or
/// when something calls Open(). Commission Witch, Zap Attack (generator door),
/// Spark of Corruption, Roach Invasion, Detective Liz, Anabasis.
///
/// SETUP
///  1. Door sprite + Collider2D (SOLID, not a trigger — it blocks the player) + this script.
///  2. Requirement:
///       None         – opens whenever Open() is called (a switch, a boss defeated).
///       Collect      – needs Required Count of Required Item in the CollectionTracker.
///                      Consume On Open ✓ spends them (a key), ✗ just checks (a quota).
///       Flag         – opens when ChoiceFlagManager has the named flag (Tier 6).
///                      Until Tier 6 exists this behaves like None.
///  3. Auto Check: with a trigger child ("ProximityZone") the door checks the requirement
///     when the player walks up. Otherwise call TryOpen() from an Interactable (Tier 6)
///     or a UnityEvent.
///  4. Open Mode: Slide (moves by Open Offset), Fade, or Disable (just vanishes).
///  5. Locked Feedback: a rattle sound and OnOpenFailed event so the player learns
///     "I need something." Show a HUD hint here.
///
/// Zap Attack's generator door: Requirement = Collect, Item = Green Electricity,
/// Required Count = 5, Consume ✗.
/// </summary>
public class Door : MonoBehaviour
{
    public enum Requirement { None, Collect, Flag }
    public enum OpenMode { Slide, Fade, Disable }

    [Header("Lock")]
    public Requirement requirement = Requirement.None;
    public ItemType requiredItem;
    public int requiredCount = 1;
    public bool consumeOnOpen = true;
    [Tooltip("Flag mode: the flag name that must be set (Tier 6 ChoiceFlagManager).")]
    public string requiredFlag = "";
    public bool startOpen = false;

    [Header("Opening")]
    public OpenMode openMode = OpenMode.Slide;
    public Vector2 openOffset = new Vector2(0f, 3f);
    public float openSpeed = 4f;
    public bool canCloseAgain = false;

    [Header("Auto check")]
    [Tooltip("Optional trigger child. When the player is inside, the door tries to open by itself.")]
    public Collider2D proximityZone;

    [Header("Feedback")]
    public string openSfx = "door_open";
    public string lockedSfx = "door_locked";
    public UnityEvent OnOpened;
    public UnityEvent OnClosed;
    public UnityEvent OnOpenFailed;      // "You need 5 batteries" hint
    public UnityEvent<int, int> OnProgress;   // (have, needed) — for a HUD readout

    public bool IsOpen { get; private set; }

    private Vector3 closedPos;
    private Vector3 openPos;
    private Collider2D blocker;
    private SpriteRenderer sr;
    private Coroutine motion;
    private readonly Collider2D[] overlap = new Collider2D[8];
    private ContactFilter2D noFilter;

    void Awake()
    {
        closedPos = transform.position;
        openPos = closedPos + (Vector3)openOffset;
        blocker = GetComponent<Collider2D>();
        sr = GetComponentInChildren<SpriteRenderer>();
        noFilter = new ContactFilter2D();
        noFilter.NoFilter();
        if (proximityZone != null) proximityZone.isTrigger = true;
    }

    void Start()
    {
        if (startOpen) SetOpenInstant(true);
    }

    void Update()
    {
        if (IsOpen || proximityZone == null) return;
        int n = proximityZone.Overlap(noFilter, overlap);
        for (int i = 0; i < n; i++)
            if (overlap[i] != null && overlap[i].CompareTag("Player")) { TryOpen(); break; }
    }

    /// <summary>Check the requirement and open if it's satisfied. Safe to call every frame.</summary>
    public bool TryOpen()
    {
        if (IsOpen) return true;

        if (requirement == Requirement.Collect && requiredItem != null)
        {
            int have = CollectionTracker.Instance != null ? CollectionTracker.Instance.GetCount(requiredItem) : 0;
            OnProgress?.Invoke(have, requiredCount);
            if (have < requiredCount) { Refuse(); return false; }
            if (consumeOnOpen) CollectionTracker.Instance.Spend(requiredItem, requiredCount);
        }
        else if (requirement == Requirement.Flag && !string.IsNullOrEmpty(requiredFlag))
        {
            // Tier 6 hook. Until ChoiceFlagManager exists, Flag doors open freely.
            var flags = FindFlagManager();
            if (flags != null && !flags.HasFlag(requiredFlag)) { Refuse(); return false; }
        }

        Open();
        return true;
    }

    /// <summary>Open regardless of the requirement (switch, boss defeated, cutscene).</summary>
    public void Open()
    {
        if (IsOpen) return;
        IsOpen = true;
        if (!string.IsNullOrEmpty(openSfx)) AudioManager.Instance?.PlaySFX(openSfx);
        if (motion != null) StopCoroutine(motion);
        motion = StartCoroutine(Animate(true));
        OnOpened?.Invoke();
    }

    public void Close()
    {
        if (!IsOpen || !canCloseAgain) return;
        IsOpen = false;
        if (motion != null) StopCoroutine(motion);
        motion = StartCoroutine(Animate(false));
        OnClosed?.Invoke();
    }

    void Refuse()
    {
        if (!string.IsNullOrEmpty(lockedSfx)) AudioManager.Instance?.PlaySFX(lockedSfx);
        OnOpenFailed?.Invoke();
    }

    IEnumerator Animate(bool opening)
    {
        if (openMode == OpenMode.Disable)
        {
            gameObject.SetActive(!opening);
            yield break;
        }

        if (opening && blocker != null) blocker.enabled = false;

        if (openMode == OpenMode.Slide)
        {
            Vector3 target = opening ? openPos : closedPos;
            while (Vector3.Distance(transform.position, target) > 0.01f)
            {
                transform.position = Vector3.MoveTowards(transform.position, target, openSpeed * Time.deltaTime);
                yield return null;
            }
            transform.position = target;
        }
        else if (sr != null)   // Fade
        {
            float from = sr.color.a, to = opening ? 0f : 1f, t = 0f;
            while (t < 1f)
            {
                t += Time.deltaTime * openSpeed;
                Color c = sr.color; c.a = Mathf.Lerp(from, to, t); sr.color = c;
                yield return null;
            }
        }

        if (!opening && blocker != null) blocker.enabled = true;
    }

    void SetOpenInstant(bool open)
    {
        IsOpen = open;
        if (blocker != null) blocker.enabled = !open;
        if (openMode == OpenMode.Slide) transform.position = open ? openPos : closedPos;
        else if (openMode == OpenMode.Disable) gameObject.SetActive(!open);
        else if (sr != null) { Color c = sr.color; c.a = open ? 0f : 1f; sr.color = c; }
    }

    // Tier 6 forward-compatibility without a hard dependency.
    ChoiceFlagManager FindFlagManager() => ChoiceFlagManager.Instance;

    void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.green;
        Vector3 from = Application.isPlaying ? closedPos : transform.position;
        Gizmos.DrawLine(from, from + (Vector3)openOffset);
        Gizmos.DrawWireCube(from + (Vector3)openOffset, Vector3.one * 0.3f);
    }
}