using UnityEngine;

/// <summary>
/// DepositBagAction — Navigate to own vault and deposit carried bags.
/// Score increases with more bags carried and when vault is nearby.
/// </summary>
public class DepositBagAction : AIAction
{
    public override string Name => "DepositBag";

    public override float Score(AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.isDead || !bb.isCarrying) return 0f;
        if (bb.myVault == null) return 0f;

        float score = 0.4f; // Base desire to deposit

        // More bags = stronger urge to deposit (risk increases)
        score += bb.carriedBagCount * 0.2f;

        // High value = deposit urgently
        if (bb.totalCarriedValue >= 200f)
            score += 0.15f;

        // Enemies nearby while carrying = deposit NOW
        if (bb.nearbyEnemyCount > 0 && bb.nearestEnemyDistance < 12f)
            score += 0.25f;

        // Low health while carrying = deposit ASAP
        if (bb.healthPercent < 0.4f)
            score += 0.2f;

        // Close to vault = just do it
        float vaultDist = Vector3.Distance(
            bb.myVault.transform.position,
            bb.myVault.transform.position // Will be overridden by brain position
        );

        // Bonus if losing (need to score to catch up)
        if (bb.scoreDifference < -200f)
            score += 0.1f;

        return Mathf.Clamp01(score);
    }

    public override void Execute(AIBrain brain, AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.myVault == null) return;

        brain.NavigateTo(bb.myVault.transform.position);

        // Check if close enough to deposit
        float dist = Vector3.Distance(brain.transform.position, bb.myVault.transform.position);
        if (dist < 3f)
        {
            CashCarrier carrier = brain.GetComponent<CashCarrier>();
            if (carrier != null && carrier.IsCarrying)
            {
                carrier.DepositToVault(bb.myVault);
            }
        }
    }
}

/// <summary>
/// AttackEnemyAction — Engage nearest enemy. Prioritizes bag carriers and low-HP targets.
/// Respects team engagement limits (max 2 AI per enemy).
/// </summary>
public class AttackEnemyAction : AIAction
{
    public override string Name => "AttackEnemy";
    public override bool CanInterrupt => true;

    public override float Score(AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.isDead) return 0f;
        if (bb.nearbyEnemyCount == 0) return 0f;

        float score = 0.35f; // Base aggression

        // Enemy carrier spotted — HIGH priority
        if (bb.nearestEnemyCarrier != null)
        {
            float carrierDist = Vector3.Distance(bb.nearestEnemyCarrier.transform.position,
                bb.myVault != null ? bb.myVault.transform.position : Vector3.zero);
            score += 0.35f;

            // More bags on carrier = more urgent
            score += bb.nearestEnemyCarrier.BagCount * 0.1f;
        }

        // Close enemy = react aggressively
        float proximityFactor = InverseCurve(bb.nearestEnemyDistance, 15f);
        score *= (0.5f + proximityFactor * 0.5f);

        // Outnumber advantage
        if (bb.nearbyAllyCount > bb.nearbyEnemyCount)
            score += 0.1f;

        // Don't be aggressive when low health (unless enemy carrier)
        if (bb.healthPercent < 0.3f && bb.nearestEnemyCarrier == null)
            score *= 0.3f;

        // Carrying bags = less aggressive (protect the payload)
        if (bb.carriedBagCount > 0)
            score *= 0.5f;

        return Mathf.Clamp01(score);
    }

    public override void Execute(AIBrain brain, AIBlackboard bb, TeamBlackboard tb)
    {
        // Choose target: carrier > low HP > nearest
        Transform target = null;
        float bestPriority = float.MinValue;

        for (int i = 0; i < bb.perceivedEnemies.Count; i++)
        {
            PerceivedEntity enemy = bb.perceivedEnemies[i];
            if (enemy.gameObject == null) continue;

            // Skip if too many teammates already targeting
            int engagedCount = tb.GetEnemyTargetCount(enemy.transform);
            if (engagedCount >= 2) continue;

            float priority = 0f;

            // Carrier priority
            if (enemy.isCarryingBag)
                priority += 50f + enemy.carriedBagCount * 20f;

            // Low HP priority
            priority += (1f - enemy.healthPercent) * 30f;

            // Distance priority (closer = higher)
            priority += InverseCurve(enemy.distance, 15f) * 20f;

            // Visible bonus
            if (enemy.isVisible) priority += 10f;

            if (priority > bestPriority)
            {
                bestPriority = priority;
                target = enemy.transform;
            }
        }

        if (target == null) return;

        // Register targeting
        bb.currentTarget = target;
        tb.AddEnemyTarget(target);

        // Delegate combat to CharacterAIController
        brain.EngageTarget(target);
    }

    public override void OnExit(AIBrain brain, AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.currentTarget != null)
            tb.RemoveEnemyTarget(bb.currentTarget);
        bb.currentTarget = null;
    }
}

