Problem with Animator , script and Sub-State Machine after refactoring to State Machine

I don’t know if this is the right section, if so, I apologize in advance and ask to move it.
I have a problem with the enemy (Ghost), so I use SubState-Machines. So, in each SubState-Machine, I have various animations, which are selected randomly. In the animator, I have int parameters, photos of which I’ve attached, which are used to randomly select the animations, and Trigger parameters to enter the various SubState-Machines or select certain animations.
Before splitting the code (since I had almost everything in a single script called GhostController) it worked pretty well, but when I decided to make a state machine to make everything more orderly and modular, I destroyed everything and I can’t fix it anymore and I’m trying everything (yes, I should have thought about it before, it’s true, have mercy, I’m a beginner, I’ve been studying Unity3D for a year and something, I still have a lot to learn, but what do they say? You learn from your mistakes, right?)
So my intention was that

  1. the Enemy, having arrived at the PatrolPoint, stops, randomly enters “SpecialEventStateMachine” or “IdleStateMachine”, then selects a random animation, also changing state, waits for the duration of the animation and then changes PatrolPoint, entering again the SubState-Machine “WallkStateMachine”, until it stays still on the Patrol, it can neither follow nor attack the The Player,
    obviously, while walking and entering a certain range, can follow the player, and if he gets even closer and enters attack range, he attacks the player, selecting one of the two animations randomly in AttackStateMachine and then focusing the player’s camera on the enemy. One last thing I wanted to implement, but I’ve had quite a few problems with, is detecting when the Player is behind the enemy, so as to activate a backward walk, activating the “TriggerWalkBack” trigger.
    I’ll also share the various scripts with you, leaving the codes commented, so perhaps you can understand the previous flows.
    The enemy has a “Stand Up” animation when it comes to the patrol, handled with speed and selected condition with Less
    In GhostController I could control almost everything before
using System.Collections;
using UnityEngine;
using static GhostStateMachine;

public class GhostAnimation : MonoBehaviour
{
    private Animator animator;
    //private bool isWalking = false;
    //private bool canWalk = true;
    public bool IsBusy => animator.GetBool("IsBusy"); private GhostStateMachine stateMachine;

    /// <summary>Nomi stati "selettore" nell'Animator: non hanno clip con fine significativa.</summary>
    private static readonly int[] SelectorNameHashes =
    {
        Animator.StringToHash("IdleSelector"),
        Animator.StringToHash("EventType"),
        Animator.StringToHash("WalkingSelector"),
    };

    void Awake()
    {
        animator = GetComponent<Animator>();
        if (animator == null) Debug.LogError("Animator non trovato!");
        stateMachine = GetComponent<GhostStateMachine>();
    }

    //public void StartWalkSequence(int walkingType)
    //{
    //    if (!canWalk || isWalking || animator == null || IsBusy) return;
    //    isWalking = true;
    //    Debug.Log("canWalk: " + canWalk + ", isWalking: " + isWalking + ", IsBusy: " + IsBusy);
    //    Debug.Log("Start walking with type: " + walkingType);

    //    animator.SetInteger("WalkingType", walkingType);
    //    animator.SetTrigger("TriggerWalk");

    //    //StartCoroutine(WaitForWalkAnimation());
    //}

    //private IEnumerator WaitForWalkAnimation()
    //{
    //    Debug.Log("Waiting for walk animation to finish...");

    //    yield return new WaitUntil(() => IsLocomotionIntroFinished());
    //    Debug.Log("Walking intro / transition into crawl finished (code-side check)");
    //}

    //public void StopWalk()
    //{
    //    if (animator == null) return;
    //    animator.SetFloat("Speed", 0f);
    //    isWalking = false;
    //    canWalk = false;
    //}

    public void AllowWalk()
    {
        //IsBusy = false;
        //isWalking = false;
        //canWalk = true;
        if (animator != null)
        {
            animator.SetBool("IsBusy", false);
            animator.SetBool("IsPlayingSpecialEvent", false);
        }
    }

    public void AnimationFinished()
    {
        animator.SetBool("IsBusy", false);

        if (stateMachine != null)
            stateMachine.OnAnimationFinished();
    }

    public void UpdateMovementAnimation(float speed)
    {
        if (animator == null) return;
        animator.SetFloat("Speed", speed, 0.15f, Time.deltaTime);
    }

  
    public bool IsPatrolArrivalStandFinished()
    {
        if (animator == null) return true;
        if (animator.IsInTransition(0)) return false;

        AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(0);
        if (info.IsTag("WalkEnd"))
            return info.normalizedTime >= 0.98f;

        

        return false;
    }

  
    public bool IsPatrolIdleOrSpecialFinished()
    {
        if (animator == null) return true;
        if (animator.IsInTransition(0)) return false;

        AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(0);
        if (info.IsName("IdleStateMachine/In_Place_Ghost_Idle_Standing_LookBehind") ||
        info.IsName("IdleStateMachine/In_Place_Ghost_Idle_LayingSitUp_HeadSpin_Scare") ||
        info.IsName("IdleStateMachine/Ghost_Idle_Standing_LookBehind") ||
        info.IsName("IdleStateMachine/Ghost_Idle_Weeping_Exit") ||
        info.IsName("SpecialEventStateMachine/Ghost_Idle_Victim_Possession") ||
        info.IsName("SpecialEventStateMachine/Ghost_Idle_Standing_HeadShake") ||
        info.IsName("SpecialEventStateMachine/Ghost_Idle_Bound_Headshake") ||
        info.IsName("SpecialEventStateMachine/In_Place_Ghost_Idle_Standing_HandsReachOut") ||
        info.IsName("SpecialEventStateMachine/In_Place_Ghost_Idle_Standing"))
        {
            return info.normalizedTime >= 0.98f;
        }


        return false;
    }

   
    public bool IsLocomotionIntroFinished()
    {
        if (animator == null) return true;
        if (animator.IsInTransition(0)) return false;

        AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(0);
        
        return info.normalizedTime >= 0.98f;
    }

