using UnityEngine;
using UnityEngine.AI;

/// <summary>
/// AIBrain — Central AI orchestrator. Replaces CashSystemAI.
/// Runs perception → utility scoring → action execution on a configurable tick.
/// 
/// Features:
/// - AI LOD (distance-based tick scaling)
/// - Zero FindObjectOfType calls
/// - Modular scoring via UtilityScorer
/// - Delegates combat to existing CharacterAIController
/// - Delegates navigation to AINavigationHelper
/// 
/// Attach to all AI characters (both player-team AI and enemy-team AI).
/// </summary>
public class AIBrain : MonoBehaviour
{
    [Header("AI Settings")]
    [SerializeField] private UtilityScorer.AIRole role = UtilityScorer.AIRole.Balanced;
    [SerializeField] private bool autoAssignRole = true;

    [Header("Tick Rate (AI LOD)")]
    [SerializeField] private float baseTick = 0.3f;           // Tier 0: on-screen, close
    [SerializeField] private float midTick = 0.5f;            // Tier 1: on-screen, far
    [SerializeField] private float farTick = 1.0f;            // Tier 2: off-screen
    [SerializeField] private float lodMidDistance = 15f;
    [SerializeField] private float lodFarDistance = 30f;

    [Header("Behavior")]
    [SerializeField] private float minActionDuration = 1.5f;   // Minimum time before switching actions

    // ─── Components ──────────────────────────────────────────
    private AIPerceptionSystem _perception;
    private AINavigationHelper _navigation;
    private CharacterAIController _aiController;
    private CashCarrier _carrier;
    private HealthNew _health;
    private TeamMember _teamMember;

    // ─── AI State ────────────────────────────────────────────
    private AIBlackboard _blackboard;
    private TeamBlackboard _teamBlackboard;
    private UtilityScorer _scorer;
    private AIAction _currentAction;
    private float _lastTickTime;
    private float _currentTick;
    private Transform _mainCamera;
    private bool _combatEnabled;

    // ─── Properties ──────────────────────────────────────────
    public AIBlackboard Blackboard => _blackboard;
    public AIAction CurrentAction => _currentAction;
    public UtilityScorer.AIRole Role => role;
    public string CurrentActionName => _scorer?.CurrentActionName ?? "Initializing";

    // ─── Lifecycle ───────────────────────────────────────────

    private void Awake()
    {
        // Ensure components exist
        _perception = GetComponent<AIPerceptionSystem>();
        if (_perception == null) _perception = gameObject.AddComponent<AIPerceptionSystem>();

        _navigation = GetComponent<AINavigationHelper>();
        if (_navigation == null) _navigation = gameObject.AddComponent<AINavigationHelper>();
    }

    private void Start()
    {
        if (SelectionOptions.Instance == null || !SelectionOptions.Instance.isCashSystemSelected)
        {
            enabled = false;
            return;
        }

        // Cache components
        _aiController = GetComponent<CharacterAIController>();
        _carrier = GetComponent<CashCarrier>();
        _health = GetComponent<HealthNew>();
        _teamMember = GetComponent<TeamMember>();

        // Find camera for LOD
        if (Camera.main != null)
            _mainCamera = Camera.main.transform;

        // Initialize blackboard
        _blackboard = new AIBlackboard();
        _blackboard.teamTag = gameObject.tag;
        _blackboard.team = _teamMember != null ? _teamMember.CurrentTeam : TeamMember.Team.EnemyTeam;

        // Initialize perception
        _perception.Initialize(_blackboard.teamTag);

        // Find vaults (one-time, cached)
        FindVaults();

        // Auto-assign role
        if (autoAssignRole)
            AssignRandomRole();

        // Initialize scorer
        _scorer = new UtilityScorer(role);

        // Get team blackboard
        _teamBlackboard = TeamBlackboard.Get(_blackboard.teamTag);

        _currentTick = baseTick;

        // Subscribe to events
        GameEvents.OnCombatEnabled += OnCombatEnabled;
        GameEvents.OnVaultUnderAttack += OnVaultAttacked;
        GameEvents.OnMatchEnd += OnMatchEnd;
    }

    private void OnDestroy()
    {
        GameEvents.OnCombatEnabled -= OnCombatEnabled;
        GameEvents.OnVaultUnderAttack -= OnVaultAttacked;
        GameEvents.OnMatchEnd -= OnMatchEnd;

        // Release claims
        _teamBlackboard?.ReleaseBagClaim(this);
    }

    private void Update()
    {
        if (!_combatEnabled) return;
        if (_health != null && _health.isDead) return;

        // AI LOD — adjust tick rate based on distance to camera
        UpdateAILOD();

        // Tick check
        if (Time.time - _lastTickTime < _currentTick) return;
        _lastTickTime = Time.time;

        // 1. Update self state on blackboard
        UpdateSelfState();

        // 2. Run perception
        _perception.UpdatePerception(_blackboard);

        // 3. Update team state
        UpdateTeamState();

        // 4. Score and select action
        AIAction bestAction = _scorer.Evaluate(this, _blackboard, _teamBlackboard);

        // 5. Execute action
        if (bestAction != null)
        {
            _currentAction = bestAction;
            _currentAction.Execute(this, _blackboard, _teamBlackboard);
        }
    }

    // ─── State Updates ───────────────────────────────────────

