using Friflo.Engine.ECS.Systems;
using LittleSim.Content;
using Microsoft.Xna.Framework;
using MrGameEng.AI;
using MrGameEng.Core;
using MrGameEng.Graphics;
using MrGameEng.Lighting;

namespace LittleSim.Sim;

/// <summary>
/// Двигает рост растений по игровому календарю: прирост возраста = пригодность среды для генов
/// растения. Скорость = <c>бодрость · пригодность(свет) · пригодность(температура) ·
/// пригодность(плодородность)</c>, каждая пригодность — гауссов «колокол» вокруг оптимума из генов
/// (см. <see cref="PlantGenome"/>). Свет/температура в фазе B глобальные (день/ночь и сезон); стадии
/// и спрайт переключаются по накопленному возрасту как прежде. Терминальную стадию пропускает.
/// </summary>
public sealed class PlantGrowthSystem(
    PlantSet plants,
    Calendar calendar,
    Climate climate,
    Lighting lighting,
    int cellSize
) : QuerySystem<PlantGrowth, PlantGenome, Sprite, Transform2D>
{
    protected override void OnUpdate()
    {
        var deltaDays = Tick.deltaTime / calendar.SecondsPerDay;
        if (deltaDays <= 0f)
        {
            return; // пауза — рост стоит
        }

        // Температура глобальная; свет — локальный (лайтмап: подлесок под кронами темнее).
        var temperature = climate.Temperature;

        foreach (var (growths, genomes, sprites, transforms, _) in Query.Chunks)
        {
            var g = growths.Span;
            var dna = genomes.Span;
            var s = sprites.Span;
            var t = transforms.Span;
            for (var i = 0; i < g.Length; i++)
            {
                ref var grow = ref g[i];
                var stages = plants[grow.Species].Stages;
                if (grow.Stage >= stages.Length - 1)
                {
                    grow.AgeDays += deltaDays; // зрелое: старение в реальном времени → смерть по старости
                    continue;
                }

                ref var gene = ref dna[i];
                var light = lighting.SampleAt(t[i].Position);
                var rate =
                    gene.Vigor
                    * Suitability.Gaussian(light, gene.OptimalLight, gene.LightTolerance)
                    * Suitability.Gaussian(
                        temperature,
                        gene.OptimalTemperature,
                        gene.TemperatureTolerance
                    )
                    * Suitability.Gaussian(
                        grow.CellFertility,
                        gene.OptimalFertility,
                        gene.FertilityTolerance
                    );

                grow.AgeDays += deltaDays * rate;
                var changed = false;
                while (
                    grow.Stage < stages.Length - 1
                    && grow.AgeDays >= stages[grow.Stage + 1].EnterDay
                )
                {
                    grow.Stage++;
                    changed = true;
                }

                if (changed)
                {
                    Apply(ref s[i], ref t[i], stages[grow.Stage]);
                }
            }
        }
    }

    private void Apply(ref Sprite sprite, ref Transform2D transform, in PlantSet.Stage stage)
    {
        sprite.Region = stage.Region;
        sprite.Origin = new Vector2(stage.Region.Width / 2f, stage.Region.Height / 2f);
        transform.Scale = new Vector2(cellSize * stage.SizeCells / stage.Region.Width);
    }
}