    //private static bool IsSelectorState(AnimatorStateInfo info)
    //{
    //    for (int i = 0; i < SelectorNameHashes.Length; i++)
    //    {
    //        if (info.shortNameHash == SelectorNameHashes[i])
    //            return true;
    //    }
    //    return false;
    //}

    /// <summary>Compatibilità con attacchi / codice esistente: clip one-shot sul layer base.</summary>
    public bool IsAnimationFinished()
    {
        if (animator == null) return true;
        if (animator.IsInTransition(0)) return false;

        AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(0);
        if (info.IsTag("WalkEnd"))
            return info.normalizedTime >= 0.98f;
        Debug.Log("Animazione finita");
        //Debug.Log("IsLocomotionIntroFinished - State: " + info.shortNameHash + ", Normalized Time: " + info.normalizedTime);


        return info.normalizedTime >= 0.98f;
    }

    public void PlayRandomIdle()
    {
        if (animator == null) return;
        //IsBusy = true;
        animator.SetBool("IsPlayingSpecialEvent", false);
        animator.SetBool("IsBusy", true);
        animator.SetInteger("IdleType", Random.Range(0, 4));
        animator.SetTrigger("TriggerIdle");
    }

    public void PlayRandomSpecialEvent()
    {
        if (animator == null) return;
        //IsBusy = true;
        animator.SetBool("IsPlayingSpecialEvent", true);
        animator.SetBool("IsBusy", true);
        animator.SetInteger("EventType", Random.Range(0, 5));
        animator.SetTrigger("TriggerSpecialEvent");

        //StartCoroutine(WaitAnimSpecial());

    }

//    private IEnumerator WaitAnimSpecial()
//    {
//        yield return new WaitUntil(() =>
//    animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 0.98f
//);

//        if (stateMachine != null)
//        {
//            stateMachine.ChangeState(GhostState.Walking);
//        }
//    }

    public void TriggerWalkBack()
    {
        if (animator == null) return;
        animator.SetTrigger("TriggerWalkBack");
    }

    //public void TriggerWalkForward()
    //{
    //    if (animator == null) return;
    //    animator.SetTrigger("TriggerWalk");
    //}

    public void PlayAttack(int attackType)
    {
        if (animator == null) return;

        //IsBusy = true;
        animator.SetBool("IsPlayingSpecialEvent", false);
        animator.SetBool("IsBusy", true);
        animator.SetInteger("AttackType", attackType);
        animator.SetTrigger("TriggerAttack");
    }

    //public bool IsPlayingIdle
    //{
    //    get
    //    {
    //        if (animator == null) return false;
    //        return IsBusy && !animator.GetBool("IsPlayingSpecialEvent");
    //    }
    //}

    //public bool IsPlayingSpecialEvent
    //{
    //    get
    //    {
    //        if (animator == null) return false;
    //        return animator.GetBool("IsPlayingSpecialEvent");
    //    }
    //}
}
using ScriptBoy.ProceduralBook;
using System.Collections;
using UnityEngine;

public class GhostAttack : MonoBehaviour
{
    public float attackCooldown = 2f;

    public float lastAttackTime;

    public FearManager fearManager;

    private GhostController ghostController;
    private GhostEvent ghostEvent;
    private GhostAnimation ghostAnimation;
    public Movement PlayerMovement;
    public Transform player;
    private GhostMovement movement;

    [Header("Attack Settings")]
    public float attackDistance = 2f;
    public float grabDistance = 1.2f; // distanza ravvicinata per grab
    [Range(0f, 180f)]
    public float walkBackAngle = 60f; // angolo dietro per camminata all'indietro

    //public float cameraFocusSpeed = 5f;
    //private bool isCameraFocusing = false;

    private bool isAttacking = false;

    //public Camera mainCamera;

    private void Awake()
    {
        ghostController = GetComponent<GhostController>();
        movement = GetComponent<GhostMovement>();
        ghostAnimation = GetComponent<GhostAnimation>();
        ghostEvent = GetComponent<GhostEvent>();
    }

    private void Update()
    {
        ghostController.CameraFocus();
    }

    public void AttackPlayer()
    {
        if (Time.time < lastAttackTime + attackCooldown)
            return;

        lastAttackTime = Time.time;

        // Logica per attaccare il giocatore
        Debug.Log("Ghost Attack!");

        // Gestione della paura
        if (fearManager != null)
        {
            fearManager.AddFear(10f); // Aggiungi paura al giocatore
        }

        StartCoroutine(AttackRoutine());
    }

