using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;

namespace Northbound
{
    public class BuildingManager : NetworkBehaviour
    {
        public static BuildingManager Instance { get; private set; }

        [Header("Settings")]
        public float gridSize = 1f;
        public LayerMask groundLayer;

        [Header("Building Database")]
        public List<BuildingData> availableBuildings = new List<BuildingData>();

        private List<Building> placedBuildings = new List<Building>();

        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
                return;
            }
            Instance = this;
        }

        public Vector3 SnapToGrid(Vector3 worldPosition)
        {
            return new Vector3(
                Mathf.Round(worldPosition.x / gridSize) * gridSize,
                worldPosition.y,
                Mathf.Round(worldPosition.z / gridSize) * gridSize
            );
        }

        public Vector3Int WorldToGrid(Vector3 worldPosition)
        {
            return new Vector3Int(
                Mathf.RoundToInt(worldPosition.x / gridSize),
                Mathf.RoundToInt(worldPosition.y / gridSize),
                Mathf.RoundToInt(worldPosition.z / gridSize)
            );
        }

        public Vector3 GridToWorld(Vector3Int gridPosition)
        {
            return new Vector3(
                gridPosition.x * gridSize,
                gridPosition.y * gridSize,
                gridPosition.z * gridSize
            );
        }

        public bool IsValidPlacement(BuildingData data, Vector3 position, int rotation, out Vector3 groundPosition)
        {
            groundPosition = position;

            // Ground check
            if (!CheckGround(position, out groundPosition))
                return false;

            // IMPORTANT: Snap to grid BEFORE checking overlap!
            // Otherwise we check the raw cursor position which might overlap
            Vector3 snappedPosition = SnapToGrid(groundPosition);
            groundPosition = snappedPosition; // Update groundPosition to snapped value

            // Overlap check using GRID SIZE from BuildingData (not actual colliders)
            Vector3 gridSize = data.GetSize(rotation);

            // Shrink bounds slightly to allow buildings to touch without overlapping
            // This prevents Bounds.Intersects() from returning true for adjacent buildings
            Vector3 shrunkSize = gridSize - Vector3.one * 0.01f;
            Bounds checkBounds = new Bounds(snappedPosition + Vector3.up * gridSize.y * 0.5f, shrunkSize);

            foreach (var building in placedBuildings)
            {
                if (building == null) continue;

                // Compare grid bounds, not collider bounds
                Bounds buildingGridBounds = building.GetGridBounds();

                if (checkBounds.Intersects(buildingGridBounds))
                    return false;
            }

            return true;
        }

        /// <summary>
        /// Get the grid bounds for a building at a given position
        /// Useful for preview visualization
        /// </summary>
        public Bounds GetPlacementBounds(BuildingData data, Vector3 position, int rotation)
        {
            Vector3 gridSize = data.GetSize(rotation);
            return new Bounds(position + Vector3.up * gridSize.y * 0.5f, gridSize);
        }

        private bool CheckGround(Vector3 position, out Vector3 groundPosition)
        {
            groundPosition = position;

            // Raycast down to find ground
            if (Physics.Raycast(position + Vector3.up * 10f, Vector3.down, out RaycastHit hit, 20f, groundLayer))
            {
                groundPosition = hit.point;
                return true;
            }

            return false;
        }

        [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
        public void PlaceBuildingServerRpc(int buildingIndex, Vector3 position, int rotation)
        {
            if (buildingIndex < 0 || buildingIndex >= availableBuildings.Count)
                return;

            BuildingData data = availableBuildings[buildingIndex];

            // IsValidPlacement now returns snapped position in groundPosition
            if (!IsValidPlacement(data, position, rotation, out Vector3 snappedPosition))
                return;

            Vector3Int gridPosition = WorldToGrid(snappedPosition);

            // Spawn building at snapped position
            GameObject buildingObj = Instantiate(data.prefab, snappedPosition + data.placementOffset, Quaternion.Euler(0, rotation * 90f, 0));
            NetworkObject netObj = buildingObj.GetComponent<NetworkObject>();

            if (netObj != null)
            {
                netObj.Spawn();

                Building building = buildingObj.GetComponent<Building>();
                if (building == null)
                    building = buildingObj.AddComponent<Building>();

                building.Initialize(data, gridPosition, rotation);
                placedBuildings.Add(building);
            }
        }

        public void RemoveBuilding(Building building)
        {
            if (placedBuildings.Contains(building))
                placedBuildings.Remove(building);
        }
    }
}
