using UnityEngine;
using System.Linq;

/// <summary>
/// AI-controlled movement for hockey players using physics-based forces.
/// Implements realistic hockey skating with momentum and inertia.
/// </summary>
public class PlayerAIMovement : MonoBehaviour
{
    [Header("Movement Settings")]
    [SerializeField] private float maxSpeed = 8f;
    [SerializeField] private float acceleration = 15f;
    [SerializeField] private float deceleration = 10f;
    [SerializeField] private float turnSpeed = 5f;
    [SerializeField] private float stoppingForce = 20f;

    [Header("AI Behavior Settings")]
    [SerializeField] private MovementSchema movementSchema;
    [SerializeField] private float decisionUpdateInterval = 0.2f;
    [SerializeField] private float minOpponentDistance = 5f;
    [SerializeField] private float passSearchRadius = 20f;
    [SerializeField] private float shootingDistance = 15f;
    [SerializeField] private float interceptionRadius = 2f;

    [Header("Zone Positions")]
    [SerializeField] private float defensiveBlueLineZ = -18f;
    [SerializeField] private float offensiveBlueLineZ = 18f;
    [SerializeField] private float neutralZoneCenter = 0f;

    [Header("Faceoff Control")]
    [Tooltip("Disable AI movement during faceoffs")]
    public bool freezeDuringFaceoff = true;

    private Vector3 targetPosition;
    private Vector3 desiredVelocity;
    private float nextDecisionTime;
    private bool isAIControlled = true;
    private Rigidbody rb;
    private PlayerController playerController;
    private PuckController puck;
    private FaceoffManager faceoffManager;

    public bool IsAIControlled
    {
        get => isAIControlled;
        set => isAIControlled = value;
    }

    void Awake()
    {
        // Get components from same GameObject
        playerController = GetComponent<PlayerController>();
        rb = GetComponent<Rigidbody>();

        // Find puck by tag
        GameObject puckObject = GameObject.FindGameObjectWithTag("Puck");
        if (puckObject != null)
        {
            puck = puckObject.GetComponent<PuckController>();
        }

        // Find faceoff manager
        faceoffManager = FindAnyObjectByType<FaceoffManager>();
    }

    void Start()
    {
        // Set rigidbody constraints for hockey movement
        if (rb != null)
        {
            rb.constraints = RigidbodyConstraints.FreezeRotationX |
                           RigidbodyConstraints.FreezeRotationZ |
                           RigidbodyConstraints.FreezePositionY;
            rb.linearDamping = 1f;
        }
    }

    void Update()
    {
        if (!isAIControlled) return;
        
        // Don't make decisions if frozen (during faceoff)
        if (playerController != null && playerController.IsFrozen())
        {
            return;
        }

        // Don't make decisions if puck is not in play
        if (GameManager.Instance != null && !GameManager.Instance.IsPuckInPlay)
        {
            return;
        }

        // Make decisions periodically
        if (Time.time >= nextDecisionTime)
        {
            MakeMovementDecision();
            nextDecisionTime = Time.time + decisionUpdateInterval;
        }
    }

    void FixedUpdate()
    {
        if (!isAIControlled || rb == null) return;
        
        // Stop movement if frozen (during faceoff)
        if (playerController != null && playerController.IsFrozen())
        {
            rb.linearVelocity = Vector3.zero;
            rb.angularVelocity = Vector3.zero;
            return;
        }

        // Stop movement if puck is not in play
        if (GameManager.Instance != null && !GameManager.Instance.IsPuckInPlay)
        {
            rb.linearVelocity = Vector3.Lerp(rb.linearVelocity, Vector3.zero, deceleration * Time.fixedDeltaTime);
            return;
        }

        ApplyMovementForces();
        ApplyRotation();
    }

    bool IsFaceoffActive()
    {
        // Check if faceoff manager exists and has a faceoff in progress
        // You can also check if players are frozen via FaceoffManager
        if (faceoffManager != null)
        {
            // Access the private field through reflection or add a public property to FaceoffManager
            // For now, we'll assume if faceoffManager exists and players might be frozen
            return false; // Placeholder - you'll need to add public property to FaceoffManager
        }
        return false;
    }

    void MakeMovementDecision()
    {
        if (playerController == null || puck == null) return;

        bool hasPuck = playerController.HasPuck();
        bool teammateHasPuck = IsTeammateCarryingPuck(out PlayerController puckCarrier);
        bool opponentHasPuck = puck.CurrentCarrier != null && IsOpponent(puck.CurrentCarrier);

        if (hasPuck)
        {
            DecideMovementWithPuck();
        }
        else if (teammateHasPuck)
        {
            DecideMovementTeammateHasPuck(puckCarrier);
        }
        else if (opponentHasPuck)
        {
            DecideMovementOpponentHasPuck();
        }
        else
        {
            DecideMovementLoosePuck();
        }
    }