    private IEnumerator AttackRoutine()
    {
        //ghostAttack.lastAttackTime = Time.time;
        //ghostAnimation.IsBusy = true;
        ghostController.isCameraFocusing = true;
        ghostController.mainCamera.fieldOfView = Mathf.Lerp(ghostController.mainCamera.fieldOfView, 40f, Time.deltaTime * 5f);
        int attackType = Random.Range(0, 2);

        // 🔥 Aggiungi il sollevamento del ghost quando inizia l'attacco
        if (attackType == 0)
        {
            // Distanziamo e solleviamo il ghost per attacco type 0
            yield return StartCoroutine(DistanceAndLiftGhost(0.5f, 0.5f));  // Distanza dal player + alzamento
        }
        else if (attackType == 1)
        {
            // Solo distanziamento (per attacco type 1), senza sollevamento, ma abbassiamo leggermente il ghost
            yield return StartCoroutine(DistanceAndLowerGhost(1f, -0.2f));  // Distanza dal player + abbassamento
        }


        // 🔥 PASSA IL TIPO GIUSTO
        ghostAnimation.PlayAttack(attackType);
        ghostEvent.RandomTransform();

        yield return StartCoroutine(HoverGhost(0.5f, 0.3f));

        if (attackType == 0)
            yield return StartCoroutine(DragPlayer());
        else
            yield return StartCoroutine(LiftPlayer());

        yield return new WaitUntil(() => ghostAnimation.IsAnimationFinished());

        ghostController.EnablePlayerControl();
        ghostController.ResetPlayerPosition();


        movement.agent.isStopped = false;
        movement.agent.ResetPath();

        //ghostAnimation.IsBusy = false;
        isAttacking = false;
        ghostController.isCameraFocusing = false;
        ghostController.mainCamera.fieldOfView = Mathf.Lerp(ghostController.mainCamera.fieldOfView, 60f, Time.deltaTime * 5f);
        ghostEvent.ResetAllExpressionsSmooth();
    }

    private IEnumerator DistanceAndLiftGhost(float distance, float height)
    {
        // Distanziamo il ghost dal player e lo solleviamo
        Vector3 startPos = transform.position;
        Vector3 targetPos = player.position + transform.forward * distance + Vector3.up * height;

        float elapsed = 0f;
        float duration = 0.3f;  // Tempo per distanziare e alzare

        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            transform.position = Vector3.Lerp(startPos, targetPos, elapsed / duration);
            yield return null;
        }

        transform.position = targetPos; // Garantisce che arrivi esattamente alla posizione finale
    }

    private IEnumerator DistanceAndLowerGhost(float distance, float height)
    {
        // Distanziamo il ghost dal player e lo abbassiamo leggermente
        Vector3 startPos = transform.position;
        Vector3 targetPos = player.position + transform.forward * distance + Vector3.up * height;

        float elapsed = 0f;
        float duration = 0.3f;  // Tempo per distanziare e abbassare

        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            transform.position = Vector3.Lerp(startPos, targetPos, elapsed / duration);
            yield return null;
        }

        transform.position = targetPos; // Garantisce che arrivi esattamente alla posizione finale
    }

    private IEnumerator RaiseGhost(float height)
    {
        Vector3 startPos = transform.position;
        Vector3 targetPos = startPos + Vector3.up * height;

        float elapsed = 0f;
        float duration = 0.3f;  // Tempo per l'alzamento

        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            transform.position = Vector3.Lerp(startPos, targetPos, elapsed / duration);
            yield return null;
        }

        transform.position = targetPos; // Garantisce che arrivi esattamente alla posizione finale
    }

    private IEnumerator HoverGhost(float duration, float height)
    {
        Vector3 start = transform.position;
        Vector3 target = start + Vector3.up * height;

        float time = 0;

        while (time < duration)
        {
            transform.position = Vector3.Lerp(start, target, time / duration);
            time += Time.deltaTime;
            yield return null;
        }

        transform.position = target;
    }

    private IEnumerator DragPlayer()
    {
        if (!player) yield break;

        ghostController.DisablePlayerControl();

        float duration = 1.5f;

        // 🔥 OFFSET RAVVICINATO davanti al ghost
        float grabDistance = 0.5f; // distanza ravvicinata
        Vector3 offset = transform.forward * grabDistance;

        // salva altezza del player
        float groundY = player.position.y;

        float time = 0f;

        while (time < duration)
        {
            // posizione target: vicino al ghost, stessa altezza
            Vector3 targetPos = transform.position + offset;
            targetPos.y = groundY;

            // sposta direttamente il player
            player.position = targetPos;

            time += Time.deltaTime;
            yield return null;
        }

        ghostController.EnablePlayerControl();
    }

    private IEnumerator LiftPlayer()
    {
        if (!player) yield break;

        ghostController.DisablePlayerControl();

        float duration = 1.5f;
        float height = 2f;

        Vector3 fixedXZ = player.position;
        fixedXZ.y = 0;

        float startY = player.position.y;
        float targetY = startY + height;

        float time = 0f;

        // SALITA
        while (time < duration)
        {
            float newY = Mathf.Lerp(startY, targetY, time / duration);

            Vector3 pos = fixedXZ;
            pos.y = newY;

            player.position = pos;

            time += Time.deltaTime;
            yield return null;
        }

        // 🔥 NON ASPETTIAMO PIÙ L’ANIMAZIONE (BUG FIX)
        yield return new WaitForSeconds(0.1f);

        // 🔥 FORZA SUBITO A TERRA
        float groundY = player.GetComponent<CapsuleCollider>().bounds.min.y;

        Vector3 finalPos = player.position;
        finalPos.y = groundY;

        player.position = finalPos;

        ghostController.EnablePlayerControl();
    }
}
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
using static GhostStateMachine;

public class GhostMovement : MonoBehaviour
{
    [Header("Movement Settings")]
    public float moveSpeed = 3.5f;

    [Header("Patrol Settings")]
    public Transform[] patrolPoints;
    public float arrivalThreshold = 0.2f;
    public float slowDownDistance = 1.0f;
    public float minWaitTime = 1f;
    public float maxWaitTime = 3f;
    private bool isWaitingAtPatrol = false;