/// <summary>
/// DefendVaultAction — Rush to own vault when under attack.
/// Highest priority interrupt action.
/// </summary>
public class DefendVaultAction : AIAction
{
    public override string Name => "DefendVault";
    public override bool CanInterrupt => true;

    public override float Score(AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.isDead) return 0f;
        if (!bb.myVaultUnderAttack) return 0f;

        float score = 0.9f; // Very high base — vault defense is critical

        // Closer to vault = we should definitely defend
        if (bb.myVault != null)
        {
            float dist = Vector3.Distance(bb.myVault.transform.position, bb.myVault.transform.position);
            score += InverseCurve(dist, 30f) * 0.1f;
        }

        return Mathf.Clamp01(score);
    }

    public override void Execute(AIBrain brain, AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.myVault == null) return;

        // If carrying, deposit first
        CashCarrier carrier = brain.GetComponent<CashCarrier>();
        float vaultDist = Vector3.Distance(brain.transform.position, bb.myVault.transform.position);

        if (carrier != null && carrier.IsCarrying && vaultDist < 3f)
        {
            carrier.DepositToVault(bb.myVault);
        }

        // Check for enemies near vault
        Transform nearestEnemyAtVault = null;
        float nearestDist = float.MaxValue;

        for (int i = 0; i < bb.perceivedEnemies.Count; i++)
        {
            PerceivedEntity enemy = bb.perceivedEnemies[i];
            if (enemy.gameObject == null) continue;

            float enemyVaultDist = Vector3.Distance(enemy.transform.position, bb.myVault.transform.position);
            if (enemyVaultDist < 10f && enemyVaultDist < nearestDist)
            {
                nearestDist = enemyVaultDist;
                nearestEnemyAtVault = enemy.transform;
            }
        }

        if (nearestEnemyAtVault != null)
        {
            brain.EngageTarget(nearestEnemyAtVault);
        }
        else
        {
            brain.NavigateTo(bb.myVault.transform.position);
        }
    }
}

/// <summary>
/// PatrolAction — Wander randomly via NavMesh when no other objective.
/// Lowest-priority fallback action.
/// </summary>
public class PatrolAction : AIAction
{
    public override string Name => "Patrol";

    private float _pauseEndTime;

    public override float Score(AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.isDead) return 0f;

        // Patrol is the default — returns low score so anything else takes priority
        return 0.1f;
    }

    public override void Execute(AIBrain brain, AIBlackboard bb, TeamBlackboard tb)
    {
        if (Time.time < _pauseEndTime) return;

        if (!bb.hasPatrolDestination || brain.HasReachedDestination())
        {
            if (bb.hasPatrolDestination)
            {
                // Pause at patrol point
                _pauseEndTime = Time.time + Random.Range(1f, 3f);
                bb.hasPatrolDestination = false;
                return;
            }

            // Generate new patrol destination
            Vector3 randomPoint = brain.transform.position + Random.insideUnitSphere * 12f;
            randomPoint.y = brain.transform.position.y;

            UnityEngine.AI.NavMeshHit hit;
            if (UnityEngine.AI.NavMesh.SamplePosition(randomPoint, out hit, 12f, UnityEngine.AI.NavMesh.AllAreas))
            {
                bb.patrolDestination = hit.position;
                bb.hasPatrolDestination = true;
                brain.NavigateTo(bb.patrolDestination);
            }
        }
        else
        {
            brain.NavigateTo(bb.patrolDestination);
        }
    }

    public override void OnExit(AIBrain brain, AIBlackboard bb, TeamBlackboard tb)
    {
        bb.hasPatrolDestination = false;
    }
}

/// <summary>
/// RetreatAction — Fall back to vault when low health.
/// Deposits any carried bags along the way.
/// </summary>
public class RetreatAction : AIAction
{
    public override string Name => "Retreat";
    public override bool CanInterrupt => true;

    public override float Score(AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.isDead) return 0f;

        // Only retreat when health is low
        if (bb.healthPercent > 0.3f) return 0f;

        float score = 0.7f; // High priority when triggered

        // Lower health = more urgent
        score += InverseCurve(bb.healthPercent, 0.3f) * 0.3f;

        // Even more urgent if carrying bags
        if (bb.isCarrying)
            score += 0.1f;

