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

/// <summary>
/// TeamControlManager - Manages player control switching between team members.
/// Inspired by FRAG Pro Shooter's instant character switching system.
/// </summary>
public class TeamControlManager : MonoBehaviour
{
    public static TeamControlManager Instance { get; private set; }
    
    [Header("Current Control")]
    [SerializeField] private GameObject currentControlledCharacter;
    [SerializeField] private int currentCharacterIndex = 0;
    
    [Header("Team References")]
    [SerializeField] private List<GameObject> playerTeamCharacters = new List<GameObject>();
    
    [Header("Camera Settings")]
    [SerializeField] private bool autoFollowCamera = true;
    
    // Events
    public event System.Action<GameObject, GameObject> OnControlSwitched; // (old, new)
    
    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
    }
    
    /// <summary>
    /// Register a character to the player team
    /// </summary>
    public void RegisterPlayerTeamCharacter(GameObject character, bool isPlayerControlled = false)
    {
        if (!playerTeamCharacters.Contains(character))
        {
            playerTeamCharacters.Add(character);
            DevLog.Log($"[TeamControlManager] Registered {character.name} to player team");
            
            if (isPlayerControlled)
            {
                SetControlledCharacter(character);
            }
        }
    }
    
    /// <summary>
    /// Remove a character from the team (e.g., on death)
    /// </summary>
    public void UnregisterCharacter(GameObject character)
    {
        if (playerTeamCharacters.Contains(character))
        {
            playerTeamCharacters.Remove(character);
            DevLog.Log($"[TeamControlManager] Unregistered {character.name}");
            
            // If this was the controlled character, switch to another
            if (currentControlledCharacter == character)
            {
                SwitchToNextAvailableCharacter();
            }
        }
    }
    
    /// <summary>
    /// Set which character is player-controlled using the unified ControlType system
    /// </summary>
    public void SetControlledCharacter(GameObject newCharacter)
    {
        if (newCharacter == null || newCharacter == currentControlledCharacter) return;
        
        GameObject oldCharacter = currentControlledCharacter;
        
        // Get TeamMember components
        TeamMember oldMember = oldCharacter?.GetComponent<TeamMember>();
        TeamMember newMember = newCharacter.GetComponent<TeamMember>();
        
        // Switch control using ControlType system (handles all component config!)
        if (oldMember != null)
        {
            // Old character becomes PlayerAI (still on player team, but AI controlled)
            oldMember.SetControlType(TeamMember.ControlType.PlayerAI);
            DevLog.Log($"[TeamControlManager] {oldCharacter.name} -> PlayerAI");
        }
        
        if (newMember != null)
        {
            // New character becomes HumanControlled
            newMember.SetControlType(TeamMember.ControlType.HumanControlled);
            DevLog.Log($"[TeamControlManager] {newCharacter.name} -> HumanControlled");
            
            // CRITICAL: Bind input actions for the new controlled character
            BindPlayerInputActions(newCharacter);
        }
        else
        {
            // Fallback for characters without TeamMember (shouldn't happen)
            DevLog.LogWarning($"[TeamControlManager] {newCharacter.name} has no TeamMember component!");
            EnablePlayerControl(newCharacter);
        }
        
        currentControlledCharacter = newCharacter;
        currentCharacterIndex = playerTeamCharacters.IndexOf(newCharacter);
        
        // Update camera using CameraManager (preferred) or legacy UpdateCameraTarget
        if (CameraManager.Instance != null)
        {
            CameraManager.Instance.SetTarget(newMember);
        }
        else if (autoFollowCamera)
        {
            UpdateCameraTarget(newCharacter);
        }
        
        DevLog.Log($"[TeamControlManager] Switched control to {newCharacter.name}");
        OnControlSwitched?.Invoke(oldCharacter, newCharacter);
    }
    
    /// <summary>
    /// Switch to the next character in the team
    /// </summary>
    public void SwitchToNextCharacter()
    {
        if (playerTeamCharacters.Count <= 1) return;
        
        int nextIndex = (currentCharacterIndex + 1) % playerTeamCharacters.Count;
        
        // Find next alive character
        for (int i = 0; i < playerTeamCharacters.Count; i++)
        {
            int checkIndex = (currentCharacterIndex + 1 + i) % playerTeamCharacters.Count;
            GameObject candidate = playerTeamCharacters[checkIndex];
            
            if (candidate != null && candidate.activeInHierarchy && IsCharacterAlive(candidate))
            {
                SetControlledCharacter(candidate);
                return;
            }
        }
        
        DevLog.LogWarning("[TeamControlManager] No other alive characters to switch to!");
    }
    
    /// <summary>
    /// Switch to a specific character by index
    /// </summary>
    public void SwitchToCharacter(int index)
    {
        if (index >= 0 && index < playerTeamCharacters.Count)
        {
            GameObject character = playerTeamCharacters[index];
            if (character != null && character.activeInHierarchy && IsCharacterAlive(character))
            {
                SetControlledCharacter(character);
            }
        }
    }
    
    /// <summary>
    /// Switch to next available character when current dies
    /// </summary>
    private void SwitchToNextAvailableCharacter()
    {
        foreach (var character in playerTeamCharacters)
        {
            if (character != null && character.activeInHierarchy && IsCharacterAlive(character))
            {
                SetControlledCharacter(character);
                return;
            }
        }
        
        Debug.LogError("[TeamControlManager] No available characters to control!");
        currentControlledCharacter = null;
    }
    
    private bool IsCharacterAlive(GameObject character)
    {
        // Check if character has health and is alive
        HealthNew health = character.GetComponent<HealthNew>();
        if (health != null)
        {
            return !health.isDead;
        }
        return true; // Assume alive if no health component
    }
    
    private void EnablePlayerControl(GameObject character)
    {
        // Update TeamMember
        TeamMember teamMember = character.GetComponent<TeamMember>();
        if (teamMember != null)
        {
            teamMember.IsPlayerControlled = true;
        }
        
        // Enable PlayerScript
        PlayerScript playerScript = character.GetComponent<PlayerScript>();
        if (playerScript != null)
        {
            playerScript.enabled = true;
            playerScript.attack = true;
        }
        
        // Enable PlayerInput
        PlayerInput playerInput = character.GetComponent<PlayerInput>();
        if (playerInput != null)
        {
            playerInput.enabled = true;
            try
            {
                playerInput.SwitchCurrentActionMap("Player Controls");
            }
            catch (System.Exception) { }
        }
        
        // Update tag
        character.tag = "Player";
        
        DevLog.Log($"[TeamControlManager] Enabled player control on {character.name}");
    }
    
    private void DisablePlayerControl(GameObject character)
    {
        // Update TeamMember
        TeamMember teamMember = character.GetComponent<TeamMember>();
        if (teamMember != null)
        {
            teamMember.IsPlayerControlled = false;
        }
        
        // Disable PlayerScript (attacks, not movement animation)
        PlayerScript playerScript = character.GetComponent<PlayerScript>();
        if (playerScript != null)
        {
            playerScript.attack = false;
            // Keep enabled for animation but disable input
        }
        
        // Disable PlayerInput
        PlayerInput playerInput = character.GetComponent<PlayerInput>();
        if (playerInput != null)
        {
            playerInput.enabled = false;
        }
        
        DevLog.Log($"[TeamControlManager] Disabled player control on {character.name}");
    }
    
    private void EnableTeamAI(GameObject character)
    {
        TeamAIController aiController = character.GetComponent<TeamAIController>();
        if (aiController != null)
        {
            aiController.enabled = true;
        }
        
        // Also enable CashSystemAI if present
        CashSystemAI cashAI = character.GetComponent<CashSystemAI>();
        if (cashAI != null)
        {
            cashAI.enabled = true;
        }
        
        DevLog.Log($"[TeamControlManager] Enabled AI on {character.name}");
    }
    
    private void DisableTeamAI(GameObject character)
    {
        TeamAIController aiController = character.GetComponent<TeamAIController>();
        if (aiController != null)
        {
            aiController.enabled = false;
        }
        
        // Also disable CashSystemAI if present (player makes own decisions)
        CashSystemAI cashAI = character.GetComponent<CashSystemAI>();
        if (cashAI != null)
        {
            cashAI.enabled = false;
        }
        
        DevLog.Log($"[TeamControlManager] Disabled AI on {character.name}");
    }
    
    private void UpdateCameraTarget(GameObject character)
    {
        // Correct separation: Follow = root (orbit center), LookAt = head (aim point)
        Transform followTarget = character.transform;
        Transform lookAtTarget = FindCharacterHead(character);
        
        // Update Cinemachine FreeLook with correct separation
        Cinemachine.CinemachineFreeLook[] freeLookCameras = FindObjectsOfType<Cinemachine.CinemachineFreeLook>();
        foreach (var cam in freeLookCameras)
        {
            if (cam.gameObject.activeInHierarchy)
            {
                cam.Follow = followTarget;
                cam.LookAt = lookAtTarget;
            }
        }
        
        // Update Cinemachine Virtual Cameras
        Cinemachine.CinemachineVirtualCamera[] virtualCameras = FindObjectsOfType<Cinemachine.CinemachineVirtualCamera>();
        foreach (var cam in virtualCameras)
        {
            if (cam.gameObject.activeInHierarchy)
            {
                cam.Follow = followTarget;
                cam.LookAt = lookAtTarget;
            }
        }
        
        DevLog.Log($"[TeamControlManager] Updated camera to follow {character.name} (Follow=root, LookAt=head)");
    }
    
    private Transform FindCharacterHead(GameObject character)
    {
        string[] headNames = { "Head", "head", "Bip001 Head", "mixamorig:Head", "Bip01 Head" };
        
        foreach (string headName in headNames)
        {
            Transform head = FindChildRecursive(character.transform, headName);
            if (head != null) return head;
        }
        
        // Fallback to character root
        return character.transform;
    }
    
    private Transform FindChildRecursive(Transform parent, string name)
    {
        foreach (Transform child in parent)
        {
            if (child.name == name) return child;
            Transform found = FindChildRecursive(child, name);
            if (found != null) return found;
        }
        return null;
    }
    
    /// <summary>
    /// Get the currently controlled character
    /// </summary>
    public GameObject GetCurrentControlledCharacter() => currentControlledCharacter;
    
    /// <summary>
    /// Get all player team characters
    /// </summary>
    public List<GameObject> GetPlayerTeamCharacters() => playerTeamCharacters;
    
    /// <summary>
    /// Clear all registered characters
    /// </summary>
    public void ClearTeam()
    {
        playerTeamCharacters.Clear();
        currentControlledCharacter = null;
        currentCharacterIndex = 0;
    }
    
    /// <summary>
    /// Bind input action callbacks to PlayerScript methods.
    /// This mirrors what Practice mode does in SelectionOptions.SetUpPlayerInputAI.
    /// </summary>
    private void BindPlayerInputActions(GameObject character)
    {
        PlayerInput playerInput = character.GetComponent<PlayerInput>();
        PlayerScript playerScript = character.GetComponent<PlayerScript>();
        
        if (playerInput == null || playerScript == null)
        {
            DevLog.LogWarning($"[TeamControlManager] Cannot bind input - PlayerInput: {playerInput != null}, PlayerScript: {playerScript != null}");
            return;
        }
        
        // Ensure PlayerInput is enabled
        playerInput.enabled = true;
        try { playerInput.SwitchCurrentActionMap("Player Controls"); } catch { }
        
        var actionMap = playerInput.currentActionMap;
        if (actionMap == null)
        {
            Debug.LogError("[TeamControlManager] No current action map found!");
            return;
        }
        
        // CRITICAL: Bind the Move action!
        TryBindAction(actionMap, "Move", playerScript.OnMove);
        
        // Bind attack actions
        TryBindAction(actionMap, "Jab", playerScript.OnJab);
        TryBindAction(actionMap, "Right", playerScript.OnRight);
        TryBindAction(actionMap, "LeftHook", playerScript.OnLeftHook);
        TryBindAction(actionMap, "RightHook", playerScript.OnRightHook);
        TryBindAction(actionMap, "LeftElbow", playerScript.OnLeftElbow);
        TryBindAction(actionMap, "RightElbow", playerScript.OnRightElbow);
        TryBindAction(actionMap, "RightBody", playerScript.OnRightBody);
        TryBindAction(actionMap, "PowerPunchLeft", playerScript.OnPowerPunchLeft);
        TryBindAction(actionMap, "SupermanPunch", playerScript.OnSupermanPunch);
        
        // Kick actions
        TryBindAction(actionMap, "LegKickRight", playerScript.OnLegKickRight);
        TryBindAction(actionMap, "BodyKickRight", playerScript.OnBodyKickRight);
        TryBindAction(actionMap, "KneeRight", playerScript.OnKneeRight);
        TryBindAction(actionMap, "BackSideKick", playerScript.OnBackSideKick);
        TryBindAction(actionMap, "FrontKickRight", playerScript.OnFrontKickRight);
        TryBindAction(actionMap, "LegPowerKickRight", playerScript.OnLegPowerKickRight);
        
        // Dodge actions
        TryBindAction(actionMap, "JumpBack", playerScript.OnJumpBack);
        TryBindAction(actionMap, "JumpLeft", playerScript.OnJumpLeft);
        TryBindAction(actionMap, "JumpRight", playerScript.OnJumpRight);
        
        // Block actions
        TryBindAction(actionMap, "BlockStepBack", playerScript.OnBlockStepBack);
        TryBindAction(actionMap, "BlockBodyLeft", playerScript.OnBlockBodyLeft);
        TryBindAction(actionMap, "BlockLeg", playerScript.OnBlockLeg);
        
        // Special attacks
        TryBindAction(actionMap, "Chokeslam", playerScript.OnChokeslam);
        TryBindAction(actionMap, "Suplex", playerScript.OnSuplex);
        TryBindAction(actionMap, "GiantSwing", playerScript.OnGiantSwing);
        TryBindAction(actionMap, "DiamondCrusher", playerScript.OnDiamondCrusher);
        TryBindAction(actionMap, "SumoSlap", playerScript.OnSumoSlap);
        TryBindAction(actionMap, "JavelinTackle", playerScript.OnJavelinTackle);
        TryBindAction(actionMap, "RKO", playerScript.OnRKO);
        TryBindAction(actionMap, "Spear", playerScript.OnSpear);
        TryBindAction(actionMap, "RockBottom", playerScript.OnRockBottom);
        TryBindAction(actionMap, "F5", playerScript.OnF5);
        
        DevLog.Log($"[TeamControlManager] Input actions bound for {character.name}");
    }
    
    /// <summary>
    /// Helper to safely bind an action
    /// </summary>
    private void TryBindAction(InputActionMap actionMap, string actionName, System.Action<InputAction.CallbackContext> callback)
    {
        InputAction action = actionMap.FindAction(actionName);
        if (action != null)
        {
            action.performed += callback;
            if (actionName == "Move") action.canceled += callback;
        }
    }
}
