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

public class BuildManager : NetworkBehaviour
{
    public static BuildManager Instance;

    [System.Serializable]
    public struct TurretData
    {
        public string turretName;
        public GameObject finalPrefab;
        public GameObject ghostPrefab;
        public float buildTime;
    }

    [Header("Uniform Grid Settings")]
    public float cellSize = 1f;
    [SerializeField] private float pivotOffset = 0.5f; // 블록/터널 에셋의 중심점

    [Header("Tunnel Settings")]
    public int tunnelLengthInBlocks = 3;

    [Header("Prefabs & Layers")]
    [SerializeField] private GameObject constructionSitePrefab;
    [SerializeField] private List<TurretData> turretLibrary = new List<TurretData>();
    [SerializeField] private LayerMask groundLayer;
    [SerializeField] private LayerMask tunnelLayer;

    private int _selectedTurretIndex = 0;
    private bool _isBuildMode = false;
    private GameObject _ghostInstance;
    private Vector3Int _currentGridPos;
    private PlayerInputActions _inputActions;

    private Dictionary<Vector3Int, TunnelNode> _tunnelRegistry = new Dictionary<Vector3Int, TunnelNode>();
    private HashSet<Vector3Int> _occupiedNodes = new HashSet<Vector3Int>();

    void Awake()
    {
        if (Instance == null) Instance = this;
        else Destroy(gameObject);
        _inputActions = new PlayerInputActions();
    }

    public override void OnNetworkSpawn()
    {
        _inputActions.Player.ToggleBuild.performed += ctx => ToggleBuildMode();
        _inputActions.Player.Build.performed += ctx => OnBuildRequested();
        _inputActions.Player.Cancel.performed += ctx => ExitBuildMode();

        _inputActions.Player.Select1.performed += ctx => SelectTurret(0);
        _inputActions.Player.Select2.performed += ctx => SelectTurret(1);
        _inputActions.Player.Select3.performed += ctx => SelectTurret(2);

        _inputActions.Enable();
    }

    void Update()
    {
        if (!_isBuildMode || _ghostInstance == null) return;
        UpdateGhostPosition();
    }

    private void UpdateGhostPosition()
    {
        Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());

        if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, groundLayer | tunnelLayer))
        {
            Vector3 targetPos;

            // 터널 조준 시: 복잡한 계산 없이 X, Z는 유지, Y만 3 낮춤
            if (((1 << hit.collider.gameObject.layer) & tunnelLayer) != 0)
            {
                Vector3 parentPos = hit.collider.transform.position;
                targetPos = new Vector3(parentPos.x, parentPos.y - (tunnelLengthInBlocks * cellSize), parentPos.z);
            }
            else
            {
                // 지형 조준 시: 격자에 맞춤
                _currentGridPos = WorldToGrid3D(hit.point + hit.normal * 0.01f);
                targetPos = GridToWorld(_currentGridPos);
            }

            _currentGridPos = WorldToGrid3D(targetPos);
            _ghostInstance.transform.position = targetPos;
        }
    }

    // 모든 좌표를 반올림하여 0.5 단위 오차를 제거
    public Vector3Int WorldToGrid3D(Vector3 worldPos)
    {
        return new Vector3Int(
            Mathf.RoundToInt((worldPos.x - pivotOffset) / cellSize),
            Mathf.RoundToInt((worldPos.y - pivotOffset) / cellSize),
            Mathf.RoundToInt((worldPos.z - pivotOffset) / cellSize)
        );
    }

    public Vector3 GridToWorld(Vector3Int gridPos)
    {
        return new Vector3(
            (gridPos.x * cellSize) + pivotOffset,
            (gridPos.y * cellSize) + pivotOffset,
            (gridPos.z * cellSize) + pivotOffset
        );
    }

    // [에러 해결] ConstructionSite.cs 참조용
    public TurretData GetTurretData(int index)
    {
        if (index < 0 || index >= turretLibrary.Count) return default;
        return turretLibrary[index];
    }

    // BuildManager.cs 내 핵심 수정 부분
    // [수정] 서버와 클라이언트 모두에서 터널 위치를 기록하도록 함
    // BuildManager.cs 내부
    public void RegisterTunnel(Vector3Int topPos, TunnelNode node)
    {
        // 터널이 점유하는 Y, Y-1, Y-2 세 칸 모두에 노드를 등록합니다.
        for (int i = 0; i < 3; i++)
        {
            Vector3Int cellPos = topPos + (Vector3Int.down * i);
            if (!_tunnelRegistry.ContainsKey(cellPos))
            {
                _tunnelRegistry.Add(cellPos, node);
            }
        }
    }

    // [수정] 특정 좌표의 터널을 찾는 공용 함수
    public TunnelNode GetTunnelAt(Vector3Int pos)
    {
        return _tunnelRegistry.GetValueOrDefault(pos);
    }

    // 1. 건설 요청 시 실제 계산된 worldPos를 넘겨줍니다.
    private void OnBuildRequested()
    {
        if (!_isBuildMode || EventSystem.current.IsPointerOverGameObject()) return;

        // 고스트가 현재 위치한 '그 좌표'를 그대로 보냅니다.
        RequestBuildRpc(_selectedTurretIndex, _currentGridPos, _ghostInstance.transform.position);
        ExitBuildMode();
    }

    // 2. RPC에서 넘겨받은 worldPos를 사용하여 토대를 생성합니다.
    [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
    private void RequestBuildRpc(int index, Vector3Int gridPos, Vector3 worldPos)
    {
        // GridToWorld를 다시 계산하지 않고 전달받은 worldPos를 그대로 사용합니다.
        GameObject siteObj = Instantiate(constructionSitePrefab, worldPos, Quaternion.identity);
        siteObj.GetComponent<NetworkObject>().Spawn();

        ConstructionSite site = siteObj.GetComponent<ConstructionSite>();
        if (site != null) site.Initialize(index, gridPos);
    }

    public void SelectTurret(int index)
    {
        if (index < 0 || index >= turretLibrary.Count) return;
        _selectedTurretIndex = index;
        if (_isBuildMode && _ghostInstance != null)
        {
            Destroy(_ghostInstance);
            _ghostInstance = Instantiate(turretLibrary[_selectedTurretIndex].ghostPrefab);
        }
    }

    private void ToggleBuildMode() { if (_isBuildMode) ExitBuildMode(); else EnterBuildMode(); }
    private void EnterBuildMode() { _isBuildMode = true; if (turretLibrary.Count > 0) _ghostInstance = Instantiate(turretLibrary[_selectedTurretIndex].ghostPrefab); }
    private void ExitBuildMode() { _isBuildMode = false; if (_ghostInstance) Destroy(_ghostInstance); }
    public override void OnNetworkDespawn() => _inputActions.Disable();
}