using System.Collections.Generic;
using System.Text;
using Friflo.Engine.ECS;
using LittleSim.Content;
using LittleSim.Sim;
using Microsoft.Xna.Framework;
using MrGameEng.AI;
using MrGameEng.Core;
using MrGameEng.Graphics;
using MrGameEng.Mods;
using Myra.Graphics2D;
using Myra.Graphics2D.Brushes;
using Myra.Graphics2D.UI;

namespace LittleSim.UI;

/// <summary>
/// Панель осмотра выбранной сущности (инфо-карточка в стиле RimWorld): угловая рамка вокруг объекта
/// (<see cref="SelectionBrackets"/>) и боковая панель в левом нижнем углу с вкладками — «Обзор»,
/// «Гены», «Продукты». Источник выделения — <see cref="Selection"/>; панель только читает компоненты
/// и обновляется каждый кадр (<see cref="Refresh"/>), оставаясь живой даже на паузе. Все строки идут
/// через <see cref="LanguageManager"/> (ключи <c>inspect.*</c>).
/// </summary>
internal sealed class InspectPanel
{
    private enum Tab
    {
        Overview,
        Genes,
        Products,
    }

    private readonly EntityStore _store;
    private readonly PlantSet _plants;
    private readonly GameContent _content;
    private readonly Climate _climate;
    private readonly Selection _selection;
    private readonly SelectionBrackets _brackets;

    private readonly VerticalStackPanel _panel;
    private readonly Label _title;
    private readonly Label _body;
    private readonly List<(Tab Tab, TextButton Button)> _tabs = [];
    private Tab _tab = Tab.Overview;

    public InspectPanel(
        EntityStore store,
        PlantSet plants,
        GameContent content,
        Climate climate,
        Selection selection,
        SelectionBrackets brackets
    )
    {
        _store = store;
        _plants = plants;
        _content = content;
        _climate = climate;
        _selection = selection;
        _brackets = brackets;

        _title = new Label { TextColor = Ui.Accent, Wrap = true };
        _body = new Label { TextColor = new Color(210, 216, 226), Wrap = true };

        var tabBar = new HorizontalStackPanel { Spacing = 4 };
        AddTab(tabBar, Tab.Overview, "inspect.tab.overview");
        AddTab(tabBar, Tab.Genes, "inspect.tab.genes");
        AddTab(tabBar, Tab.Products, "inspect.tab.products");

        _panel = new VerticalStackPanel
        {
            Spacing = 6,
            Padding = new Thickness(14),
            Width = 380,
            HorizontalAlignment = HorizontalAlignment.Left,
            VerticalAlignment = VerticalAlignment.Bottom,
            Margin = new Thickness(12, 0, 0, 14),
            Background = new SolidBrush(new Color(10, 13, 18, 240)),
            Border = new SolidBrush(new Color(96, 134, 168)),
            BorderThickness = new Thickness(2),
            Visible = false,
        };
        _panel.Widgets.Add(_title);
        _panel.Widgets.Add(tabBar);
        _panel.Widgets.Add(new HorizontalSeparator());
        _panel.Widgets.Add(_body);
        _panel.Widgets.Add(
            new Label
            {
                Text = _content.Languages.Get("inspect.hint"),
                TextColor = Ui.Muted,
                Wrap = true,
            }
        );
    }

    /// <summary>Боковая инфо-панель — добавляется в корень экрана.</summary>
    public VerticalStackPanel Panel => _panel;

    /// <summary>
    /// Подтягивает выделение каждый кадр: проверяет, жива ли сущность (иначе снимает выбор), двигает
    /// рамку к объекту и пересобирает текст активной вкладки. Не-растения панель не показывает.
    /// </summary>
    public void Refresh()
    {
        if (
            !_selection.HasSelection
            || !_store.TryGetEntityById(_selection.EntityId, out var entity)
            || entity.IsNull
            || !entity.HasComponent<PlantGrowth>()
            || !entity.HasComponent<PlantOrganism>()
            || !entity.HasComponent<Transform2D>()
            || !entity.HasComponent<Sprite>()
        )
        {
            if (_selection.HasSelection)
            {
                _selection.Clear(); // сущность исчезла (растение погибло)
            }

            _panel.Visible = false;
            _brackets.Hide();
            return;
        }

        var transform = entity.GetComponent<Transform2D>();
        var sprite = entity.GetComponent<Sprite>();
        if (sprite.Region is { } region)
        {
            var (center, radius) = CullingMath.SpriteBoundingCircle(
                in transform,
                region,
                sprite.Origin
            );
            _brackets.Show(center, radius);
        }

        UpdateText(entity);
        _panel.Visible = true;
    }

    private void AddTab(HorizontalStackPanel bar, Tab tab, string labelKey)
    {
        var button = new TextButton { Text = _content.Languages.Get(labelKey) };
        button.Click += (_, _) => _tab = tab;
        bar.Widgets.Add(button);
        _tabs.Add((tab, button));
    }

