using UnityEngine;

/// <summary>
/// GAME 1303 Tier 1 — Pushes movement state into the Animator so the Mechanim
/// controller (Idle / Walk / Run / Jump / Fall / Hurt / Dead) can drive itself.
///
/// SETUP
///  1. Add to the same GameObject as PlayerController2D and an Animator.
///  2. In your Animator Controller create these parameters:
///       Speed      (Float)   - absolute horizontal speed, 0 when standing
///       IsGrounded (Bool)
///       YVelocity  (Float)   - positive going up, negative falling
///       Jump       (Trigger)
///       Hurt       (Trigger)
///       Dead       (Trigger)
///  3. Transitions students typically wire:
///       Any -> Jump   when Jump trigger
///       Idle -> Walk  when Speed > 0.1      Walk -> Run  when Speed > runThreshold
///       Walk -> Idle  when Speed < 0.1
///       Any -> Fall   when IsGrounded == false AND YVelocity < 0
///       Fall -> Idle  when IsGrounded == true
///
/// If the Health script is on the object too, Hurt/Dead triggers fire automatically.
/// Works for non-player characters as well (e.g. Cozy Critters' pet) — just leave
/// the controller slot empty and call SetSpeed() from your own AI.
/// </summary>
[RequireComponent(typeof(Animator))]
public class PlayerAnimatorBridge : MonoBehaviour
{
    [Tooltip("Optional. If empty, drive the animator manually with SetSpeed/SetGrounded.")]
    public PlayerController2D controller;
    [Tooltip("Optional. Hooks Hurt and Dead triggers.")]
    public Health health;

    // Cache hashes — faster than string lookups every frame
    static readonly int SpeedHash      = Animator.StringToHash("Speed");
    static readonly int GroundedHash   = Animator.StringToHash("IsGrounded");
    static readonly int YVelHash       = Animator.StringToHash("YVelocity");
    static readonly int JumpHash       = Animator.StringToHash("Jump");
    static readonly int HurtHash       = Animator.StringToHash("Hurt");
    static readonly int DeadHash       = Animator.StringToHash("Dead");

    private Animator anim;

    void Awake()
    {
        anim = GetComponent<Animator>();
        if (controller == null) controller = GetComponent<PlayerController2D>();
        if (health == null) health = GetComponent<Health>();
    }

    void OnEnable()
    {
        if (controller != null) controller.OnJumped.AddListener(TriggerJump);
        if (health != null)
        {
            health.OnDamaged.AddListener(TriggerHurt);
            health.OnDied.AddListener(TriggerDead);
        }
    }

    void OnDisable()
    {
        if (controller != null) controller.OnJumped.RemoveListener(TriggerJump);
        if (health != null)
        {
            health.OnDamaged.RemoveListener(TriggerHurt);
            health.OnDied.RemoveListener(TriggerDead);
        }
    }

    void Update()
    {
        if (controller == null) return;
        anim.SetFloat(SpeedHash, Mathf.Abs(controller.Velocity.x));
        anim.SetBool(GroundedHash, controller.IsGrounded);
        anim.SetFloat(YVelHash, controller.Velocity.y);
    }

    // ---- Manual API for AI-driven characters ----
    public void SetSpeed(float speed)      => anim.SetFloat(SpeedHash, Mathf.Abs(speed));
    public void SetGrounded(bool grounded) => anim.SetBool(GroundedHash, grounded);
    public void TriggerJump()              => anim.SetTrigger(JumpHash);
    public void TriggerHurt()              => anim.SetTrigger(HurtHash);
    public void TriggerDead()              => anim.SetTrigger(DeadHash);
}