using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.BossRoom.Gameplay.GameplayObjects;
using Unity.BossRoom.Gameplay.GameplayObjects.Character;
using Unity.Multiplayer.Samples.BossRoom;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
//using static Codice.Client.Common.WebApi.WebApiEndpoints;

public class AbilitySystem : NetworkBehaviour
{
    [Header("Assigned Abilities")]
    public List<Ability> abilities = new List<Ability>();
    public AbilityUI[] abilitiesUI;

    private Ability activeAbility;
    private bool isAbilityActive = false;
    private HashSet<Ability> abilitiesOnCooldown = new HashSet<Ability>();

    [SerializeField] private GameObject currentAbilityIndicator;
    [SerializeField] private GameObject wallIndicator;
    [SerializeField] private GameObject radiusIndicator;
    [SerializeField] private Material validPlacementMaterial;
    [SerializeField] private Material invalidPlacementMaterial;

    [Header("Wall Placement Settings")]
    [SerializeField] private float wallRotationSpeed = 0.5f;
    [SerializeField] private LayerMask playerLayer; // Layer for detecting players
    [SerializeField] private float mouseMoveThreshold = 0.1f; // Minimum mouse movement threshold

    private Vector3 initialMousePosition;
    private Vector3 wallSpawnPosition;
    private bool isWallPlacementStarted = false;
    private bool isValidPlacement = true;
    NavMeshAgent m_Agent;
    private Dictionary<string, CursorState> abilityCursorMap;

    private void InitializeAbilityCursorMap()
    {
        abilityCursorMap = new Dictionary<string, CursorState>
    {
        { GameDataSource.Instance.DashNCrashAbilityKey, CursorState.Dash },
        { GameDataSource.Instance.FreezeThrowAbilityKey, CursorState.Freeze },
        { GameDataSource.Instance.VectorWallAbilityKey, CursorState.VectorWall }
    };
    }
    private void Awake()
    {
        m_Agent = GetComponent<NavMeshAgent>();
    }

    private void Start()
    {
        abilitiesUI = FindObjectsOfType<AbilityUI>();
        InitializeAbilityCursorMap();
    }

    private void UpdateCursorState(string abilityKey)
    {
        if (abilityCursorMap.TryGetValue(abilityKey, out CursorState cursorState))
        {
            Debug.Log("UpdateCursorState: " + abilityKey);
            GameStateManager.Instance.ChangeState(cursorState);
        }
    }
    void Update()
    {
        HandleAbilityMode();
    }

    private void HandleAbilityMode()
    {
        if (isAbilityActive)
        {
            if (activeAbility.abilityKey == "VectorFence")
            {
                //GameStateManager.Instance.ChangeState(CursorState.VectorWall);
                ManageVectorFenceIndicator();

                if (!isWallPlacementStarted)
                {
                    UpdateWallIndicatorPosition(); // Follow the mouse when ability is activated
                }

                if (Input.GetMouseButtonDown(0))
                {
                    StartWallPlacement();
                }

                if (Input.GetMouseButton(0) && isWallPlacementStarted)
                {
                    RotateWallIndicator(); // Rotate while holding LMB
                }

                if (Input.GetMouseButtonUp(0) && isWallPlacementStarted)
                {
                    UseActiveAbility(); // Place the wall when LMB is released
                    isWallPlacementStarted = false;
                }
            }
            else
            {
                ManageStandardAbilityIndicator();

                if (Input.GetMouseButtonDown(0))
                {
                    UseActiveAbility();
                }
            }
        }
        else
        {

            // GameStateManager.Instance.ChangeState(CursorState.Default);
            DeactivateIndicators();
        }
    }

    private void ManageVectorFenceIndicator()
    {
        if (wallIndicator != null)
        {
            wallIndicator.SetActive(true);
            currentAbilityIndicator.SetActive(false);

            // Apply ability-specific scale to the wall indicator
            if (activeAbility is VectorFenceAbility vectorFence)
            {
                wallIndicator.transform.localScale = new Vector3(vectorFence.wallLength, vectorFence.wallHeight, vectorFence.wallWidth);
            }
        }
    }

