namespace ReactorMaintenance.Simulation;

internal static class ConsumerSystem
{
    public static LevelState Resolve(LevelState level)
    {
        var props = level.Props.ToArray();
        foreach (var position in LevelTraversal.AllPositions(level))
        {
            var index = level.Index(position);
            var prop = props[index];
            if (prop.Type != EPropType.Consumer)
                continue;

            if (prop.SwitchState == EPropSwitchState.Disabled)
            {
                var disabledFuel = DisabledServiceStateFor(level, position, ECarrierType.Fuel);
                var disabledCoolant = DisabledServiceStateFor(level, position, ECarrierType.Coolant);
                var disabledElectricity = DisabledServiceStateFor(level, position, ECarrierType.Electricity);
                props[index] = prop with {
                    ServiceState = Aggregate(disabledFuel, disabledCoolant, disabledElectricity),
                    FuelServiceState = disabledFuel,
                    CoolantServiceState = disabledCoolant,
                    ElectricityServiceState = disabledElectricity
                };
                continue;
            }

            var fuel = ServiceStateFor(level, position, ECarrierType.Fuel);
            var coolant = ServiceStateFor(level, position, ECarrierType.Coolant);
            var electricity = ServiceStateFor(level, position, ECarrierType.Electricity);
            props[index] = prop with {
                ServiceState = Aggregate(fuel, coolant, electricity),
                FuelServiceState = fuel,
                CoolantServiceState = coolant,
                ElectricityServiceState = electricity
            };
        }

        return level with { Props = props };
    }

    private static EConsumerServiceState ServiceStateFor(LevelState level, GridPosition position, ECarrierType carrier)
    {
        var underground = level.GetUnderground(position, carrier);
        if (!underground.IsPresent)
            return EConsumerServiceState.Unknown;

        var supplied = underground.Amount >= Balancing.Current.ConsumerRequiredAmount && underground.Intensity >= Balancing.Current.ConsumerRequiredIntensity;
        return supplied ? EConsumerServiceState.Producing : EConsumerServiceState.Starved;
    }

    private static EConsumerServiceState DisabledServiceStateFor(LevelState level, GridPosition position, ECarrierType carrier)
    {
        return level.GetUnderground(position, carrier).IsPresent ? EConsumerServiceState.Disabled : EConsumerServiceState.Unknown;
    }

    private static EConsumerServiceState Aggregate(params EConsumerServiceState[] states)
    {
        var participating = states.Where(state => state != EConsumerServiceState.Unknown).ToArray();
        if (participating.Length == 0)
            return EConsumerServiceState.Unknown;

        if (participating.Any(state => state == EConsumerServiceState.Starved))
            return EConsumerServiceState.Starved;

        if (participating.Any(state => state == EConsumerServiceState.Disabled))
            return EConsumerServiceState.Disabled;

        return EConsumerServiceState.Producing;
    }
}