namespace splat;

using Godot;

/// <summary>
/// A road segment. Accumulates wear from vehicle throughput and weather, and
/// exposes a quality factor that slows traffic. At full wear, potholes form and
/// the surface becomes effectively impassable. Roads are physical (per design
/// pillar): wear is tracked as state, not abstracted to a stat.
/// </summary>
public partial class Road : StaticBody3D
{
    [Export] public RoadData Data { get; set; } = default!;

    /// <summary>True once wear has reached 1 and potholes have formed.</summary>
    public bool HasPotholes => Data != null && Data.Wear >= 1f;

    /// <summary>Emitted when the road becomes fully degraded.</summary>
    [Signal] public delegate void DegradedEventHandler(Road road);

    public override void _Ready()
    {
        CollisionLayer = 8u; // Infrastructure physics layer (layer 4)

        if (GetNodeOrNull<CollisionShape3D>("CollisionShape3D") == null)
        {
            var shape = new CollisionShape3D();
            shape.Shape = new BoxShape3D { Size = new Vector3(4f, 0.4f, 12f) };
            shape.Position = new Vector3(0f, -0.2f, 0f);
            AddChild(shape);
        }

        if (GetNodeOrNull<MeshInstance3D>("MeshInstance3D") == null)
        {
            var mesh = new MeshInstance3D();
            var box = new BoxMesh { Size = new Vector3(4f, 0.4f, 12f) };
            mesh.Mesh = box;
            mesh.Position = new Vector3(0f, -0.2f, 0f);
            var mat = new StandardMaterial3D
            {
                AlbedoColor = Data?.Material switch
                {
                    RoadMaterial.Cobble => new Color(0.45f, 0.45f, 0.47f),
                    RoadMaterial.Gravel => new Color(0.5f, 0.47f, 0.4f),
                    RoadMaterial.Setts => new Color(0.4f, 0.4f, 0.42f),
                    _ => new Color(0.18f, 0.18f, 0.2f) // Tarmac
                }
            };
            mesh.MaterialOverride = mat;
            AddChild(mesh);
        }

        ApplyWearVisuals();
    }

    /// <summary>Register vehicle throughput; adds wear scaled by material resistance.</summary>
    public void RegisterTraffic(float passes = 1f, bool wet = false)
    {
        if (Data == null || HasPotholes)
            return;

        var weatherMul = wet ? Data.WeatherWearMultiplier : 1f;
        var added = passes * Data.BaseWearRate / RoadData.WearResistance(Data.Material) * weatherMul;
        Data.Wear = Mathf.Clamp(Data.Wear + added, 0f, 1f);
        ApplyWearVisuals();

        if (HasPotholes)
            EmitSignal(SignalName.Degraded, this);
    }

    public float QualityFactor() => Data?.QualityFactor() ?? 1f;

    private void ApplyWearVisuals()
    {
        if (Data == null)
            return;
        // Darken / desaturate the surface as wear rises to read as grime and potholes.
        var mesh = GetNodeOrNull<MeshInstance3D>("MeshInstance3D");
        if (mesh?.MaterialOverride is StandardMaterial3D mat)
        {
            var t = Data.Wear;
            var baseColor = Data.Material switch
            {
                RoadMaterial.Cobble => new Color(0.45f, 0.45f, 0.47f),
                RoadMaterial.Gravel => new Color(0.5f, 0.47f, 0.4f),
                RoadMaterial.Setts => new Color(0.4f, 0.4f, 0.42f),
                _ => new Color(0.18f, 0.18f, 0.2f)
            };
            mat.AlbedoColor = baseColor.Lerp(new Color(0.25f, 0.22f, 0.18f), t);
        }
    }
}
