using Friflo.Engine.ECS.Systems;
using LittleSim.Content;
using MrGameEng.AI;
using MrGameEng.Core;

namespace LittleSim.Sim;

/// <summary>
/// Плодоношение (фаза G4): у зрелого растения с признаком <see cref="PlantPhenotype.FruitYield"/> &gt; 0
/// в его генетический сезон (<see cref="PlantPhenotype.FruitSeason"/>) копятся зрелые плоды до потолка
/// <see cref="PlantPhenotype.FruitYield"/>; вне сезона плоды опадают. Полностью управляется генами через
/// признаки — система лишь применяет их к компоненту <see cref="Fruiting"/>. Незрелые/бесплодные
/// растения остаются с нулём.
/// </summary>
public sealed class PlantFruitingSystem(PlantSet plants, Calendar calendar, Climate climate)
    : QuerySystem<PlantGrowth, PlantOrganism, Fruiting>
{
    // За сколько игровых дней набирается/опадает полный урожай.
    private const float RipenDays = 10f;
    private const float DropDays = 20f;

    protected override void OnUpdate()
    {
        var deltaDays = Tick.deltaTime / calendar.SecondsPerDay;
        if (deltaDays <= 0f)
        {
            return; // пауза
        }

        var season = (int)climate.Season;

        foreach (var (growths, organisms, fruits, _) in Query.Chunks)
        {
            var g = growths.Span;
            var orgs = organisms.Span;
            var f = fruits.Span;
            for (var i = 0; i < g.Length; i++)
            {
                ref var traits = ref orgs[i].Traits;
                var mature = g[i].Stage >= plants[g[i].Species].Stages.Length - 1;
                if (!mature || traits.FruitYield < 1f)
                {
                    f[i].RipeFruit = 0f; // незрелое или бесплодное — плодов нет
                    continue;
                }

                ref var ripe = ref f[i].RipeFruit;
                if (season == traits.FruitSeason)
                {
                    ripe = MathF.Min(
                        traits.FruitYield,
                        ripe + deltaDays * (traits.FruitYield / RipenDays)
                    );
                }
                else
                {
                    ripe = MathF.Max(0f, ripe - deltaDays * (traits.FruitYield / DropDays));
                }
            }
        }
    }
}