    private void UpdateSelfState()
    {
        if (_health != null)
        {
            _blackboard.currentHealth = _health.currentHealth;
            _blackboard.maxHealth = _health.maxHealth;
            _blackboard.healthPercent = _health.maxHealth > 0 ? _health.currentHealth / _health.maxHealth : 1f;
            _blackboard.isDead = _health.isDead;
        }

        if (_carrier != null)
        {
            _blackboard.carriedBagCount = _carrier.BagCount;
            _blackboard.totalCarriedValue = _carrier.TotalValue;
            _blackboard.isCarrying = _carrier.IsCarrying;
        }
    }

    private void UpdateTeamState()
    {
        if (_teamBlackboard != null)
        {
            _blackboard.myVaultUnderAttack = _teamBlackboard.vaultUnderAttack;
            _blackboard.myTeamScore = _teamBlackboard.teamScore;
        }

        // Get enemy team score
        string enemyTag = _blackboard.teamTag == "Player" ? "Enemy" : "Player";
        TeamBlackboard enemyBoard = TeamBlackboard.Get(enemyTag);
        if (enemyBoard != null)
        {
            _blackboard.enemyTeamScore = enemyBoard.teamScore;
        }

        _blackboard.scoreDifference = _blackboard.myTeamScore - _blackboard.enemyTeamScore;
    }

    private void UpdateAILOD()
    {
        if (_mainCamera == null)
        {
            _currentTick = baseTick;
            return;
        }

        float distToCamera = Vector3.Distance(transform.position, _mainCamera.position);

        if (distToCamera > lodFarDistance)
            _currentTick = farTick;
        else if (distToCamera > lodMidDistance)
            _currentTick = midTick;
        else
            _currentTick = baseTick;
    }

    private void FindVaults()
    {
        var vaults = EntityRegistry<TeamVault>.All;
        for (int i = 0; i < vaults.Count; i++)
        {
            if (vaults[i] == null) continue;
            if (vaults[i].TeamTag == _blackboard.teamTag)
                _blackboard.myVault = vaults[i];
            else
                _blackboard.enemyVault = vaults[i];
        }

        // Fallback to FindObjectsOfType (only at initialization)
        if (_blackboard.myVault == null || _blackboard.enemyVault == null)
        {
            TeamVault[] allVaults = FindObjectsOfType<TeamVault>();
            foreach (var vault in allVaults)
            {
                if (vault.TeamTag == _blackboard.teamTag)
                    _blackboard.myVault = vault;
                else
                    _blackboard.enemyVault = vault;
            }
        }
    }

    private void AssignRandomRole()
    {
        float rand = Random.value;
        if (rand < 0.35f) role = UtilityScorer.AIRole.Balanced;
        else if (rand < 0.60f) role = UtilityScorer.AIRole.Collector;
        else if (rand < 0.80f) role = UtilityScorer.AIRole.Defender;
        else role = UtilityScorer.AIRole.Aggressor;
    }

    // ─── Public API (called by AIActions) ────────────────────

    /// <summary>Navigate to a world position.</summary>
    public void NavigateTo(Vector3 position)
    {
        _navigation.SetDestination(position);
    }

    /// <summary>Stop all navigation.</summary>
    public void StopNavigation()
    {
        _navigation.Stop();
    }

    /// <summary>Has the AI reached its current navigation destination?</summary>
    public bool HasReachedDestination()
    {
        return _navigation.HasReachedDestination();
    }

    /// <summary>Engage a target in combat (delegates to CharacterAIController).</summary>
    public void EngageTarget(Transform target)
    {
        if (_aiController != null)
        {
            _aiController.SetTarget(target.gameObject);
            _aiController.NavigateTo(target.position);
            _aiController.attack = true;
        }
        else
        {
            // Fallback: just navigate toward
            NavigateTo(target.position);
        }
    }

    /// <summary>Disengage from combat.</summary>
    public void DisengageTarget()
    {
        if (_aiController != null)
        {
            _aiController.Stop();
        }
    }

    // ─── Event Handlers ──────────────────────────────────────

    private void OnCombatEnabled(bool enabled)
    {
        _combatEnabled = enabled;
    }

    private void OnVaultAttacked(TeamVault vault)
    {
        if (vault.TeamTag == _blackboard.teamTag)
        {
            _blackboard.myVaultUnderAttack = true;
            if (_teamBlackboard != null)
                _teamBlackboard.vaultUnderAttack = true;

            // Force immediate decision (bypass tick timer)
            _lastTickTime = 0;
        }
    }

    private void OnMatchEnd(string winnerTag)
    {
        _combatEnabled = false;
        StopNavigation();
    }

    // ─── Debug ───────────────────────────────────────────────

#if UNITY_EDITOR
    private void OnDrawGizmosSelected()
    {
        if (_blackboard == null) return;

        // Show current action
        UnityEditor.Handles.Label(transform.position + Vector3.up * 2.5f,
            $"AI: {CurrentActionName}\n" +
            $"Role: {role}\n" +
            $"HP: {_blackboard.healthPercent:P0}\n" +
            $"Bags: {_blackboard.carriedBagCount}\n" +
            $"Enemies: {_blackboard.nearbyEnemyCount}\n" +
            $"Tick: {_currentTick:F2}s");

        // Show target
        if (_blackboard.currentTarget != null)
        {
            Gizmos.color = Color.red;
            Gizmos.DrawLine(transform.position + Vector3.up, _blackboard.currentTarget.position + Vector3.up);
        }

        // Show target bag
        if (_blackboard.targetBag != null)
        {
            Gizmos.color = Color.yellow;
            Gizmos.DrawLine(transform.position + Vector3.up, _blackboard.targetBag.transform.position);
        }
    }
#endif
}