    private void UpdateWallIndicatorPosition()
    {
        if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out RaycastHit hit))
        {
            //wallIndicator.transform.position = hit.point; // Update position to follow the mouse
            wallIndicator.transform.position = new Vector3(hit.point.x, 0, hit.point.z);
            isValidPlacement = IsPlacementValid(hit.point, wallIndicator.transform.rotation, playerLayer);
        }
    }

    private void StartWallPlacement()
    {
        if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out RaycastHit hit))
        {
            wallSpawnPosition = new Vector3(hit.point.x, 0, hit.point.z); // Save spawn position
            initialMousePosition = Input.mousePosition; // Store the initial mouse position on click
            isWallPlacementStarted = true;
            Debug.Log($"[AbilitySystem] Wall placement started at {wallSpawnPosition}");

        }
    }
    private void RotateWallIndicator()
    {
        if (isWallPlacementStarted && wallIndicator != null)
        {
            // Get the current mouse position in screen space
            Vector3 currentMousePosition = Input.mousePosition;

            // Calculate the distance the mouse has moved since the initial click
            float mouseDistance = Vector3.Distance(initialMousePosition, currentMousePosition);

            // Check if the movement exceeds the threshold
            if (mouseDistance >= mouseMoveThreshold)
            {
                Ray ray = Camera.main.ScreenPointToRay(currentMousePosition);
                if (Physics.Raycast(ray, out RaycastHit hit))
                {
                    Vector3 direction = (new Vector3(hit.point.x, 0, hit.point.z) - wallIndicator.transform.position).normalized;
                    float angle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
                    angle -= 90f;
                    Quaternion targetRotation = Quaternion.Euler(0f, angle, 0f);

                    wallIndicator.transform.rotation = Quaternion.Lerp(wallIndicator.transform.rotation, targetRotation, 0.5f);
                    isValidPlacement = IsPlacementValid(wallIndicator.transform.position, wallIndicator.transform.rotation, playerLayer);

                }
            }
        }
    }


    private bool IsPlacementValid(Vector3 position, Quaternion rotation, LayerMask layerMask)
    {

        // Perform overlap check after applying rotation
        Vector3 halfExtents = new Vector3(
            wallIndicator.transform.localScale.x / 2f,
            wallIndicator.transform.localScale.y / 2f,
            wallIndicator.transform.localScale.z / 2f
        );
        // Perform a CheckBox for the given parameters
        bool isOverlap = Physics.CheckBox(position, halfExtents, rotation, layerMask);


        return !isOverlap; // Return true if valid placement (no overlap)
    }

    private void ManageStandardAbilityIndicator()
    {
        if (currentAbilityIndicator != null)
        {
            currentAbilityIndicator.SetActive(true);
        }
        if (wallIndicator != null)
        {
            wallIndicator.SetActive(false);
        }
        UpdateIndicatorPosition();
    }

    private void DeactivateIndicators()
    {
        if (currentAbilityIndicator != null) currentAbilityIndicator.SetActive(false);
        if (wallIndicator != null) wallIndicator.SetActive(false);
    }

    public void ActivateAbilityByKey(string key)
    {
        var ability = abilities.FirstOrDefault(a => a.abilityKey == key);
        if (ability == null)
        {
            Debug.LogWarning($"No ability assigned to key {key}.");
            return;
        }

        if (abilitiesOnCooldown.Contains(ability))
        {
            Debug.Log($"{ability.abilityName} is on cooldown.");
        }
        else
        {
            ToggleAbilityMode(ability,key);
        }
    }

    public bool IsAbilityModeActive() => isAbilityActive;

    private void ToggleAbilityMode(Ability ability,string abilitykey)
    {
        if (isAbilityActive && activeAbility == ability)
        {
            DeactivateAbilityMode();
        }
        else
        {
            ActivateAbilityMode(ability);
            UpdateCursorState(abilitykey);
        }
    }

    private void ActivateAbilityMode(Ability ability)
    {
        isAbilityActive = true;
        activeAbility = ability;
        Debug.Log($"Ability {ability.abilityName} activated! Click to use.");
        radiusIndicator.transform.localScale = new Vector3(ability.abilityApplicationRadius * 2, 0, ability.abilityApplicationRadius * 2);
        radiusIndicator.SetActive(true);
    }

    public void DeactivateAbilityMode()
    {
        GameStateManager.Instance.ChangeState(CursorState.Default);
        isAbilityActive = false;
        activeAbility = null;
        isWallPlacementStarted = false;
        radiusIndicator.SetActive(false);
        Debug.Log("Ability mode deactivated.");
    }

    private bool IsPlacementWithinRadius(Vector3 targetPosition)
    {
        float placementRadius = activeAbility.abilityApplicationRadius; // Fetch radius from the active ability
        float distance = Vector3.Distance(transform.position, targetPosition);

        return distance <= placementRadius;
    }


    public void UseActiveAbility()
    {
        if (activeAbility == null)
        {
            Debug.LogWarning("[AbilitySystem] No active ability to use.");
            return;
        }

        GameObject indicator = activeAbility.abilityKey == "VectorFence" ? wallIndicator : currentAbilityIndicator;
        Vector3 targetPosition = indicator.transform.position;
        Vector3 targetRotation = indicator.transform.eulerAngles;

        if (!IsPlacementWithinRadius(targetPosition))
        {
            Debug.Log("[AbilitySystem] Not in Radius.");
            return;
        }
        Debug.Log($"[AbilitySystem] Using active ability {activeAbility.abilityName}.");
        RequestAbilityActivationServerRpc(activeAbility.abilityKey, targetPosition, targetRotation);
        StartCoroutine(StartCooldown(activeAbility));
        DeactivateAbilityMode();
    }

    [ServerRpc(RequireOwnership = false)]
    private void RequestAbilityActivationServerRpc(string abilityKey, Vector3 targetPosition, Vector3 targetRotation, ServerRpcParams rpcParams = default)
    {
        ulong ownerClientId = rpcParams.Receive.SenderClientId;
        Debug.Log($"[AbilitySystem] Received activation request for ability '{abilityKey}' from client {ownerClientId}.");
        ExecuteAbilityOnServer(abilityKey, ownerClientId, targetPosition, targetRotation);
    }

    private void ExecuteAbilityOnServer(string abilityKey, ulong ownerClientId, Vector3 targetPosition, Vector3 targetRotation)
    {
        var playerObject = NetworkManager.Singleton.SpawnManager.SpawnedObjectsList
            .FirstOrDefault(obj => obj.OwnerClientId == ownerClientId && obj.GetComponent<ServerCharacter>());

        if (playerObject == null || !playerObject.TryGetComponent(out ServerCharacter character))
        {
            Debug.LogError($"[AbilitySystem] No ServerCharacter component found for player {ownerClientId}.");
            return;
        }

        var ability = abilities.FirstOrDefault(a => a.abilityKey == abilityKey);
        if (ability == null)
        {
            Debug.LogError($"[AbilitySystem] Ability {abilityKey} not found.");
            return;
        }

        Debug.Log($"[AbilitySystem] Activating ability {ability.abilityName} for player {ownerClientId}.");
        ability.Execute(character, targetPosition, targetRotation);
    }

    private IEnumerator StartCooldown(Ability ability)
    {
        abilitiesOnCooldown.Add(ability);
        Debug.Log($"{ability.abilityName} is now on cooldown for {ability.abilityCooldownTime} seconds.");
        var abilityUI = abilitiesUI.FirstOrDefault(a => a.key == ability.abilityKey);
        abilityUI.StopWatchFiller(ability.abilityCooldownTime);
        yield return new WaitForSeconds(ability.abilityCooldownTime);

        abilitiesOnCooldown.Remove(ability);
        Debug.Log($"{ability.abilityName} is off cooldown.");
    }

    private void UpdateIndicatorPosition()
    {
        if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out RaycastHit hit))
        {
            currentAbilityIndicator.transform.position = new Vector3(hit.point.x, 0, hit.point.z);
            currentAbilityIndicator.transform.localScale = Vector3.one * activeAbility.abilityRadius;
        }
    }
}