    private bool isFollowingPlayer = false;
    public NavMeshAgent agent;

    private GhostAnimation ghostAnimation;
    private GhostStateMachine ghostStateMachine;
    private GhostAttack ghostAttack;

    private int currentPoint;
    private bool isAttacking = false;

    private bool isWalkingBack = false;

    [Header("Follow Settings")]
    public float followDistance = 5f;

    [SerializeField] Transform player;

    void Awake()
    {
        ghostAnimation = GetComponent<GhostAnimation>();
        ghostStateMachine = GetComponent<GhostStateMachine>();
        ghostAttack = GetComponent<GhostAttack>();

        agent = GetComponent<NavMeshAgent>();
        if (agent == null)
            Debug.LogError("NavMeshAgent non trovato!");

        agent.speed = moveSpeed;
        agent.stoppingDistance = arrivalThreshold;
        agent.autoBraking = true;
    }

    void Update()
    {
        //HandlePatrol();
    }

    public void MoveToPatrol()
    {
        if (patrolPoints.Length == 0) return;

        if (!agent.hasPath)
            agent.SetDestination(patrolPoints[currentPoint].position);
        agent.isStopped = false;
    }

    public void SetNextPatrol()
    {
        if (patrolPoints.Length == 0) return;
        currentPoint = Random.Range(0, patrolPoints.Length);
        agent.SetDestination(patrolPoints[currentPoint].position);
    }

    public bool HasReachedDestination()
    {
        Debug.Log("Reached destination, starting patrol arrival.");

        return !agent.pathPending && agent.remainingDistance <= arrivalThreshold  && agent.velocity.sqrMagnitude < 0.01f;
    }

    // Nuove funzioni per gestire il movimento di inseguimento
    public void MoveToPlayer(Transform player)
    {
        agent.SetDestination(player.position);
    }

    public void StopMoving()
    {
        agent.isStopped = true;
    }

    public void HandlePatrol()
    {


        // Blocca il comportamento di pattugliamento se ci sono altre azioni in corso
        if (isAttacking || isFollowingPlayer || ghostAnimation.IsBusy) // || ghostAnimation.IsPlayingSpecialEvent)
            return;

        // Quando il fantasma arriva al punto di pattugliamento, entra nella routine
        if (!isWaitingAtPatrol && HasReachedDestination() && !ghostAnimation.IsBusy)
        {
            StartCoroutine(PatrolPointRoutine());
        }
    }

    public IEnumerator PatrolPointRoutine()
    {
        // Inizia la routine di attesa quando il fantasma arriva al punto di pattugliamento
        isWaitingAtPatrol = true;
        agent.isStopped = true;  // Ferma il movimento del ghost
        agent.velocity = Vector3.zero;

        // Stoppa l'animazione di camminata
        //ghostAnimation.StopWalk();

        // Aspetta che l'animazione di arrivo a punto pattuglia sia finita
        yield return new WaitUntil(() => ghostAnimation.IsPatrolArrivalStandFinished());

        if (isFollowingPlayer)
        {
            isWaitingAtPatrol = false;
            yield break;
        }

        // Scegli tra Idle e SpecialEvent, ma solo quando il ghost è fermo
        bool chooseSpecialEvent = Random.value < 0.5f;

        if (chooseSpecialEvent)
        {
            // Esegui animazione speciale
            ghostStateMachine.ChangeState(GhostState.SpecialEvent);
        }
        else
        {
            // Esegui animazione idle
            ghostStateMachine.ChangeState(GhostState.Idle);
        }

        // Aspetta che l'animazione finisce prima di continuare
        yield return new WaitUntil(() => ghostAnimation.IsPatrolIdleOrSpecialFinished());

        // Se il ghost stava seguendo il giocatore, interrompe la routine
        if (isFollowingPlayer)
        {
            isWaitingAtPatrol = false;
            yield break;
        }

        // Permetti al fantasma di camminare di nuovo
        ghostAnimation.AllowWalk();

        // Imposta il prossimo punto di pattugliamento
        SetNextPatrol();
        agent.isStopped = false; // Riprende il movimento

        // Avvia una sequenza di camminata casuale, ma rimanendo nella camminata in loop
        StartWalkRandom();

        isWaitingAtPatrol = false;
    }

    public void StartWalkRandom()
    {
        int walkingType = 0;

        // Se il fantasma è vicino a un muro, cambia la camminata
        if (IsNearWall(1f) && Random.value < 0.4f)
            walkingType = 1;

        //StartWalkSequence(walkingType);
    }

    private bool IsNearWall(float distance)
    {
        RaycastHit hit;
        Vector3 origin = transform.position + Vector3.up * 0.5f;
        if (Physics.Raycast(origin, transform.forward, out hit, distance))
            if (hit.collider.CompareTag("Wall"))
                return true;
        return false;
    }


