using HanaTui.System;
using Spectre.Console;
using Spectre.Console.Rendering;

namespace HanaTui.Tui.Components;

/// <summary>
/// Renders the system stats panel (CPU bars, RAM bar, Swap bar, elapsed time).
/// Uses only hardcoded markup tags — no dynamic data ever enters a markup string.
/// </summary>
public static class StatsPanel
{
    public static IRenderable Build(SystemSnapshot snap, TimeSpan elapsed, int panelWidth)
    {
        var barWidth = Math.Max(10, panelWidth - 16);

        var grid = new Grid();
        grid.AddColumn(new GridColumn().NoWrap());

        // --- CPU ---
        grid.AddRow(new Markup("[bold yellow]CPU[/]"));

        if (snap.CpuPercents.Length == 0)
        {
            grid.AddRow(new Markup("[grey]No data[/]"));
        }
        else
        {
            for (int i = 0; i < snap.CpuPercents.Length; i++)
            {
                var label = snap.CpuLabels.Length > i ? snap.CpuLabels[i] : $"cpu{i}";
                var displayLabel = label == "cpu" ? "Total" : label.Replace("cpu", "Core");
                var pct = snap.CpuPercents[i];
                // Build as Columns: label | bar | pct — no interpolation of dynamic values into markup
                grid.AddRow(BuildBarRow(displayLabel, pct, barWidth));
            }
        }

        grid.AddRow(new Text(""));

        // --- Memory ---
        grid.AddRow(new Markup("[bold cyan]MEMORY[/]"));
        if (snap.MemTotalKb > 0)
        {
            var memPct = snap.MemUsedPercent;
            grid.AddRow(BuildBarRow("Used", memPct, barWidth));
            grid.AddRow(new Text($"  {SystemSnapshot.FormatGb(snap.MemUsedKb)} / {SystemSnapshot.FormatGb(snap.MemTotalKb)}",
                new Style(Color.Grey)));
        }
        else
        {
            grid.AddRow(new Markup("[grey]No data[/]"));
        }

        grid.AddRow(new Text(""));

        // --- Swap ---
        grid.AddRow(new Markup("[bold cyan]SWAP[/]"));
        if (snap.SwapTotalKb > 0)
        {
            var swapPct = snap.SwapUsedPercent;
            grid.AddRow(BuildBarRow("Used", swapPct, barWidth));
            grid.AddRow(new Text($"  {SystemSnapshot.FormatGb(snap.SwapUsedKb)} / {SystemSnapshot.FormatGb(snap.SwapTotalKb)}",
                new Style(Color.Grey)));
        }
        else
        {
            grid.AddRow(new Markup("[grey]No swap[/]"));
        }

        grid.AddRow(new Text(""));

        // --- Elapsed ---
        // Two separate renderables composed — no interpolation of elapsed into markup
        var elapsedGrid = new Grid();
        elapsedGrid.AddColumn(new GridColumn().NoWrap());
        elapsedGrid.AddColumn(new GridColumn().NoWrap());
        elapsedGrid.AddRow(
            new Markup("[bold]Elapsed:[/]"),
            new Text(" " + FormatElapsed(elapsed), new Style(Color.Yellow)));
        grid.AddRow(elapsedGrid);

        return new Panel(grid)
        {
            Header = new PanelHeader("[bold] SYSTEM STATS [/]"),
            Border = BoxBorder.Rounded,
            Padding = new Padding(1, 0),
        };
    }

    // -------------------------------------------------------------------------
    // Helpers
    // -------------------------------------------------------------------------

    /// <summary>
    /// Builds a single bar row as a Grid with three columns:
    ///   label (dim) | bar (block chars, plain Text with color) | pct (bold)
    /// Nothing here goes through markup parsing with dynamic content.
    /// </summary>
    private static IRenderable BuildBarRow(string label, double pct, int barWidth)
    {
        var filled = (int)Math.Round(pct / 100.0 * barWidth);
        filled = Math.Clamp(filled, 0, barWidth);
        var empty = barWidth - filled;

        var filledColor = CpuColor(pct);
        var filledStr = new string('\u2588', filled);
        var emptyStr  = new string('\u2591', empty);

        var row = new Grid();
        row.AddColumn(new GridColumn().NoWrap().Width(9));   // label
        row.AddColumn(new GridColumn().NoWrap());             // bar chars
        row.AddColumn(new GridColumn().NoWrap().Width(7));   // pct

        row.AddRow(
            new Text($"  {label,-5}", new Style(Color.Grey, decoration: Decoration.Dim)),
            // Bar: colored filled + dim empty, wrapped in plain Text objects side by side
            new Columns(
                new Text("[", new Style(Color.Grey)),
                new Text(filledStr, new Style(filledColor)),
                new Text(emptyStr,  new Style(Color.Grey, decoration: Decoration.Dim)),
                new Text("]", new Style(Color.Grey))
            ),
            new Text($" {pct,5:F1}%", new Style(Color.White, decoration: Decoration.Bold))
        );

        return row;
    }

    private static Color CpuColor(double pct) => pct switch
    {
        > 90 => Color.Red,
        > 70 => Color.Yellow,
        > 40 => Color.Green,
        _    => Color.Blue,
    };

    private static string FormatElapsed(TimeSpan t)
    {
        if (t.TotalHours >= 1)
            return $"{(int)t.TotalHours}h {t.Minutes:D2}m {t.Seconds:D2}s";
        if (t.TotalMinutes >= 1)
            return $"{t.Minutes}m {t.Seconds:D2}s";
        return $"{t.Seconds}s";
    }
}
