using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.BossRoom.Gameplay.GameplayObjects;
using Unity.BossRoom.Gameplay.GameplayObjects.Character;
using Unity.Netcode;
using UnityEngine;

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

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

    [SerializeField] private GameObject currentAbilityIndicator;
    [SerializeField] private GameObject wallIndicator;
    [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;

    void Update()
    {
        HandleAbilityMode();
    }

    private void HandleAbilityMode()
    {
        if (isAbilityActive)
        {
            if (activeAbility.abilityKey == "VectorFence")
            {
                ManageVectorFenceIndicator();

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

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

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

                if (Input.GetMouseButtonUp(0) && isWallPlacementStarted)
                {
                    if (isValidPlacement)
                    {
                        UseActiveAbility(); // Place the wall when LMB is released
                        isWallPlacementStarted = false;
                    }
                    else
                    {
                        Debug.Log("Invalid placement! Cannot place wall on top of another player.");
                    }
                }
            }
            else
            {
                ManageStandardAbilityIndicator();

                if (Input.GetMouseButtonDown(0))
                {
                    UseActiveAbility();
                }
            }
        }
        else
        {
            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
            
            isValidPlacement = IsPlacementValid(hit.point, wallIndicator.transform.rotation, playerLayer);

            var meshRenderer = wallIndicator.GetComponent<MeshRenderer>();
            if (meshRenderer != null)
            {
                meshRenderer.material = isValidPlacement ? validPlacementMaterial : invalidPlacementMaterial;
            }
        }
    }
    
    private void StartWallPlacement()
    {
        if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out RaycastHit hit))
        {
            if (isValidPlacement)
            {
                wallSpawnPosition = hit.point; // Save spawn position
                initialMousePosition = Input.mousePosition; // Store the initial mouse position on click
                isWallPlacementStarted = true;
                Debug.Log($"[AbilitySystem] Wall placement started at {wallSpawnPosition}");
            }
            else
            {
                Debug.Log("Cannot place the wall on top of another player.");
            }
        }
    }

    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 = (hit.point - wallIndicator.transform.position).normalized;
                    float angle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
                    Quaternion targetRotation = Quaternion.Euler(0f, angle, 0f);

                    // Smooth rotation with Lerp
                    // wallIndicator.transform.rotation = targetRotation;
                    wallIndicator.transform.rotation = Quaternion.Lerp(wallIndicator.transform.rotation, targetRotation, Time.deltaTime * wallRotationSpeed);
                    isValidPlacement = IsPlacementValid(wallIndicator.transform.position, wallIndicator.transform.rotation, playerLayer);

                    // Change indicator color based on placement validity
                    var meshRenderer = wallIndicator.GetComponent<MeshRenderer>();
                    if (meshRenderer != null)
                    {
                        meshRenderer.material = isValidPlacement ? validPlacementMaterial : invalidPlacementMaterial;
                    }

                    if (!isValidPlacement)
                    {
                        Debug.Log("Cannot rotate wall here: Overlapping with another object.");
                    }
                }
            }
        }
    }


    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);
        }
    }

    public bool IsAbilityModeActive() => isAbilityActive;

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

    private void ActivateAbilityMode(Ability ability)
    {
        isAbilityActive = true;
        activeAbility = ability;
        Debug.Log($"Ability {ability.abilityName} activated! Click to use.");
    }

    public void DeactivateAbilityMode()
    {
        isAbilityActive = false;
        activeAbility = null;
        isWallPlacementStarted = false;
        Debug.Log("Ability mode deactivated.");
    }

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

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

        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.");

        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 = hit.point;
            currentAbilityIndicator.transform.localScale = Vector3.one * activeAbility.abilityRadius;
        }
    }
}