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

public class FaceoffManager : MonoBehaviour
{
    [Header("References")]
    [SerializeField] private PuckController puck;

    [Header("Faceoff Spots")]
    [SerializeField] private Transform centerIceFaceoffSpot;
    [SerializeField] private Transform homeZoneLeftFaceoffSpot;
    [SerializeField] private Transform homeZoneRightFaceoffSpot;
    [SerializeField] private Transform awayZoneLeftFaceoffSpot;
    [SerializeField] private Transform awayZoneRightFaceoffSpot;
    [SerializeField] private Transform homeZoneBlueLineLeftFaceoffSpot;
    [SerializeField] private Transform homeZoneBlueLineRightFaceoffSpot;
    [SerializeField] private Transform awayZoneBlueLineLeftFaceoffSpot;
    [SerializeField] private Transform awayZoneBlueLineRightFaceoffSpot;

    private Transform currentFaceoffSpot;

    [Header("Faceoff Settings")]
    [SerializeField] private float faceoffDuration = 2.0f;
    [SerializeField] private float struggleDuration = 3.0f;
    [SerializeField] private float struggleChance = 0.3f;
    [SerializeField] private float winThreshold = 0.7f;

    [Header("Puck Launch Settings")]
    [SerializeField] private float passForce = 8f; // Force to send puck to teammate
    [SerializeField] private float struggleLaunchForce = 5f; // Force when puck is loose

    private PlayerController homeCenterPlayer;
    private PlayerController awayCenterPlayer;
    private List<PlayerController> homeTeam = new List<PlayerController>();
    private List<PlayerController> awayTeam = new List<PlayerController>();

    private bool faceoffInProgress = false;
    private FaceoffOutcome currentOutcome;

    public enum FaceoffOutcome
    {
        None,
        HomeWin,
        AwayWin,
        Struggle
    }

    void Start()
    {
        FindPlayers();
    }

    void FindPlayers()
    {
        PlayerController[] allPlayers = FindObjectsByType<PlayerController>(FindObjectsSortMode.None);

        homeTeam.Clear();
        awayTeam.Clear();

        foreach (var player in allPlayers)
        {
            if (player.CompareTag("HomeTeam"))
            {
                homeTeam.Add(player);
                if (player.stats.position == PlayerPosition.C)
                {
                    homeCenterPlayer = player;
                }
            }
            else if (player.CompareTag("AwayTeam"))
            {
                awayTeam.Add(player);
                if (player.stats.position == PlayerPosition.C)
                {
                    awayCenterPlayer = player;
                }
            }
        }

        Debug.Log($"Found {homeTeam.Count} home players and {awayTeam.Count} away players");
    }

    public void StartFaceoffAt(Transform faceoffSpot)
    {
        if (faceoffSpot == null)
        {
            Debug.LogWarning("Faceoff spot is not assigned!");
            return;
        }

        currentFaceoffSpot = faceoffSpot;
        StartFaceoff();
    }

    public void StartFaceoff()
    {
        if (faceoffInProgress)
        {
            Debug.LogWarning("Faceoff already in progress!");
            return;
        }

        if (currentFaceoffSpot == null)
        {
            currentFaceoffSpot = centerIceFaceoffSpot;
        }

        if (homeCenterPlayer == null || awayCenterPlayer == null)
        {
            Debug.LogError("Missing center players for faceoff!");
            return;
        }

        StartCoroutine(FaceoffSequence());
    }

    private IEnumerator FaceoffSequence()
    {
        faceoffInProgress = true;
        Debug.Log("Faceoff starting...");

        // Position puck at faceoff spot
        if (puck != null && currentFaceoffSpot != null)
        {
            puck.transform.position = currentFaceoffSpot.position + Vector3.up * 0.025f; // Slight lift
            puck.Release(); // Make sure puck is free
        }

        FreezeAllPlayers(true);

        yield return new WaitForSeconds(1.0f);

        currentOutcome = DetermineFaceoffOutcome();
        Debug.Log($"Faceoff outcome: {currentOutcome}");

        yield return new WaitForSeconds(faceoffDuration);

        switch (currentOutcome)
        {
            case FaceoffOutcome.HomeWin:
                ExecuteCleanWin(homeCenterPlayer, homeTeam, awayTeam);
                break;

            case FaceoffOutcome.AwayWin:
                ExecuteCleanWin(awayCenterPlayer, awayTeam, homeTeam);
                break;

            case FaceoffOutcome.Struggle:
                ExecuteStruggle();
                yield return new WaitForSeconds(struggleDuration);
                break;
        }

        FreezeAllPlayers(false);
        faceoffInProgress = false;
        Debug.Log("Faceoff complete!");
    }