        // Less urgent if no enemies nearby
        if (bb.nearbyEnemyCount == 0)
            score *= 0.6f;

        return Mathf.Clamp01(score);
    }

    public override void Execute(AIBrain brain, AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.myVault == null) return;

        brain.NavigateTo(bb.myVault.transform.position);

        // Deposit if close to vault
        float vaultDist = Vector3.Distance(brain.transform.position, bb.myVault.transform.position);
        if (vaultDist < 3f)
        {
            CashCarrier carrier = brain.GetComponent<CashCarrier>();
            if (carrier != null && carrier.IsCarrying)
                carrier.DepositToVault(bb.myVault);
        }

        // If health recovered, exit retreat
        if (bb.healthPercent > 0.5f)
        {
            // Score will drop, brain will switch naturally
        }
    }
}

/// <summary>
/// EscortCarrierAction — Follow and protect an ally who is carrying bags.
/// Maintains distance, engages threats approaching the carrier.
/// </summary>
public class EscortCarrierAction : AIAction
{
    public override string Name => "EscortCarrier";

    private const float ESCORT_DISTANCE = 4f;
    private const float THREAT_RANGE = 10f;

    public override float Score(AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.isDead) return 0f;
        if (bb.isCarrying) return 0f; // Don't escort if carrying ourselves

        // Need an ally carrier to escort
        if (bb.nearestAllyCarrier == null) return 0f;

        float score = 0.45f;

        // More bags on ally = more valuable to escort
        score += bb.nearestAllyCarrier.BagCount * 0.1f;

        // Enemies near the carrier = escort more important
        float carrierPos = 0;
        for (int i = 0; i < bb.perceivedEnemies.Count; i++)
        {
            float enemyDist = Vector3.Distance(
                bb.perceivedEnemies[i].transform.position,
                bb.nearestAllyCarrier.transform.position);
            if (enemyDist < THREAT_RANGE)
                score += 0.15f;
        }

        // Already close to carrier = maintain escort
        float distToCarrier = Vector3.Distance(bb.nearestAllyCarrier.transform.position, bb.myVault.transform.position);
        if (distToCarrier < ESCORT_DISTANCE * 2f)
            score += 0.1f;

        return Mathf.Clamp01(score);
    }

    public override void Execute(AIBrain brain, AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.nearestAllyCarrier == null) return;

        Vector3 carrierPos = bb.nearestAllyCarrier.transform.position;

        // Check for threats near carrier
        Transform nearestThreat = null;
        float nearestThreatDist = float.MaxValue;

        for (int i = 0; i < bb.perceivedEnemies.Count; i++)
        {
            PerceivedEntity enemy = bb.perceivedEnemies[i];
            float distToCarrier = Vector3.Distance(enemy.transform.position, carrierPos);
            if (distToCarrier < THREAT_RANGE && distToCarrier < nearestThreatDist)
            {
                nearestThreatDist = distToCarrier;
                nearestThreat = enemy.transform;
            }
        }

        if (nearestThreat != null)
        {
            // Engage threat
            brain.EngageTarget(nearestThreat);
        }
        else
        {
            // Follow carrier at distance
            float distToCarrier = Vector3.Distance(brain.transform.position, carrierPos);
            if (distToCarrier > ESCORT_DISTANCE)
            {
                brain.NavigateTo(carrierPos);
            }
            else
            {
                brain.StopNavigation();
            }
        }
    }
}

/// <summary>
/// InterceptCarrierAction — Chase and attack an enemy who is carrying bags.
/// Highest combat priority.
/// </summary>
public class InterceptCarrierAction : AIAction
{
    public override string Name => "InterceptCarrier";
    public override bool CanInterrupt => true;

    public override float Score(AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.isDead) return 0f;
        if (bb.nearestEnemyCarrier == null) return 0f;

        float score = 0.75f; // Very high base priority

        // More bags = more vital to intercept
        score += bb.nearestEnemyCarrier.BagCount * 0.08f;

        // Close to our vault = CRITICAL
        if (bb.myVault != null)
        {
            float carrierToVault = Vector3.Distance(
                bb.nearestEnemyCarrier.transform.position,
                bb.myVault.transform.position);
            if (carrierToVault < 15f)
                score += 0.15f;
        }

        // Low health = less interception
        if (bb.healthPercent < 0.25f)
            score *= 0.4f;

        return Mathf.Clamp01(score);
    }

    public override void Execute(AIBrain brain, AIBlackboard bb, TeamBlackboard tb)
    {
        if (bb.nearestEnemyCarrier == null) return;

        brain.EngageTarget(bb.nearestEnemyCarrier.transform);
    }
}
