namespace SpaceGame.Api.Industry.Planning;

internal static class CommodityOperationalSignal
{
    internal static float ComputeNeedScore(FactionCommoditySnapshot commodity, float targetLevelSeconds)
    {
        var productionDeficit = MathF.Max(0f, commodity.ConsumptionRatePerSecond - commodity.ProjectedProductionRatePerSecond);
        var levelDeficit = MathF.Max(0f, targetLevelSeconds - commodity.LevelSeconds) / MathF.Max(targetLevelSeconds, 1f);
        var backlogPressure = MathF.Max(0f, commodity.BuyBacklog + commodity.ReservedForConstruction - commodity.AvailableStock);

        var levelWeight = commodity.Level switch
        {
            CommodityLevelKind.Critical => 140f,
            CommodityLevelKind.Low => 80f,
            CommodityLevelKind.Stable => 20f,
            _ => 0f,
        };

        return levelWeight
          + (productionDeficit * 140f)
          + (levelDeficit * 120f)
          + backlogPressure;
    }

    internal static bool IsOperational(FactionCommoditySnapshot commodity, float targetLevelSeconds) =>
      commodity.ProjectedProductionRatePerSecond > 0.01f
      && commodity.ProjectedNetRatePerSecond >= -0.01f
      && commodity.LevelSeconds >= targetLevelSeconds
      && commodity.Level is CommodityLevelKind.Stable or CommodityLevelKind.Surplus;

    internal static bool IsStrained(FactionCommoditySnapshot commodity, float targetLevelSeconds) =>
      !IsOperational(commodity, targetLevelSeconds)
      || commodity.Level is CommodityLevelKind.Critical or CommodityLevelKind.Low;

    internal static float ComputeFeasibilityFactor(FactionCommoditySnapshot commodity, float targetLevelSeconds)
    {
        if (commodity.AvailableStock <= 0.01f && commodity.ProjectedProductionRatePerSecond <= 0.01f)
        {
            return 0.65f;
        }

        if (commodity.Level is CommodityLevelKind.Critical)
        {
            return 0.72f;
        }

        if (commodity.Level is CommodityLevelKind.Low || commodity.LevelSeconds < targetLevelSeconds)
        {
            return 0.84f;
        }

        return 1f;
    }
}
