using UnityEngine;
using UnityEngine.Events;

/// <summary>
/// GAME 1303 Tier 5 — "Carry the food from A to B. Monsters try to steal it."
/// Last Delivery's core loop.
///
/// SETUP
///  1. Player (the delivery robot): TopDownMover or GridMover + Health + this script.
///  2. Carried Visual: a child sprite of the food/package. It's shown while carrying and
///     hidden when stolen.
///  3. Starting Cargo: how many items you set off with (1 for a single package;
///     3 for "deliver as many as you can").
///  4. Losing cargo: wire the monster's damage to LoseCargo — either
///        Health.OnDamaged -> DeliveryObjective.LoseOne     (a hit costs you food)
///     or from an enemy's DamageOnContact set to 0 damage plus a UnityEvent, if you want
///     the monsters to steal food WITHOUT hurting the robot (closer to Chris's pitch).
///  5. Delivery point: a DeliveryPoint trigger at B (see the other script).
///  6. OnAllCargoLost fires when you arrive empty-handed or run out — wire to
///     GameManager.GameOver or a "you failed the delivery" line.
///
/// Design note worth raising with Chris: losing the food (not health) as the fail state
/// makes the monsters scary without needing combat, which fits a delivery robot better
/// than a health bar does.
/// </summary>
public class DeliveryObjective : MonoBehaviour
{
    [Header("Cargo")]
    public int startingCargo = 1;
    public GameObject carriedVisual;
    [Tooltip("Prefab dropped in the world when cargo is stolen — the player can pick it back up.")]
    public GameObject droppedCargoPrefab;
    public float dropForce = 3f;
    [Tooltip("Seconds of immunity after losing cargo so one monster can't take everything at once.")]
    public float lossCooldown = 1f;

    [Header("Feedback")]
    public string loseSfx = "cargo_lost";
    public string pickupSfx = "collect";
    public string deliverSfx = "delivered";

    [Header("Events")]
    public UnityEvent<int> OnCargoChanged;
    public UnityEvent OnCargoLost;
    public UnityEvent OnCargoRecovered;
    public UnityEvent OnAllCargoLost;
    public UnityEvent<int> OnDelivered;      // how many were delivered

    public int Cargo { get; private set; }
    public bool HasCargo => Cargo > 0;

    private float cooldown;

    void Start()
    {
        Cargo = startingCargo;
        Refresh();
    }

    void Update() { cooldown -= Time.deltaTime; }

    /// <summary>Wire an enemy hit here. Drops one item into the world.</summary>
    public void LoseOne()
    {
        if (Cargo <= 0 || cooldown > 0f) return;
        cooldown = lossCooldown;
        Cargo--;

        if (droppedCargoPrefab != null)
        {
            var drop = Instantiate(droppedCargoPrefab, transform.position, Quaternion.identity);
            var rb = drop.GetComponent<Rigidbody2D>();
            if (rb != null)
                rb.AddForce(Random.insideUnitCircle.normalized * dropForce, ForceMode2D.Impulse);
        }

        if (!string.IsNullOrEmpty(loseSfx)) AudioManager.Instance?.PlaySFX(loseSfx);
        Refresh();
        OnCargoLost?.Invoke();
        if (Cargo <= 0) OnAllCargoLost?.Invoke();
    }

    /// <summary>Wire a DroppedCargo pickup here (or call from Collectible.OnCollected).</summary>
    public void PickUpOne()
    {
        Cargo++;
        if (!string.IsNullOrEmpty(pickupSfx)) AudioManager.Instance?.PlaySFX(pickupSfx);
        Refresh();
        OnCargoRecovered?.Invoke();
    }

    /// <summary>Called by DeliveryPoint. Returns how many were handed over.</summary>
    public int DeliverAll()
    {
        int delivered = Cargo;
        Cargo = 0;
        Refresh();
        if (delivered > 0 && !string.IsNullOrEmpty(deliverSfx)) AudioManager.Instance?.PlaySFX(deliverSfx);
        OnDelivered?.Invoke(delivered);
        return delivered;
    }

    void Refresh()
    {
        if (carriedVisual != null) carriedVisual.SetActive(Cargo > 0);
        OnCargoChanged?.Invoke(Cargo);
    }
}