    public void HandlePlayerFollow()
    {
        if (player == null) return;

        // 🔹 CALCOLO SE IL PLAYER È DIETRO (ANGOLARE)
        bool isBehind = IsPlayerBehind();

        // 🔹 ANIMAZIONE WALK-BACK (PRIORITÀ MASSIMA)
        if (isBehind)
        {
            if (!isWalkingBack)
            {
                isWalkingBack = true;
                //ghostAnimation.animationController.TriggerWalkBack();
                Debug.Log("Walk-back attivato!");
            }
        }
        else
        {
            if (isWalkingBack)
            {
                //MoveBackwardsTowardsPlayer(2); // movimento fisico
                isWalkingBack = false;
                //animationController.TriggerWalkForward();
            }
        }

        // 🔹 SE IL GHOST È IN IDLE O SPECIAL EVENT, NON PUÒ SEGUIRE O ATTACCARE
        //if (animationController.IsPlayingIdle || animationController.IsPlayingSpecialEvent)
        //{
        //    agent.isStopped = true;
        //    isFollowingPlayer = false;
        //    return;
        //}

        // 🔹 ATTACCO/FOLLOW NORMALE
        float distanceToPlayer = Vector3.Distance(transform.position, player.position);
        Vector3 playerFeet = player.GetComponent<Collider>().bounds.min;
        float distanceToFeet = Vector3.Distance(transform.position, playerFeet);
        bool canGrab = distanceToFeet <= ghostAttack.grabDistance;

        if (distanceToPlayer <= followDistance)
        {
            isFollowingPlayer = true;

            // 🔹 ATTACCO
            if (canGrab && Time.time > ghostAttack.lastAttackTime + ghostAttack.attackCooldown)
            {
                if (!ghostAnimation.IsBusy)
                {
                    isAttacking = true;
                    agent.isStopped = true;
                    //StartCoroutine(AttackRoutine());
                    ghostAttack.AttackPlayer();
                    return;
                }
            }

            // 🔹 FOLLOW
            isAttacking = false;
            agent.isStopped = false;
            if (!agent.hasPath || agent.destination != player.position)
                agent.SetDestination(player.position);
        }
        else
        {
            isFollowingPlayer = false;
            isAttacking = false;
        }
    }

    private bool IsPlayerBehind()
    {
        if (player == null) return false;

        // vettore dal ghost al player (ignorando Y)
        Vector3 toPlayer = player.position - transform.position;
        toPlayer.y = 0;

        // forward del ghost (ignorando Y)
        Vector3 forward = transform.forward;
        forward.y = 0;

        // calcola l'angolo tra forward e direzione verso il player
        float angleToPlayer = Vector3.Angle(forward, toPlayer);

        // distanza dal player
        float distance = Vector3.Distance(transform.position, player.position);

        // il settore dietro è quello opposto al forward
        // quindi controlliamo se l'angolo rispetto a "dietro" è minore di walkBackAngle
        float angleFromBack = Mathf.Abs(180f - angleToPlayer);

        // 🔹 ritorna true se il player è dentro il settore e vicino abbastanza
        return angleFromBack <= ghostAttack.walkBackAngle && distance <= followDistance;
    }

    private void OnDrawGizmosSelected()
    {
        // Mostra una sfera rossa intorno al Ghost per il raggio di follow
        Gizmos.color = Color.blue;
        Gizmos.DrawWireSphere(transform.position, arrivalThreshold);

    }
}
using ScriptBoy.ProceduralBook;
using System.Collections;
using UnityEngine;

public class GhostController : MonoBehaviour
{
    public GhostMovement movement;
    public GhostAnimation animationController;
    //public float minWaitTime = 1f;
    //public float maxWaitTime = 3f;
    private GhostEvent ghostEvent;
    //private GhostAttack ghostAttack;

    //private bool isWaitingAtPatrol = false;
    //private bool isWalkingBack = false;

    //private bool isFollowingPlayer = false;

    public Transform player;
    public Movement PlayerMovement;

    [Header("Follow / Attack Settings")]
    public float followDistance = 5f;
    public float attackDistance = 2f;
    public float grabDistance = 1.2f; // distanza ravvicinata per grab
    [Range(0f, 180f)]
    public float walkBackAngle = 60f; // angolo dietro per camminata all'indietro

    [Header("WalkBack Settings")]
    public float walkBackDistance = 5f; // distanza massima per walkback


    //private bool isAttacking = false;

    public Camera mainCamera;
    public Transform ghostFacePoint; // empty object sulla faccia del ghost
    public float cameraFocusSpeed = 5f;
    public bool isCameraFocusing = false;

    //private float walkBackEnterDot = -0.5f; // dietro stretto
    //private float walkBackExitDot = -0.2f;  // usciamo dal walkback

    //private bool walkBackActive = false; // true se la camminata all'indietro è in corso
    [SerializeField] private float walkBackTurnSpeed = 6f;
    void Awake()
    {
        //if (movement == null) movement = GetComponent<GhostMovement>();
        //if (animationController == null) animationController = GetComponent<GhostAnimation>();

        //movement.SetNextPatrol();
        //StartWalkRandom();
        //ghostEvent = GetComponent<GhostEvent>();
        //ghostAttack = GetComponent<GhostAttack>();
    }

    public void CameraFocus()
    {
        if (isCameraFocusing && ghostFacePoint != null)
        {
            Vector3 dir = ghostFacePoint.position - mainCamera.transform.position;
            Quaternion rot = Quaternion.LookRotation(dir);

            mainCamera.transform.rotation = Quaternion.Lerp(
                mainCamera.transform.rotation,
                rot,
                Time.deltaTime * cameraFocusSpeed
            );
        }
    }

    private void Start()
    {
        //StartWalkRandom();
    }

    void Update()
    {
        //if (!animationController.IsBusy) // 🔥 BLOCCO TOTALE
        //{
        //    animationController.UpdateMovementAnimation(movement.agent.desiredVelocity.magnitude);
        //}
        //HandlePatrol();
        //HandleWalkBack();
        //HandlePlayerFollow();

        if (isCameraFocusing && ghostFacePoint != null)
        {
            Vector3 dir = ghostFacePoint.position - mainCamera.transform.position;
            Quaternion rot = Quaternion.LookRotation(dir);

            mainCamera.transform.rotation = Quaternion.Lerp(
                mainCamera.transform.rotation,
                rot,
                Time.deltaTime * cameraFocusSpeed
            );
        }
    }

