using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Centralized animation manager class that handles playing animations
/// and provides an abstraction layer between animation names and animation triggers.
/// </summary>
public class AnimationManager : MonoBehaviour
{
    private Animator animator;
    private Dictionary<string, string> animationMappings = new Dictionary<string, string>();
    
    [SerializeField] private float defaultTransitionDuration = 0.15f; // Default cross fade time
    [SerializeField] private float reactionTransitionDuration = 0.05f; // Faster transition for reactions
    
    // Track the current animation state
    private string currentAnimationName;
    private float hitAlignmentOffset = 0.1f; // Small offset to align hit reactions precisely

    private void Awake()
    {
        animator = GetComponent<Animator>();
        InitializeAnimationMappings();
    }

    /// <summary>
    /// Initialize the mappings between logical animation names and actual animation triggers.
    /// This is where you can update animation names without changing the rest of the codebase.
    /// </summary>
    private void InitializeAnimationMappings()
    {
        // By default, map each animation name to itself
        foreach (var field in typeof(AnimationNames).GetFields())
        {
            if (field.IsLiteral && !field.IsInitOnly)
            {
                string animName = (string)field.GetValue(null);
                animationMappings[animName] = animName;
            }
        }

        // MAP OLD ANIMATIONS TO NEW ANIMATIONS
        
        // ACTIVE ANIMATIONS - These are the only ones that will work
        // Basic Punch Moves - Keep only specified animations
        animationMappings[AnimationNames.Jab] = AnimationNames.Jab;
        animationMappings[AnimationNames.Haymaker] = AnimationNames.Haymaker;
        animationMappings[AnimationNames.SpinningBackfist] = AnimationNames.SpinningBackfist;
        animationMappings[AnimationNames.ElbowSmash] = AnimationNames.ElbowSmash;
        animationMappings[AnimationNames.AirPunch] = AnimationNames.AirPunch;
        
        // Basic Kick Moves - Keep only specified animations
        animationMappings[AnimationNames.LowKick] = AnimationNames.LowKick;
        animationMappings[AnimationNames.BasicKick] = AnimationNames.BasicKick;
        
        // Add SumoSlap from vicious moves to active list
        animationMappings[AnimationNames.SumoSlap] = AnimationNames.SumoSlap;

        // Weapon Animations - active when weapon equipped
        animationMappings[AnimationNames.BatOne] = AnimationNames.BatOne;
        animationMappings[AnimationNames.BatTwo] = AnimationNames.BatTwo;
        animationMappings[AnimationNames.HammerOne] = AnimationNames.HammerOne;
        animationMappings[AnimationNames.HammerTwo] = AnimationNames.HammerTwo;
        // Pickup animation
        animationMappings[AnimationNames.WeaponPickup] = AnimationNames.WeaponPickup;

        // Keep reaction animations for the active moves
        animationMappings[AnimationNames.JabReaction] = AnimationNames.JabReaction;
        animationMappings[AnimationNames.HaymakerReaction] = AnimationNames.HaymakerReaction;
        animationMappings[AnimationNames.SpinningBackfistReaction] = AnimationNames.SpinningBackfistReaction;
        animationMappings[AnimationNames.ElbowSmashReaction] = AnimationNames.ElbowSmashReaction;
        animationMappings[AnimationNames.AirPunchReaction] = AnimationNames.AirPunchReaction;
        animationMappings[AnimationNames.LowKickReaction] = AnimationNames.LowKickReaction;
        animationMappings[AnimationNames.SumoSlapReaction] = AnimationNames.SumoSlapReaction;
        
        // Map Input Actions to Animation Names for active animations
        animationMappings["Punch"] = AnimationNames.Jab;
        animationMappings["Strike"] = AnimationNames.Haymaker;
        animationMappings["Kick"] = AnimationNames.LowKick;
        
        // Direct mappings for active animations
        animationMappings["Jab"] = AnimationNames.Jab;
        animationMappings["Haymaker"] = AnimationNames.Haymaker;
        animationMappings["SpinningBackfist"] = AnimationNames.SpinningBackfist;
        animationMappings["ElbowSmash"] = AnimationNames.ElbowSmash;
        animationMappings["AirPunch"] = AnimationNames.AirPunch;
        animationMappings["LowKick"] = AnimationNames.LowKick;
        animationMappings["BasicKick"] = AnimationNames.BasicKick;
        animationMappings["SumoSlap"] = AnimationNames.SumoSlap;

        // COMMENTED ANIMATIONS - Kept for future implementation
        /*
        // Basic Punch Moves - Map old punches to new animations
        animationMappings[AnimationNames.Right] = AnimationNames.Haymaker;
        animationMappings[AnimationNames.LeftHook] = AnimationNames.Chop;
        animationMappings[AnimationNames.RightHook] = AnimationNames.SpinningBackfist;
        animationMappings[AnimationNames.LeftElbow] = AnimationNames.ElbowSmash;
        animationMappings[AnimationNames.RightElbow] = AnimationNames.ChargePunch;
        animationMappings[AnimationNames.RightBody] = AnimationNames.GroundPound;
        animationMappings[AnimationNames.PowerPunchLeft] = AnimationNames.Uppercut;
        animationMappings[AnimationNames.SupermanPunch] = AnimationNames.AirPunch;
        animationMappings[AnimationNames.SpecialBackfist] = AnimationNames.SpinningBackfist;
        animationMappings[AnimationNames.Chop] = AnimationNames.Chop;
        animationMappings[AnimationNames.GroundPound] = AnimationNames.GroundPound;
        animationMappings[AnimationNames.Uppercut] = AnimationNames.Uppercut;
        
        // Basic Kick Moves - Map old kicks to new animations
        animationMappings[AnimationNames.FrontKickRight] = AnimationNames.DropKick;
        animationMappings[AnimationNames.BodyKickRight] = AnimationNames.AirKick;
        animationMappings[AnimationNames.KneeRight] = AnimationNames.LowKick;
        animationMappings[AnimationNames.BackSideKick] = AnimationNames.Claymore;
        animationMappings[AnimationNames.LegKickRight] = AnimationNames.LowKick;
        animationMappings[AnimationNames.LegPowerKickRight] = AnimationNames.SuperKick;
        animationMappings[AnimationNames.AirKick] = AnimationNames.AirKick;
        animationMappings[AnimationNames.Claymore] = AnimationNames.Claymore;
        animationMappings[AnimationNames.SuperKick] = AnimationNames.SuperKick;
        
        // Hit Reactions - Map old hit reactions to new hit reactions
        animationMappings[AnimationNames.RightHookHitReaction] = AnimationNames.SpinningBackfistReaction;
        animationMappings[AnimationNames.BodyKickHitReaction] = AnimationNames.AirKickReaction;
        animationMappings[AnimationNames.HookHitReaction] = AnimationNames.ChopReaction;
        animationMappings[AnimationNames.JabHitReaction] = AnimationNames.JabReaction;
        animationMappings[AnimationNames.LegKickHitReaction] = AnimationNames.LowKickReaction;
        animationMappings[AnimationNames.UppercutPowerHitReaction] = AnimationNames.HaymakerReaction;
        animationMappings[AnimationNames.OverhandHitReaction] = AnimationNames.GroundPoundReaction;
        animationMappings[AnimationNames.ChopReaction] = AnimationNames.ChopReaction;
        animationMappings[AnimationNames.GroundPoundReaction] = AnimationNames.GroundPoundReaction;
        animationMappings[AnimationNames.AirKickReaction] = AnimationNames.AirKickReaction;
        
        // Jump Moves
        animationMappings["Jump"] = AnimationNames.JumpBack;
        animationMappings[AnimationNames.JumpBack] = AnimationNames.JumpBack;
        animationMappings[AnimationNames.JumpLeft] = AnimationNames.JumpLeft;
        animationMappings[AnimationNames.JumpRight] = AnimationNames.JumpRight;
        
        // Block Moves
        animationMappings[AnimationNames.BlockStepBack] = AnimationNames.BlockStepBack;
        animationMappings[AnimationNames.BlockBodyLeft] = AnimationNames.BlockBodyLeft;
        animationMappings[AnimationNames.BlockLeg] = AnimationNames.BlockLeg;
        animationMappings[AnimationNames.Block] = AnimationNames.Block;
        animationMappings["Block"] = AnimationNames.Block;
        
        // Other movement
        animationMappings["Sprint"] = "Sprint";
        
        // Special Moves and Finishers - Map all special moves from the input system
        animationMappings[AnimationNames.Clothesline] = AnimationNames.Clothesline;
        animationMappings[AnimationNames.Spear] = AnimationNames.Spear;
        animationMappings[AnimationNames.RKO] = AnimationNames.RKO;
        animationMappings[AnimationNames.Claymore] = AnimationNames.Claymore;
        animationMappings[AnimationNames.SuperDDT] = AnimationNames.SuperDDT;
        animationMappings[AnimationNames.RockBottom] = AnimationNames.RockBottom;
        animationMappings[AnimationNames.TroubleInParadise] = AnimationNames.TroubleInParadise;
        animationMappings[AnimationNames.SwantonBomb] = AnimationNames.SwantonBomb;
        animationMappings[AnimationNames.Pedigree] = AnimationNames.Pedigree;
        animationMappings[AnimationNames.GorillaPress] = AnimationNames.GorillaPress;
        animationMappings[AnimationNames.Headbutt] = AnimationNames.Headbutt;
        animationMappings[AnimationNames.KOPunch] = AnimationNames.KOPunch;
        */
    }