    private FaceoffOutcome DetermineFaceoffOutcome()
    {
        if (homeCenterPlayer == null || awayCenterPlayer == null)
            return FaceoffOutcome.Struggle;

        float homeStrength = CalculateFaceoffStrength(homeCenterPlayer);
        float awayStrength = CalculateFaceoffStrength(awayCenterPlayer);

        float totalStrength = homeStrength + awayStrength;
        float homeWinChance = homeStrength / totalStrength;

        if (Mathf.Abs(homeWinChance - 0.5f) < (0.5f - winThreshold))
        {
            return FaceoffOutcome.Struggle;
        }

        float roll = Random.value;
        if (roll < struggleChance)
        {
            return FaceoffOutcome.Struggle;
        }

        return Random.value < homeWinChance ? FaceoffOutcome.HomeWin : FaceoffOutcome.AwayWin;
    }

    private float CalculateFaceoffStrength(PlayerController player)
    {
        return (player.stats.strength * 0.3f) +
               (player.stats.stickHandling * 0.3f) +
               (player.stats.awareness * 0.2f) +
               (player.stats.agility * 0.2f);
    }

    private void ExecuteCleanWin(PlayerController winner, List<PlayerController> winningTeam, List<PlayerController> losingTeam)
    {
        Debug.Log($"{winner.stats.playerName} wins the faceoff cleanly!");

        // Find best pass target FIRST (before assigning puck)
        PlayerController target = ChoosePassTarget(winner, winningTeam);

        if (target != null && target != winner)
        {
            Debug.Log($"Puck sent to {target.stats.playerName} at position {target.transform.position}");

            // Calculate direction from FACEOFF SPOT (not puck position, since puck might be carried)
            Vector3 startPosition = currentFaceoffSpot.position;
            Vector3 targetPosition = target.transform.position;

            // Keep pass flat on the ice (ignore Y difference)
            startPosition.y = 0.025f;
            targetPosition.y = 0.025f;

            Vector3 passDirection = (targetPosition - startPosition).normalized;

            float distance = Vector3.Distance(startPosition, targetPosition);
            float adjustedForce = passForce * Mathf.Clamp(distance / 5f, 0.8f, 2f);

            Debug.Log($"Pass direction: {passDirection}, Distance: {distance:F2}m, Force: {adjustedForce:F2}");

            // Make sure puck is free and at faceoff spot
            if (puck != null)
            {
                puck.Release();

                // Wait one frame to ensure Release() completes
                StartCoroutine(ExecutePassAfterFrame(startPosition, passDirection, adjustedForce, target));
            }
        }
        else
        {
            Debug.Log($"{winner.stats.playerName} keeps the puck!");
            if (puck != null)
            {
                puck.AssignToPlayer(winner);
            }
        }
    }

    private IEnumerator ExecutePassAfterFrame(Vector3 startPosition, Vector3 direction, float force, PlayerController target)
    {
        yield return new WaitForFixedUpdate(); // Wait for physics to settle

        if (puck != null)
        {
            // Position puck at faceoff spot
            puck.transform.position = startPosition;

            // Get rigidbody and zero everything
            Rigidbody puckRb = puck.GetComponent<Rigidbody>();
            if (puckRb != null)
            {
                puckRb.linearVelocity = Vector3.zero;
                puckRb.angularVelocity = Vector3.zero;

                // Apply force in next physics frame
                yield return new WaitForFixedUpdate();
                puckRb.AddForce(direction * force, ForceMode.VelocityChange);

                Debug.Log($"Applied force: {direction * force}");
            }
        }

        // Delay assignment to let puck travel
        StartCoroutine(AssignPuckAfterDelay(target, 0.5f));
    }

    private IEnumerator AssignPuckAfterDelay(PlayerController target, float delay)
    {
        yield return new WaitForSeconds(delay);

        // Check if puck is close enough to target
        if (puck != null && target != null && puck.IsLoose)
        {
            float distance = Vector3.Distance(puck.transform.position, target.transform.position);

            if (distance < 4f) // Increased pickup range further
            {
                // Stop the puck's movement before assigning
                Rigidbody puckRb = puck.GetComponent<Rigidbody>();
                if (puckRb != null)
                {
                    puckRb.linearVelocity = Vector3.zero;
                    puckRb.angularVelocity = Vector3.zero;
                }

                puck.AssignToPlayer(target);
                Debug.Log($"{target.stats.playerName} received the puck!");
            }
            else
            {
                Debug.Log($"Puck too far from {target.stats.playerName} ({distance:F1}m) - Puck at {puck.transform.position}, Target at {target.transform.position}");
            }
        }
    }