    //private void HandleWalkBack()
    //{
    //    if (player == null) return;

    //    // Direzione verso il player
    //    Vector3 toPlayer = player.position - transform.position;
    //    toPlayer.y = 0;

    //    float distance = toPlayer.magnitude;
    //    if (distance < 0.01f) return;

    //    // Forward del ghost (direzione attuale)
    //    Vector3 forward = transform.forward;
    //    forward.y = 0;

    //    // Se il player è dietro (al di sotto di una certa angolazione), attiviamo il walk-back
    //    if (!walkBackActive && Vector3.Dot(forward, toPlayer.normalized) < -0.5f && distance <= followDistance)
    //    {
    //        walkBackActive = true;
    //        animationController.TriggerWalkBack();
    //        Debug.Log("Walk-back attivato!");
    //    }
    //    else if (walkBackActive && Vector3.Dot(forward, toPlayer.normalized) > -0.1f)
    //    {
    //        walkBackActive = false;
    //        animationController.TriggerWalkForward();
    //        Debug.Log("Walk-back disattivato!");
    //    }

    //    // Se il walk-back è attivo
    //    if (walkBackActive)
    //    {
    //        // Muoviamo il ghost all'indietro
    //        Vector3 backwardDirection = -transform.forward;
    //        transform.position += backwardDirection * movement.agent.speed * Time.deltaTime;

    //        // Ruotiamo il corpo per farlo guardare all'indietro
    //        Quaternion targetRotation = Quaternion.LookRotation(-transform.forward); // Ruotiamo di 180 gradi
    //        transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, Time.deltaTime * walkBackTurnSpeed);

    //        // Debug: Mostra la posizione e la rotazione
    //        Debug.Log($"Walk-back Active: Moving Backwards | Position: {transform.position} | Rotation: {transform.rotation.eulerAngles}");
    //    }
    //    else
    //    {
    //        // Se non è walk-back, ruotiamo verso il player normalmente
    //        Quaternion targetRot = Quaternion.LookRotation(toPlayer);
    //        transform.rotation = Quaternion.Lerp(transform.rotation, targetRot, Time.deltaTime * 5f);

    //        // Debug: Quando il walk-back non è attivo
    //        Debug.Log($"Walk-back Inactive: Normal Rotation | Position: {transform.position} | Rotation: {transform.rotation.eulerAngles}");
    //    }
    //}

    //private void HandlePatrol()
    //{
    //    // 🔹 BLOCCO PATROL SE: 
    //    // 1. Sta seguendo il player
    //    // 2. Sta eseguendo un attacco
    //    // 3. Sta facendo un evento speciale
    //    if (isAttacking || isFollowingPlayer || animationController.IsBusy || animationController.IsPlayingSpecialEvent)
    //        return;

    //    if (!isWaitingAtPatrol && movement.HasReachedDestination())
    //        StartCoroutine(PatrolPointRoutine());
    //}

    //private IEnumerator PatrolPointRoutine()
    //{
    //    isWaitingAtPatrol = true;
    //    movement.agent.isStopped = true;
    //    movement.agent.velocity = Vector3.zero;
    //    animationController.StopWalk();

    //    yield return new WaitForSeconds(Random.Range(minWaitTime, maxWaitTime));

    //    if (isFollowingPlayer)
    //    {
    //        isWaitingAtPatrol = false;
    //        yield break; // 🔥 ESCI SUBITO
    //    }

    //    if (Random.value < 0.7f)
    //        animationController.PlayRandomIdle();
    //    else
    //        animationController.PlayRandomSpecialEvent();

    //    yield return new WaitUntil(() => animationController.IsAnimationFinished());

    //    if (isFollowingPlayer)
    //    {
    //        isWaitingAtPatrol = false;
    //        yield break; // 🔥 ESCI ANCHE QUI
    //    }

    //    animationController.AllowWalk();

    //    movement.SetNextPatrol();
    //    movement.agent.isStopped = false;
    //    StartWalkRandom();

    //    isWaitingAtPatrol = false;
    //}

    //private void StartWalkRandom()
    //{
    //    int walkingType = 0;

    //    // Esempio muro
    //    if (IsNearWall(1f) && Random.value < 0.4f)
    //        walkingType = 1;

    //    animationController.StartWalkSequence(walkingType);
    //}

    private bool IsNearWall(float distance)
    {
        RaycastHit hit;
        Vector3 origin = transform.position + Vector3.up * 0.5f;
        if (Physics.Raycast(origin, transform.forward, out hit, distance))
            if (hit.collider.CompareTag("Wall"))
                return true;
        return false;
    }

    //private void HandlePlayerFollow()
    //{
    //    if (player == null) return;

    //    // 🔹 CALCOLO SE IL PLAYER È DIETRO (ANGOLARE)
    //    bool isBehind = IsPlayerBehind();

    //    // 🔹 ANIMAZIONE WALK-BACK (PRIORITÀ MASSIMA)
    //    if (isBehind)
    //    {
    //        if (!isWalkingBack)
    //        {
    //            isWalkingBack = true;
    //            animationController.TriggerWalkBack();
    //            Debug.Log("Walk-back attivato!");
    //        }
    //    }
    //    else
    //    {
    //        if (isWalkingBack)
    //        {
    //            //MoveBackwardsTowardsPlayer(2); // movimento fisico
    //            isWalkingBack = false;
    //            animationController.TriggerWalkForward();
    //        }
    //    }