    /// <summary>
    /// Play an animation by name, using the mapping to find the actual animation to play.
    /// Uses cross-fade for smooth transitions between animations.
    /// </summary>
    /// <param name="animationName">The logical animation name (from AnimationNames class)</param>
    public void PlayAnimation(string animationName)
    {
        if (animator == null)
        {
            Debug.LogError("Animator component is missing");
            return;
        }
        
        if (!AnimationExists(animationName))
        {
            Debug.LogWarning($"Animation '{animationName}' does not exist in the animator");
            return;
        }

        string mappedAnimation;
        if (animationMappings.TryGetValue(animationName, out mappedAnimation))
        {
            // Store current animation
            currentAnimationName = mappedAnimation;

            // Determine if this is a reaction animation
            bool isReactionAnimation = IsReactionAnimation(mappedAnimation);
            
            // Choose transition duration based on animation type
            float transitionDuration = isReactionAnimation ? reactionTransitionDuration : defaultTransitionDuration;
            
            // Use CrossFade for smoother transitions
            animator.CrossFade(mappedAnimation, transitionDuration, 0, 0);
        }
        else
        {
            // Fallback to playing the animation directly
            animator.CrossFade(animationName, defaultTransitionDuration, 0, 0);
            currentAnimationName = animationName;
            Debug.LogWarning($"No mapping found for animation: {animationName}");
        }
    }

