namespace splat;

using Godot;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// Tracks every placed building and drives decay scheduling per the core
/// gameplay loop (fighting entropy). Decay is applied as structural integrity
/// loss scaled by each building's material decay rate and elapsed in-game days.
/// </summary>
public partial class BuildingManager : Node
{
    [Export] public NodePath GameManagerPath { get; set; } = new("../GameManager");

    private readonly List<Building> _buildings = new();
    private GameManager? _gameManager;

    /// <summary>Emitted whenever a building under management collapses.</summary>
    [Signal] public delegate void BuildingCollapsedEventHandler(Building building);

    /// <summary>Emitted after a decay tick so the HUD can refresh counts.</summary>
    [Signal] public delegate void BuildingsChangedEventHandler(int count);

    public IReadOnlyList<Building> Buildings => _buildings;

    public override void _Ready()
    {
        _gameManager = GetNodeOrNull<GameManager>(GameManagerPath);
        if (_gameManager != null)
            _gameManager.NewDay += OnNewDay;
    }

    public override void _ExitTree()
    {
        if (_gameManager != null)
            _gameManager.NewDay -= OnNewDay;
    }

    public void Register(Building building)
    {
        if (_buildings.Contains(building))
            return;
        _buildings.Add(building);
        building.Collapsed += OnBuildingCollapsed;
        EmitSignal(SignalName.BuildingsChanged, _buildings.Count);
    }

    public void Unregister(Building building)
    {
        if (_buildings.Remove(building))
        {
            building.Collapsed -= OnBuildingCollapsed;
            EmitSignal(SignalName.BuildingsChanged, _buildings.Count);
        }
    }

    private void OnNewDay(int day)
    {
        // One decay tick per in-game day. Abandoned/poorly-founded structures
        // would decay faster — for now apply the base material decay rate.
        foreach (var building in _buildings.ToList())
        {
            if (building.HasCollapsed)
                continue;
            building.ApplyDamage(building.Data.DecayRate);
        }
    }

    private void OnBuildingCollapsed(Building building)
    {
        Unregister(building);
        EmitSignal(SignalName.BuildingCollapsed, building);
    }
}