    #region Movement Behaviors

    void DecideMovementWithPuck()
    {
        Vector3 avoidanceVector = CalculateOpponentAvoidance();
        bool inOffensiveZone = IsInOffensiveZone();
        Vector3 goalPosition = GetOpponentGoalPosition();
        float distanceToGoal = Vector3.Distance(transform.position, goalPosition);

        if (inOffensiveZone && distanceToGoal < shootingDistance)
        {
            Vector3 shootingPosition = FindBestShootingPosition();
            targetPosition = shootingPosition + avoidanceVector;
        }
        else
        {
            Vector3 offensiveDirection = (goalPosition - transform.position).normalized;
            targetPosition = transform.position + offensiveDirection * 3f + avoidanceVector;
        }

        float moveDistance = Vector3.Distance(transform.position, targetPosition);
        if (moveDistance > 5f)
        {
            targetPosition = transform.position + (targetPosition - transform.position).normalized * 5f;
        }
    }

    void DecideMovementTeammateHasPuck(PlayerController puckCarrier)
    {
        if (puckCarrier == null) return;

        if (movementSchema == null)
        {
            DefaultTeammateHasPuckBehavior(puckCarrier);
            return;
        }

        bool puckCarrierIsDefender = IsDefender(puckCarrier.stats.position);
        bool thisPlayerIsDefender = IsDefender(playerController.stats.position);

        if (puckCarrierIsDefender && thisPlayerIsDefender)
        {
            targetPosition = FindOpenPassReceivingPosition(puckCarrier);
        }
        else if (!thisPlayerIsDefender)
        {
            targetPosition = FindForwardSupportPosition(puckCarrier);
        }
        else
        {
            DefaultTeammateHasPuckBehavior(puckCarrier);
        }
    }

    void DecideMovementOpponentHasPuck()
    {
        PlayerController opponentWithPuck = puck.CurrentCarrier;
        if (opponentWithPuck == null) return;

        bool isClosest = IsClosestTeammateToOpponent(opponentWithPuck);

        if (isClosest)
        {
            targetPosition = opponentWithPuck.transform.position;
            Vector3 toPuck = (opponentWithPuck.transform.position - transform.position).normalized;
            targetPosition = opponentWithPuck.transform.position - toPuck * interceptionRadius;
        }
        else
        {
            if (IsDefender(playerController.stats.position))
            {
                targetPosition = GetDefensiveFormationPosition(opponentWithPuck);
            }
            else
            {
                targetPosition = GetBackcheckPosition(opponentWithPuck);
            }
        }
    }

    void DecideMovementLoosePuck()
    {
        if (puck == null) return;

        // Only closest player chases loose puck
        PlayerController closestTeammate = GetClosestTeammateToPuck();
        if (closestTeammate == playerController)
        {
            targetPosition = puck.transform.position;
        }
        else
        {
            // Maintain positional structure
            targetPosition = GetDefaultPosition();
        }
    }

    #endregion

    #region Position Finding

    Vector3 CalculateOpponentAvoidance()
    {
        PlayerController[] opponents = FindOpponents();
        Vector3 avoidanceVector = Vector3.zero;

        foreach (PlayerController opponent in opponents)
        {
            float distance = Vector3.Distance(transform.position, opponent.transform.position);

            if (distance < minOpponentDistance)
            {
                Vector3 awayFromOpponent = (transform.position - opponent.transform.position).normalized;
                float strength = 1f - (distance / minOpponentDistance);
                avoidanceVector += awayFromOpponent * strength * 3f;
            }
        }

        return avoidanceVector;
    }

    Vector3 FindBestShootingPosition()
    {
        Vector3 goalPosition = GetOpponentGoalPosition();
        Vector3 directionToGoal = (goalPosition - transform.position).normalized;
        Vector3 slotPosition = goalPosition - directionToGoal * 8f;
        slotPosition.x = Mathf.Clamp(slotPosition.x, -3f, 3f);
        return slotPosition;
    }

    void DefaultTeammateHasPuckBehavior(PlayerController puckCarrier)
    {
        if (IsDefender(playerController.stats.position))
        {
            targetPosition = GetDefensivePosition();
        }
        else
        {
            targetPosition = FindForwardSupportPosition(puckCarrier);
        }
    }

    Vector3 FindOpenPassReceivingPosition(PlayerController passer)
    {
        Vector3 passerPosition = passer.transform.position;
        Vector3 goalDirection = (GetOpponentGoalPosition() - passerPosition).normalized;

        float lateralOffset = (playerController.stats.position == PlayerPosition.LD ||
                              playerController.stats.position == PlayerPosition.LW) ? -4f : 4f;

        Vector3 targetPos = passerPosition + goalDirection * 5f + Vector3.right * lateralOffset;

        float distance = Vector3.Distance(passerPosition, targetPos);
        if (distance > passSearchRadius * 0.7f)
        {
            targetPos = passerPosition + (targetPos - passerPosition).normalized * passSearchRadius * 0.7f;
        }

        return targetPos;
    }

