using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Playables;

public class KillerController : MonoBehaviour
{
    [Header("Flow")]
    [SerializeField, Min(0f)] public float startDelay = 60f;
    [SerializeField] private bool stopTimelineOnStart = true;

    [Header("Target")]
    [SerializeField] private Transform target;
    public Transform Target => target;

    [Header("Movement")]
    [SerializeField, Min(0.1f)] private float stoppingDistance = 1.8f;
    [SerializeField, Min(0.05f)] private float repathInterval = 0.25f;
    [SerializeField] private float turnSpeed = 12f;

    [Header("Attack")]
    [SerializeField] private string attackTriggerName = "Attack";
    [SerializeField] private GameObject knife;


    private PlayableDirector director;
    private NavMeshAgent agent;
    private Animator animator;

    private int attackTriggerHash;

    // Flow state
    private float elapsed;
    private bool flowStarted;

    // Runtime
    private float nextAttackTime;
    private float nextRepathTime;
    private bool readyToKill;

    private KillSwitch cachedKillSwitch;

    // Only-once attack
    private bool hasAttacked;

    private void Awake()
    {
        director = GetComponent<PlayableDirector>() ?? GetComponentInParent<PlayableDirector>();
        agent = GetComponent<NavMeshAgent>() ?? GetComponentInParent<NavMeshAgent>();
        animator = GetComponent<Animator>() ?? GetComponentInChildren<Animator>(true);

        attackTriggerHash = Animator.StringToHash(attackTriggerName);

        if (agent != null)
            agent.stoppingDistance = stoppingDistance;

        CacheTarget();

#if UNITY_EDITOR
        if (director == null) Debug.LogWarning($"[{name}] No PlayableDirector found.", this);
        if (agent == null) Debug.LogWarning($"[{name}] No NavMeshAgent found.", this);
        if (animator == null) Debug.LogWarning($"[{name}] No Animator found.", this);
#endif
    }

    private void Update()
    {
        UpdateFlow();
        if (!flowStarted) return;

        UpdateMovementAndAttack();
    }

    // ───────────────── Target API ─────────────────

    public void SetTarget(Transform newTarget)
    {
        target = newTarget;
        CacheTarget();

        // Repath quickly after a target change
        nextRepathTime = 0f;
    }

    private void CacheTarget()
    {
        cachedKillSwitch = target ? target.GetComponent<KillSwitch>() : null;
    }

    // ───────────────── FLOW (delay → timeline stop) ─────────────────

    private void UpdateFlow()
    {
        if (flowStarted) return;

        elapsed += Time.deltaTime;
        if (elapsed < startDelay) return;

        flowStarted = true;

        // 1) Stop timeline so it stops overriding anything
        if (stopTimelineOnStart && director != null)
        {
            director.Stop();
            director.time = 0;
            director.Evaluate();
            director.enabled = false; // hard lock (remove if you need timeline later)
        }

        // 2) Ensure animator has control again
        if (animator != null)
        {
            animator.enabled = true;
            animator.Rebind();
            animator.Update(0f);
        }

        // 3) Allow movement/attack
        if (agent != null)
            agent.isStopped = false;

        readyToKill = true;

#if UNITY_EDITOR
        Debug.Log($"[{name}] Flow started – timeline released", this);
#endif
    }

    // ───────────────── AI ─────────────────

    private void UpdateMovementAndAttack()
    {
        if (target == null || agent == null || !agent.isOnNavMesh) return;

        knife.SetActive(true);

        // Update destination occasionally (cheaper than SetDestination every frame)
        if (Time.time >= nextRepathTime)
        {
            nextRepathTime = Time.time + repathInterval;
            agent.SetDestination(target.position);
        }

        bool inRange =
            !agent.pathPending &&
            agent.remainingDistance <= Mathf.Max(stoppingDistance, agent.stoppingDistance);

        if (inRange)
        {
            agent.isStopped = true;
            FaceTarget();

            if (readyToKill && !hasAttacked)
                TryAttackOnce();
        }
        else
        {
            agent.isStopped = false;
        }

        if (animator != null)
            animator.speed = Mathf.Max(0.01f, agent.velocity.magnitude);
    }

    private void FaceTarget()
    {
        if (target == null) return;

        Vector3 dir = target.position - transform.position;
        dir.y = 0f;

        if (dir.sqrMagnitude < 0.001f) return;

        Quaternion targetRot = Quaternion.LookRotation(dir);
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * turnSpeed);
    }

    private void TryAttackOnce()
    {
        if (animator == null) return;
        if (Time.time < nextAttackTime) return;

        // Mark immediately so we never trigger twice (even if KillSwitch or anim has delay)
        hasAttacked = true;

        animator.SetTrigger(attackTriggerHash);

        // Switch victim from timeline to animator / death
        cachedKillSwitch?.SwitchFromTimelineToAnimator();

        // Optional: stop chasing forever after the hit
        // agent.isStopped = true;
        // enabled = false;
    }

    // ───────────────── API ─────────────────

    public void StartSequence(Transform newTarget = null)
    {
        if (newTarget != null)
            SetTarget(newTarget);

        // Reset flow
        elapsed = 0f;
        flowStarted = false;

        // Reset combat
        readyToKill = false;
        nextAttackTime = 0f;
        nextRepathTime = 0f;
        hasAttacked = false;

        if (agent != null)
            agent.isStopped = true;
    }
}
