using AceFieldNewHorizon.Scripts.Tiles;
using Godot;

namespace AceFieldNewHorizon.Scripts.System;

public partial class PlacementManager : Node2D
{
    [Export] public GridManager Grid { get; set; }
    [Export] public BuildingRegistry Registry { get; set; }

    private string _currentBuildingId = "miner";

    private Vector2I _hoveredCell;
    private BaseTile _ghostBuilding;
    
    public void SetCurrentBuilding(string buildingId)
    {
        _currentBuildingId = buildingId;

        // Replace ghost immediately
        if (_ghostBuilding == null) return;
        _ghostBuilding.QueueFree();
        _ghostBuilding = null;
    }

    public override void _Process(double delta)
    {
        // Snap mouse to grid
        var mousePos = GetGlobalMousePosition();
        _hoveredCell = GridUtils.WorldToGrid(mousePos);

        if (_ghostBuilding == null)
        {
            var scene = Registry.GetBuilding(_currentBuildingId)?.Scene;
            if (scene == null) return;
            
            _ghostBuilding = (BaseTile)scene.Instantiate();
            _ghostBuilding.SetGhostMode(true);
            AddChild(_ghostBuilding);
        }

        var placementPos = GridUtils.GridToWorld(_hoveredCell);
        var spaceState = GetWorld2D().DirectSpaceState;
        var centerPos = placementPos + new Vector2(GridUtils.TileSize / 2f, GridUtils.TileSize / 2f);

        var query = new PhysicsPointQueryParameters2D
        {
            Position = centerPos,
            CollideWithBodies = true,
            CollideWithAreas = true,
            CollisionMask = uint.MaxValue // check against all layers/masks
            // Exclude = new Godot.Collections.Array<Rid>() // optional, see below
        };

        var collision = spaceState.IntersectPoint(query, 8);
        var canPlace = Grid.IsCellFree(_hoveredCell) && collision.Count == 0;

        _ghostBuilding.Position = placementPos;
        _ghostBuilding.SetGhostMode(canPlace);

        // Left click to place
        if (Input.IsActionPressed("build_tile") && canPlace)
        {
            var scene = Registry.GetBuilding(_currentBuildingId)?.Scene;
            if (scene == null) return;
            
            _ghostBuilding.FinalizePlacement();

            var buildingData = Registry.GetBuilding(_currentBuildingId);
            Grid.OccupyCell(_hoveredCell, _ghostBuilding);

            if (buildingData is { BuildTime: > 0f })
                _ghostBuilding.StartConstruction(buildingData.BuildTime);

            _ghostBuilding = (BaseTile)scene.Instantiate();
            _ghostBuilding.SetGhostMode(true);
            AddChild(_ghostBuilding);
        }

        if (Input.IsActionPressed("destroy_tile") && !Grid.IsCellFree(_hoveredCell))
        {
            // Right click to destroy
            var building = Grid.GetBuildingAtCell(_hoveredCell);
            if (building == null) return;
            building.QueueFree();
            Grid.FreeCell(_hoveredCell);
        }
    }
}