    private void ExecuteStruggle()
    {
        Debug.Log("Faceoff is a struggle! Puck is loose!");

        if (puck != null)
        {
            puck.Release();

            // Launch puck in random direction
            Vector3 randomDirection = new Vector3(
                Random.Range(-1f, 1f),
                0.1f, // Slight upward component
                Random.Range(-1f, 1f)
            ).normalized;

            puck.ApplyForce(randomDirection * struggleLaunchForce, ForceMode.Impulse);
        }

        StartCoroutine(ResolveStruggle());
    }

    private IEnumerator ResolveStruggle()
    {
        yield return new WaitForSeconds(struggleDuration * 0.5f);

        // Find closest player to puck
        PlayerController closestPlayer = null;
        float closestDistance = float.MaxValue;

        List<PlayerController> allPlayers = new List<PlayerController>();
        allPlayers.AddRange(homeTeam);
        allPlayers.AddRange(awayTeam);

        foreach (var player in allPlayers)
        {
            float distance = Vector3.Distance(player.transform.position, puck.transform.position);
            if (distance < closestDistance)
            {
                closestDistance = distance;
                closestPlayer = player;
            }
        }

        if (closestPlayer != null && closestDistance < 3f)
        {
            puck.AssignToPlayer(closestPlayer);
            Debug.Log($"{closestPlayer.stats.playerName} gains control after struggle!");
        }
    }

    private PlayerController ChoosePassTarget(PlayerController winner, List<PlayerController> team)
    {
        // Prefer defenders for breakout
        List<PlayerController> defenders = team.Where(p =>
            p != winner && (p.stats.position == PlayerPosition.LD || p.stats.position == PlayerPosition.RD)
        ).ToList();

        if (defenders.Count > 0)
        {
            // Choose closest defender
            return defenders.OrderBy(d =>
                Vector3.Distance(d.transform.position, winner.transform.position)
            ).First();
        }

        // If no defenders, choose any teammate
        List<PlayerController> availableTeammates = team.Where(p => p != winner).ToList();
        if (availableTeammates.Count > 0)
        {
            return availableTeammates[Random.Range(0, availableTeammates.Count)];
        }

        return winner;
    }

    private void FreezeAllPlayers(bool freeze)
    {
        foreach (var player in homeTeam)
        {
            if (player != null)
            {
                player.SetFrozen(freeze);
            }
        }

        foreach (var player in awayTeam)
        {
            if (player != null)
            {
                player.SetFrozen(freeze);
            }
        }
    }

    public void InitiateFaceoff(Vector3 faceoffPosition)
    {
        if (currentFaceoffSpot == null)
        {
            GameObject spot = new GameObject("FaceoffSpot");
            currentFaceoffSpot = spot.transform;
        }

        currentFaceoffSpot.position = faceoffPosition;
        StartFaceoff();
    }

    void Update()
    {
        if (Keyboard.current != null && !faceoffInProgress)
        {
            if (Keyboard.current.fKey.wasPressedThisFrame)
            {
                StartFaceoffAt(centerIceFaceoffSpot);
            }
            else if (Keyboard.current.digit1Key.wasPressedThisFrame)
            {
                StartFaceoffAt(homeZoneLeftFaceoffSpot);
            }
            else if (Keyboard.current.digit2Key.wasPressedThisFrame)
            {
                StartFaceoffAt(homeZoneRightFaceoffSpot);
            }
            else if (Keyboard.current.digit3Key.wasPressedThisFrame)
            {
                StartFaceoffAt(awayZoneLeftFaceoffSpot);
            }
            else if (Keyboard.current.digit4Key.wasPressedThisFrame)
            {
                StartFaceoffAt(awayZoneRightFaceoffSpot);
            }
            else if (Keyboard.current.digit5Key.wasPressedThisFrame)
            {
                StartFaceoffAt(homeZoneBlueLineLeftFaceoffSpot);
            }
            else if (Keyboard.current.digit6Key.wasPressedThisFrame)
            {
                StartFaceoffAt(homeZoneBlueLineRightFaceoffSpot);
            }
            else if (Keyboard.current.digit7Key.wasPressedThisFrame)
            {
                StartFaceoffAt(awayZoneBlueLineLeftFaceoffSpot);
            }
            else if (Keyboard.current.digit8Key.wasPressedThisFrame)
            {
                StartFaceoffAt(awayZoneBlueLineRightFaceoffSpot);
            }
        }
    }
}