    Vector3 FindForwardSupportPosition(PlayerController puckCarrier)
    {
        if (movementSchema == null) return transform.position;

        Vector3 goalPosition = GetOpponentGoalPosition();
        Vector3 puckPosition = puckCarrier.transform.position;
        Vector3 offensiveDirection = (goalPosition - puckPosition).normalized;

        float lateralSpread = movementSchema.forwardLateralSpread;
        float lateralOffset = 0f;

        switch (playerController.stats.position)
        {
            case PlayerPosition.LW:
                lateralOffset = -lateralSpread;
                break;
            case PlayerPosition.RW:
                lateralOffset = lateralSpread;
                break;
            case PlayerPosition.C:
                lateralOffset = 0f;
                break;
        }

        Vector3 targetPos = puckPosition + offensiveDirection * movementSchema.forwardPushDistance + Vector3.right * lateralOffset;

        if (targetPos.z > offensiveBlueLineZ + 5f)
        {
            targetPos.z = offensiveBlueLineZ + 5f;
        }

        return targetPos;
    }

    Vector3 GetDefensiveFormationPosition(PlayerController opponentWithPuck)
    {
        Vector3 ownGoal = GetOwnGoalPosition();
        Vector3 puckPosition = opponentWithPuck.transform.position;

        PlayerController[] teammates = FindTeammates();
        PlayerController otherDefender = teammates.FirstOrDefault(t =>
            IsDefender(t.stats.position) && t != playerController);

        if (otherDefender != null)
        {
            if (playerController.stats.position == PlayerPosition.LD)
            {
                return new Vector3(-3f, 0f, defensiveBlueLineZ);
            }
            else
            {
                Vector3 targetPos = ownGoal + (puckPosition - ownGoal).normalized * 10f;
                targetPos.x = 3f;
                return targetPos;
            }
        }
        else
        {
            return ownGoal + (puckPosition - ownGoal).normalized * 12f;
        }
    }

    Vector3 GetBackcheckPosition(PlayerController opponentWithPuck)
    {
        Vector3 ownGoal = GetOwnGoalPosition();
        Vector3 puckPosition = opponentWithPuck.transform.position;
        Vector3 targetPos = puckPosition + (ownGoal - puckPosition).normalized * 3f;

        float lateralOffset = 0f;
        switch (playerController.stats.position)
        {
            case PlayerPosition.LW:
                lateralOffset = -4f;
                break;
            case PlayerPosition.RW:
                lateralOffset = 4f;
                break;
        }

        targetPos.x += lateralOffset;
        return targetPos;
    }

    Vector3 GetDefensivePosition()
    {
        float sideOffset = (playerController.stats.position == PlayerPosition.LD) ? -3f : 3f;
        bool isHomeTeam = CompareTag("HomeTeam");
        float zPosition = isHomeTeam ? defensiveBlueLineZ : -defensiveBlueLineZ;

        return new Vector3(sideOffset, 0, zPosition);
    }

    Vector3 GetDefaultPosition()
    {
        // Return a position based on player position and zone
        float xPos = 0f;
        float zPos = 0f;

        switch (playerController.stats.position)
        {
            case PlayerPosition.LW:
                xPos = -6f;
                zPos = offensiveBlueLineZ * 0.5f;
                break;
            case PlayerPosition.RW:
                xPos = 6f;
                zPos = offensiveBlueLineZ * 0.5f;
                break;
            case PlayerPosition.C:
                xPos = 0f;
                zPos = neutralZoneCenter;
                break;
            case PlayerPosition.LD:
                xPos = -3f;
                zPos = defensiveBlueLineZ;
                break;
            case PlayerPosition.RD:
                xPos = 3f;
                zPos = defensiveBlueLineZ;
                break;
        }

        return new Vector3(xPos, 0, zPos);
    }

    #endregion

    #region Physics Movement