    /// <summary>
    /// Play a reaction animation with proper alignment to the attack.
    /// </summary>
    /// <param name="reactionName">The reaction animation to play</param>
    public void PlayReactionAnimation(string reactionName)
    {
        if (animator == null)
        {
            Debug.LogError("Animator component is missing");
            return;
        }
        
        if (!AnimationExists(reactionName))
        {
            Debug.LogWarning($"Reaction animation '{reactionName}' does not exist in the animator");
            return;
        }

        string mappedReaction;
        if (animationMappings.TryGetValue(reactionName, out mappedReaction))
        {
            // Use a very quick transition for reactions to make them look more impactful
            animator.CrossFade(mappedReaction, reactionTransitionDuration, 0, hitAlignmentOffset);
            currentAnimationName = mappedReaction;
        }
        else
        {
            // Fallback
            animator.CrossFade(reactionName, reactionTransitionDuration, 0, hitAlignmentOffset);
            currentAnimationName = reactionName;
        }
    }

    /// <summary>
    /// Check if an animation exists in the animator controller.
    /// </summary>
    private bool AnimationExists(string animationName)
    {
        if (animator == null)
            return false;
            
        // Get all animation clips from the animator controller
        RuntimeAnimatorController ac = animator.runtimeAnimatorController;
        if (ac == null)
            return false;
            
        AnimationClip[] clips = ac.animationClips;
        foreach (AnimationClip clip in clips)
        {
            if (clip.name == animationName)
                return true;
        }
        
        return false;
    }

    /// <summary>
    /// Checks if the animation is a reaction animation.
    /// </summary>
    private bool IsReactionAnimation(string animationName)
    {
        return animationName.Contains("Reaction") || 
               animationName.Contains("Hit") || 
               animationName.Contains("Stagger") || 
               animationName.Contains("Block");
    }

    /// <summary>
    /// Get the mapped animation name for a logical animation name.
    /// </summary>
    /// <param name="animationName">The logical animation name</param>
    /// <returns>The mapped animation name</returns>
    public string GetMappedAnimationName(string animationName)
    {
        string mappedAnimation;
        if (animationMappings.TryGetValue(animationName, out mappedAnimation))
        {
            return mappedAnimation;
        }
        return animationName; // Fallback to the original animation name
    }

    /// <summary>
    /// Update a specific animation mapping.
    /// </summary>
    /// <param name="logicalName">The logical animation name</param>
    /// <param name="actualAnimationName">The actual animation name to play</param>
    public void UpdateAnimationMapping(string logicalName, string actualAnimationName)
    {
        animationMappings[logicalName] = actualAnimationName;
    }

    /// <summary>
    /// Check if the current animation matches any of the specified animations.
    /// </summary>
    /// <param name="animationNames">Array of animation names to check</param>
    /// <returns>True if the current animation matches any of the specified animations</returns>
    public bool IsPlayingAnimation(params string[] animationNames)
    {
        if (animator == null || animator.GetCurrentAnimatorClipInfo(0).Length == 0)
            return false;
            
        string currentAnimName = animator.GetCurrentAnimatorClipInfo(0)[0].clip.name;
        
        foreach (var animName in animationNames)
        {
            string mappedAnim = GetMappedAnimationName(animName);
            if (currentAnimName == mappedAnim)
                return true;
        }
        
        return false;
    }
}