    //    // 🔹 SE IL GHOST È IN IDLE O SPECIAL EVENT, NON PUÒ SEGUIRE O ATTACCARE
    //    if (animationController.IsPlayingIdle || animationController.IsPlayingSpecialEvent)
    //    {
    //        movement.agent.isStopped = true;
    //        isFollowingPlayer = false;
    //        return;
    //    }

    //    // 🔹 ATTACCO/FOLLOW NORMALE
    //    float distanceToPlayer = Vector3.Distance(transform.position, player.position);
    //    Vector3 playerFeet = player.GetComponent<Collider>().bounds.min;
    //    float distanceToFeet = Vector3.Distance(transform.position, playerFeet);
    //    bool canGrab = distanceToFeet <= grabDistance;

    //    if (distanceToPlayer <= followDistance)
    //    {
    //        isFollowingPlayer = true;

    //        // 🔹 ATTACCO
    //        if (canGrab && Time.time > ghostAttack.lastAttackTime + ghostAttack.attackCooldown)
    //        {
    //            if (!animationController.IsBusy)
    //            {
    //                isAttacking = true;
    //                movement.agent.isStopped = true;
    //                StartCoroutine(AttackRoutine());
    //                return;
    //            }
    //        }

    //        // 🔹 FOLLOW
    //        isAttacking = false;
    //        movement.agent.isStopped = false;
    //        if (!movement.agent.hasPath || movement.agent.destination != player.position)
    //            movement.agent.SetDestination(player.position);
    //    }
    //    else
    //    {
    //        isFollowingPlayer = false;
    //        isAttacking = false;
    //    }
    //}

    //private IEnumerator AttackRoutine()
    //{
    //    //ghostAttack.lastAttackTime = Time.time;
    //    animationController.IsBusy = true;
    //    isCameraFocusing = true;
    //    mainCamera.fieldOfView = Mathf.Lerp(mainCamera.fieldOfView, 40f, Time.deltaTime * 5f);
    //    int attackType = Random.Range(0, 2);

    //    // 🔥 Aggiungi il sollevamento del ghost quando inizia l'attacco
    //    if (attackType == 0)
    //    {
    //        // Distanziamo e solleviamo il ghost per attacco type 0
    //        yield return StartCoroutine(DistanceAndLiftGhost(0.5f, 0.5f));  // Distanza dal player + alzamento
    //    }
    //    else if (attackType == 1)
    //    {
    //        // Solo distanziamento (per attacco type 1), senza sollevamento, ma abbassiamo leggermente il ghost
    //        yield return StartCoroutine(DistanceAndLowerGhost(1f, -0.2f));  // Distanza dal player + abbassamento
    //    }


    //    // 🔥 PASSA IL TIPO GIUSTO
    //    animationController.PlayAttack(attackType);
    //    ghostEvent.RandomTransform();

    //    yield return StartCoroutine(HoverGhost(0.5f, 0.3f));

    //    if (attackType == 0)
    //        yield return StartCoroutine(DragPlayer());
    //    else
    //        yield return StartCoroutine(LiftPlayer());

    //    yield return new WaitUntil(() => animationController.IsAnimationFinished());

    //    EnablePlayerControl();
    //    ResetPlayerPosition();


    //    movement.agent.isStopped = false;
    //    movement.agent.ResetPath();

    //    animationController.IsBusy = false;
    //    isAttacking = false;
    //    isCameraFocusing = false;
    //    mainCamera.fieldOfView = Mathf.Lerp(mainCamera.fieldOfView, 60f, Time.deltaTime * 5f);
    //    ghostEvent.ResetAllExpressionsSmooth();
    //}

    //private IEnumerator DistanceAndLiftGhost(float distance, float height)
    //{
    //    // Distanziamo il ghost dal player e lo solleviamo
    //    Vector3 startPos = transform.position;
    //    Vector3 targetPos = player.position + transform.forward * distance + Vector3.up * height;

    //    float elapsed = 0f;
    //    float duration = 0.3f;  // Tempo per distanziare e alzare

    //    while (elapsed < duration)
    //    {
    //        elapsed += Time.deltaTime;
    //        transform.position = Vector3.Lerp(startPos, targetPos, elapsed / duration);
    //        yield return null;
    //    }

    //    transform.position = targetPos; // Garantisce che arrivi esattamente alla posizione finale
    //}

    //private IEnumerator DistanceAndLowerGhost(float distance, float height)
    //{
    //    // Distanziamo il ghost dal player e lo abbassiamo leggermente
    //    Vector3 startPos = transform.position;
    //    Vector3 targetPos = player.position + transform.forward * distance + Vector3.up * height;

    //    float elapsed = 0f;
    //    float duration = 0.3f;  // Tempo per distanziare e abbassare

    //    while (elapsed < duration)
    //    {
    //        elapsed += Time.deltaTime;
    //        transform.position = Vector3.Lerp(startPos, targetPos, elapsed / duration);
    //        yield return null;
    //    }

    //    transform.position = targetPos; // Garantisce che arrivi esattamente alla posizione finale
    //}

    //private IEnumerator RaiseGhost(float height)
    //{
    //    Vector3 startPos = transform.position;
    //    Vector3 targetPos = startPos + Vector3.up * height;

    //    float elapsed = 0f;
    //    float duration = 0.3f;  // Tempo per l'alzamento

    //    while (elapsed < duration)
    //    {
    //        elapsed += Time.deltaTime;
    //        transform.position = Vector3.Lerp(startPos, targetPos, elapsed / duration);
    //        yield return null;
    //    }