    void ApplyMovementForces()
    {
        if (rb == null) return;

        Vector3 currentVelocity = rb.linearVelocity;
        Vector3 directionToTarget = (targetPosition - transform.position).normalized;
        float distanceToTarget = Vector3.Distance(transform.position, targetPosition);

        float desiredSpeed = Mathf.Min(maxSpeed, distanceToTarget * 2f);
        desiredVelocity = directionToTarget * desiredSpeed;

        Vector3 velocityDifference = desiredVelocity - currentVelocity;
        float forceMultiplier = velocityDifference.magnitude > 0.1f ? acceleration : deceleration;

        float currentSpeed = currentVelocity.magnitude;
        float dot = Vector3.Dot(currentVelocity.normalized, directionToTarget);

        if (dot < 0 && currentSpeed > 1f)
        {
            Vector3 stoppingForceVector = -currentVelocity.normalized * stoppingForce;
            rb.AddForce(stoppingForceVector, ForceMode.Acceleration);
        }
        else
        {
            Vector3 force = velocityDifference * forceMultiplier;
            rb.AddForce(force, ForceMode.Acceleration);
        }

        if (rb.linearVelocity.magnitude > maxSpeed)
        {
            rb.linearVelocity = rb.linearVelocity.normalized * maxSpeed;
        }

        if (distanceToTarget < 0.5f && currentSpeed < 1f)
        {
            rb.linearVelocity = Vector3.zero;
        }
    }

    void ApplyRotation()
    {
        if (rb == null) return;

        Vector3 velocity = rb.linearVelocity;

        if (velocity.magnitude > 0.5f)
        {
            Vector3 lookDirection = new Vector3(velocity.x, 0, velocity.z);
            Quaternion targetRotation = Quaternion.LookRotation(lookDirection);

            transform.rotation = Quaternion.Slerp(
                transform.rotation,
                targetRotation,
                turnSpeed * Time.fixedDeltaTime
            );
        }
    }

    #endregion

    #region Helper Methods

    bool IsTeammateCarryingPuck(out PlayerController carrier)
    {
        carrier = puck?.CurrentCarrier;
        if (carrier == null) return false;

        return !IsOpponent(carrier) && carrier != playerController;
    }

    bool IsOpponent(PlayerController other)
    {
        if (other == null || playerController == null) return false;
        return other.CompareTag("HomeTeam") != CompareTag("HomeTeam");
    }

    bool IsDefender(PlayerPosition position)
    {
        return position == PlayerPosition.LD || position == PlayerPosition.RD;
    }

    bool IsInOffensiveZone()
    {
        bool isHomeTeam = CompareTag("HomeTeam");
        return isHomeTeam ? transform.position.z > offensiveBlueLineZ : transform.position.z < -offensiveBlueLineZ;
    }

    Vector3 GetOpponentGoalPosition()
    {
        bool isHomeTeam = CompareTag("HomeTeam");
        return isHomeTeam ? new Vector3(0, 1, 30f) : new Vector3(0, 1, -30f);
    }

    Vector3 GetOwnGoalPosition()
    {
        bool isHomeTeam = CompareTag("HomeTeam");
        return isHomeTeam ? new Vector3(0, 1, -30f) : new Vector3(0, 1, 30f);
    }

    PlayerController[] FindOpponents()
    {
        return FindObjectsByType<PlayerController>(FindObjectsSortMode.None)
            .Where(p => IsOpponent(p))
            .ToArray();
    }

    PlayerController[] FindTeammates()
    {
        return FindObjectsByType<PlayerController>(FindObjectsSortMode.None)
            .Where(p => !IsOpponent(p) && p != playerController)
            .ToArray();
    }

    bool IsClosestTeammateToOpponent(PlayerController opponent)
    {
        PlayerController[] teammates = FindTeammates();
        float myDistance = Vector3.Distance(transform.position, opponent.transform.position);

        foreach (PlayerController teammate in teammates)
        {
            float teammateDistance = Vector3.Distance(teammate.transform.position, opponent.transform.position);
            if (teammateDistance < myDistance)
            {
                return false;
            }
        }

        return true;
    }

    PlayerController GetClosestTeammateToPuck()
    {
        if (puck == null) return playerController;

        PlayerController[] teammates = FindObjectsByType<PlayerController>(FindObjectsSortMode.None)
            .Where(p => !IsOpponent(p))
            .ToArray();

        PlayerController closest = playerController;
        float closestDistance = Vector3.Distance(transform.position, puck.transform.position);

        foreach (PlayerController teammate in teammates)
        {
            float distance = Vector3.Distance(teammate.transform.position, puck.transform.position);
            if (distance < closestDistance)
            {
                closestDistance = distance;
                closest = teammate;
            }
        }

        return closest;
    }

    #endregion

    #region Debug Visualization

    void OnDrawGizmos()
    {
        if (!isAIControlled) return;

        // Draw target position
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(targetPosition, 0.5f);
        Gizmos.DrawLine(transform.position, targetPosition);

        // Draw desired velocity
        Gizmos.color = Color.green;
        Gizmos.DrawRay(transform.position, desiredVelocity);

        // Draw current velocity
        if (rb != null)
        {
            Gizmos.color = Color.blue;
            Gizmos.DrawRay(transform.position, rb.linearVelocity);
        }
    }

    #endregion
}