    private void UpdateText(Entity entity)
    {
        var languages = _content.Languages;
        ref readonly var grow = ref entity.GetComponent<PlantGrowth>();
        ref readonly var org = ref entity.GetComponent<PlantOrganism>();
        var species = _plants[grow.Species];
        var def = species.Def;
        var traits = org.Traits;

        _title.Text = languages.Get(def.Label) + (traits.IsVariant ? " *" : "");
        foreach (var (tab, button) in _tabs)
        {
            button.TextColor = tab == _tab ? Ui.Accent : Ui.Muted;
        }

        var text = new StringBuilder();
        switch (_tab)
        {
            case Tab.Overview:
                BuildOverview(text, entity, grow, traits, species);
                break;
            case Tab.Genes:
                BuildGenes(text, traits);
                break;
            case Tab.Products:
                BuildProducts(text, entity, def, traits);
                break;
        }

        _body.Text = text.ToString().TrimEnd();
    }

    private void BuildOverview(
        StringBuilder text,
        Entity entity,
        in PlantGrowth grow,
        in PlantPhenotype traits,
        PlantSet.Species species
    )
    {
        var languages = _content.Languages;
        var lastStage = species.Stages.Length - 1;
        var mature = grow.Stage >= lastStage;

        text.AppendLine(
            languages.Format(
                "inspect.stage",
                StageLabel(species.Def, grow.Stage),
                grow.Stage + 1,
                species.Stages.Length
            )
        );
        if (mature)
        {
            text.AppendLine(languages.Get("inspect.mature"));
        }
        else
        {
            var from = species.Stages[grow.Stage].EnterDay;
            var to = species.Stages[grow.Stage + 1].EnterDay;
            var pct = to > from ? (grow.AgeDays - from) / (to - from) * 100f : 0f;
            text.AppendLine(languages.Format("inspect.growing", Math.Clamp(pct, 0f, 100f)));
        }

        text.AppendLine(languages.Format("inspect.age", grow.AgeDays, traits.Lifespan));

        // Состояние по температуре (рост/покой) и накопленный стресс.
        var (tMin, tLow, tHigh, tMax) = traits.TemperatureBand();
        var temperature = _climate.Temperature;
        var suit = Suitability.Trapezoid(temperature, tMin, tLow, tHigh, tMax);
        var state =
            suit <= 0f
                ? languages.Get(
                    temperature <= tMin ? "inspect.state.dormantcold" : "inspect.state.dormanthot"
                )
                : languages.Get(mature ? "inspect.state.mature" : "inspect.state.growing");
        text.AppendLine(languages.Format("inspect.state", state));
        if (entity.TryGetComponent<TemperatureStress>(out var stress) && stress.Days > 0.05f)
        {
            text.AppendLine(languages.Format("inspect.stress", stress.Days));
        }

        text.AppendLine(languages.Format("inspect.temp", tMin, tMax, tLow, tHigh));
    }

    private void BuildGenes(StringBuilder text, in PlantPhenotype traits)
    {
        var languages = _content.Languages;
        text.AppendLine(languages.Format("inspect.gene.vigor", traits.Vigor, traits.Lifespan));
        text.AppendLine(
            languages.Format("inspect.gene.env", traits.OptimalLight, traits.OptimalFertility)
        );
        text.AppendLine(
            languages.Format("inspect.gene.repro", traits.DispersalRange, traits.ReproduceInterval)
        );
        text.AppendLine(
            languages.Format("inspect.gene.repro2", traits.SelfPollination, traits.MutationRate)
        );
        text.AppendLine(
            languages.Format(
                "inspect.gene.hardy",
                traits.ColdHardiness,
                traits.HeatHardiness,
                traits.LeafHue
            )
        );
        if (traits.IsVariant)
        {
            text.AppendLine(languages.Get("inspect.gene.variant"));
        }
    }

    private void BuildProducts(
        StringBuilder text,
        Entity entity,
        PlantDef def,
        in PlantPhenotype traits
    )
    {
        var languages = _content.Languages;
        if (def.HarvestProduct is { } harvest)
        {
            text.AppendLine(
                languages.Format("inspect.harvest", ProductLabel(harvest), traits.HarvestAmount)
            );
        }

        if (def.FruitProduct is { } fruit && traits.FruitYield >= 1f)
        {
            var ripe = entity.TryGetComponent<Fruiting>(out var fruiting) ? fruiting.RipeFruit : 0f;
            var season = languages.Get(
                "season." + ((Season)traits.FruitSeason).ToString().ToLowerInvariant()
            );
            text.AppendLine(
                languages.Format(
                    "inspect.fruit",
                    ProductLabel(fruit),
                    traits.FruitYield,
                    season,
                    ripe
                )
            );
        }
        else
        {
            text.AppendLine(languages.Get("inspect.barren"));
        }
    }

    private string StageLabel(PlantDef def, int stage) =>
        stage < def.Stages.Count && def.Stages[stage].Label is { } key
            ? _content.Languages.Get(key)
            : "—";

    private string ProductLabel(string productDefName) =>
        _content.Defs.TryGet<ProductDef>(productDefName, out var product)
            ? _content.Languages.Get(product.Label)
            : productDefName;
}