    //    transform.position = targetPos; // Garantisce che arrivi esattamente alla posizione finale
    //}

    public void ResetPlayerPosition()
    {
        if (!player) return;

        // forza il player a terra
        float groundY = player.GetComponent<CapsuleCollider>().bounds.min.y;

        Vector3 pos = player.position;
        pos.y = groundY;

        player.position = pos;
    }

    //private IEnumerator HoverGhost(float duration, float height)
    //{
    //    Vector3 start = transform.position;
    //    Vector3 target = start + Vector3.up * height;

    //    float time = 0;

    //    while (time < duration)
    //    {
    //        transform.position = Vector3.Lerp(start, target, time / duration);
    //        time += Time.deltaTime;
    //        yield return null;
    //    }

    //    transform.position = target;
    //}

    //private IEnumerator DragPlayer()
    //{
    //    if (!player) yield break;

    //    DisablePlayerControl();

    //    float duration = 1.5f;

    //    // 🔥 OFFSET RAVVICINATO davanti al ghost
    //    float grabDistance = 0.5f; // distanza ravvicinata
    //    Vector3 offset = transform.forward * grabDistance;

    //    // salva altezza del player
    //    float groundY = player.position.y;

    //    float time = 0f;

    //    while (time < duration)
    //    {
    //        // posizione target: vicino al ghost, stessa altezza
    //        Vector3 targetPos = transform.position + offset;
    //        targetPos.y = groundY;

    //        // sposta direttamente il player
    //        player.position = targetPos;

    //        time += Time.deltaTime;
    //        yield return null;
    //    }

    //    EnablePlayerControl();
    //}

    //private IEnumerator LiftPlayer()
    //{
    //    if (!player) yield break;

    //    DisablePlayerControl();

    //    float duration = 1.5f;
    //    float height = 2f;

    //    Vector3 fixedXZ = player.position;
    //    fixedXZ.y = 0;

    //    float startY = player.position.y;
    //    float targetY = startY + height;

    //    float time = 0f;

    //    // SALITA
    //    while (time < duration)
    //    {
    //        float newY = Mathf.Lerp(startY, targetY, time / duration);

    //        Vector3 pos = fixedXZ;
    //        pos.y = newY;

    //        player.position = pos;

    //        time += Time.deltaTime;
    //        yield return null;
    //    }

    //    // 🔥 NON ASPETTIAMO PIÙ L’ANIMAZIONE (BUG FIX)
    //    yield return new WaitForSeconds(0.1f);

    //    // 🔥 FORZA SUBITO A TERRA
    //    float groundY = player.GetComponent<CapsuleCollider>().bounds.min.y;

    //    Vector3 finalPos = player.position;
    //    finalPos.y = groundY;

    //    player.position = finalPos;

    //    EnablePlayerControl();
    //}

    public void DisablePlayerControl()
    {
        if (!player) return;

        var controller = player.GetComponent<CharacterController>();
        if (controller) controller.enabled = false;

        var movement = player.GetComponent<Movement>();
        if (movement) movement.enabled = false;

        var capsuleColl = player.GetComponent<CapsuleCollider>();
        if (capsuleColl) capsuleColl.enabled = false;
    }

    public void EnablePlayerControl()
    {
        if (!player) return;

        var controller = player.GetComponent<CharacterController>();
        if (controller) controller.enabled = true;

        var movement = player.GetComponent<Movement>();
        if (movement) movement.enabled = true;

        var capsuleColl = player.GetComponent<CapsuleCollider>();
        if (capsuleColl) capsuleColl.enabled = true;
    }

    private bool IsPlayerBehind()
    {
        if (player == null) return false;

        // vettore dal ghost al player (ignorando Y)
        Vector3 toPlayer = player.position - transform.position;
        toPlayer.y = 0;

        // forward del ghost (ignorando Y)
        Vector3 forward = transform.forward;
        forward.y = 0;

        // calcola l'angolo tra forward e direzione verso il player
        float angleToPlayer = Vector3.Angle(forward, toPlayer);

        // distanza dal player
        float distance = Vector3.Distance(transform.position, player.position);

        // il settore dietro è quello opposto al forward
        // quindi controlliamo se l'angolo rispetto a "dietro" è minore di walkBackAngle
        float angleFromBack = Mathf.Abs(180f - angleToPlayer);

        // 🔹 ritorna true se il player è dentro il settore e vicino abbastanza
        return angleFromBack <= walkBackAngle && distance <= followDistance;
    }

    private void OnDrawGizmosSelected()
    {
        // Mostra una sfera rossa intorno al Ghost per il raggio di follow
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(transform.position, followDistance);

        // 🟢 Raggio di grab
        Gizmos.color = Color.green;
        Gizmos.DrawWireSphere(transform.position, grabDistance);

        Gizmos.color = Color.black;
        Gizmos.DrawWireSphere(transform.position, attackDistance);

        // 🔵 Settore WalkBack
        Vector3 forward = transform.forward;
        Vector3 origin = transform.position;

        // disegna due linee per delimitare il settore dietro
        Vector3 rightEdge = Quaternion.Euler(0, 180f - walkBackAngle, 0) * forward;
        Vector3 leftEdge = Quaternion.Euler(0, 180f + walkBackAngle, 0) * forward;

        Gizmos.color = Color.blue;
        Gizmos.DrawLine(origin, origin + rightEdge * followDistance);
        Gizmos.DrawLine(origin, origin + leftEdge * followDistance);
    }
}

I wanted to let you know that I solved the problem. You can close it.