using System.Text;
using System.Text.Json;

namespace AxCopilot.Services.Agent;

public partial class ChartSkill
{
    // ─── 차트 렌더러 + 헬퍼 ──────────────────────────────────────────────────

    // ─── Bar Chart ───────────────────────────────────────────────────────

    private static string RenderBarChart(List<string> labels, List<Dataset> datasets, string unit, bool horizontal)
    {
        var maxVal = datasets.SelectMany(d => d.Values).DefaultIfEmpty(1).Max();
        if (maxVal <= 0) maxVal = 1;
        var sb = new StringBuilder();

        if (horizontal)
        {
            sb.AppendLine("<div class=\"hbar-chart\">");
            for (int i = 0; i < labels.Count; i++)
            {
                var val = datasets.Count > 0 && i < datasets[0].Values.Count ? datasets[0].Values[i] : 0;
                var pct = (int)(val / maxVal * 100);
                var color = datasets.Count > 0 ? datasets[0].Color : Palette[0];
                sb.AppendLine($"<div class=\"hbar-row\"><span class=\"hbar-label\">{Escape(labels[i])}</span>");
                sb.AppendLine($"<div class=\"hbar-track\"><div class=\"hbar-fill\" style=\"width:{pct}%;background:{color};\"></div></div>");
                sb.AppendLine($"<span class=\"hbar-value\">{val:G}{unit}</span></div>");
            }
            sb.AppendLine("</div>");
        }
        else
        {
            sb.AppendLine("<div class=\"vbar-chart\">");
            sb.AppendLine("<div class=\"vbar-bars\">");
            for (int i = 0; i < labels.Count; i++)
            {
                sb.AppendLine("<div class=\"vbar-group\">");
                foreach (var ds in datasets)
                {
                    var val = i < ds.Values.Count ? ds.Values[i] : 0;
                    var pct = (int)(val / maxVal * 100);
                    sb.AppendLine($"<div class=\"vbar-bar\" style=\"height:{pct}%;background:{ds.Color};\" title=\"{val:G}{unit}\"></div>");
                }
                sb.AppendLine($"<div class=\"vbar-label\">{Escape(labels[i])}</div>");
                sb.AppendLine("</div>");
            }
            sb.AppendLine("</div></div>");
        }

        return sb.ToString();
    }

    // ─── Stacked Bar ─────────────────────────────────────────────────────

    private static string RenderStackedBar(List<string> labels, List<Dataset> datasets, string unit)
    {
        var sb = new StringBuilder();
        sb.AppendLine("<div class=\"hbar-chart\">");
        for (int i = 0; i < labels.Count; i++)
        {
            var total = datasets.Sum(ds => i < ds.Values.Count ? ds.Values[i] : 0);
            sb.AppendLine($"<div class=\"hbar-row\"><span class=\"hbar-label\">{Escape(labels[i])}</span>");
            sb.AppendLine("<div class=\"hbar-track\" style=\"display:flex;\">");
            foreach (var ds in datasets)
            {
                var val = i < ds.Values.Count ? ds.Values[i] : 0;
                var pct = total > 0 ? (int)(val / total * 100) : 0;
                sb.AppendLine($"<div style=\"width:{pct}%;background:{ds.Color};height:100%;\" title=\"{ds.Name}: {val:G}{unit}\"></div>");
            }
            sb.AppendLine($"</div><span class=\"hbar-value\">{total:G}{unit}</span></div>");
        }
        sb.AppendLine("</div>");
        return sb.ToString();
    }

    // ─── Line / Area Chart (SVG) ─────────────────────────────────────────

    private static string RenderLineChart(List<string> labels, List<Dataset> datasets, string unit, bool isArea)
    {
        var allVals = datasets.SelectMany(d => d.Values).ToList();
        var maxVal = allVals.DefaultIfEmpty(1).Max();
        var minVal = allVals.DefaultIfEmpty(0).Min();
        if (maxVal <= minVal) maxVal = minVal + 1;

        int w = 600, h = 300, padL = 50, padR = 20, padT = 20, padB = 40;
        var chartW = w - padL - padR;
        var chartH = h - padT - padB;
        var n = labels.Count;

        var sb = new StringBuilder();
        sb.AppendLine($"<svg viewBox=\"0 0 {w} {h}\" class=\"line-chart-svg\" preserveAspectRatio=\"xMidYMid meet\">");

        // Y축 그리드
        for (int i = 0; i <= 4; i++)
        {
            var y = padT + chartH - (chartH * i / 4.0);
            var val = minVal + (maxVal - minVal) * i / 4.0;
            sb.AppendLine($"<line x1=\"{padL}\" y1=\"{y:F0}\" x2=\"{w - padR}\" y2=\"{y:F0}\" stroke=\"#E5E7EB\" stroke-width=\"1\"/>");
            sb.AppendLine($"<text x=\"{padL - 8}\" y=\"{y + 4:F0}\" text-anchor=\"end\" fill=\"#6B7280\" font-size=\"11\">{val:G3}{unit}</text>");
        }

        // X축 라벨
        for (int i = 0; i < n; i++)
        {
            var x = padL + (n > 1 ? chartW * i / (double)(n - 1) : chartW / 2.0);
            sb.AppendLine($"<text x=\"{x:F0}\" y=\"{h - 8}\" text-anchor=\"middle\" fill=\"#6B7280\" font-size=\"11\">{Escape(labels[i])}</text>");
        }

        // 데이터셋
        foreach (var ds in datasets)
        {
            var points = new List<(double x, double y)>();
            for (int i = 0; i < Math.Min(n, ds.Values.Count); i++)
            {
                var x = padL + (n > 1 ? chartW * i / (double)(n - 1) : chartW / 2.0);
                var y = padT + chartH - ((ds.Values[i] - minVal) / (maxVal - minVal) * chartH);
                points.Add((x, y));
            }

            var pathData = string.Join(" ", points.Select((p, i) => $"{(i == 0 ? "M" : "L")}{p.x:F1},{p.y:F1}"));

            if (isArea && points.Count > 1)
            {
                var areaPath = pathData + $" L{points.Last().x:F1},{padT + chartH} L{points.First().x:F1},{padT + chartH} Z";
                sb.AppendLine($"<path d=\"{areaPath}\" fill=\"{ds.Color}\" opacity=\"0.15\"/>");
            }

            sb.AppendLine($"<path d=\"{pathData}\" fill=\"none\" stroke=\"{ds.Color}\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>");

            // 데이터 포인트
            foreach (var (px, py) in points)
                sb.AppendLine($"<circle cx=\"{px:F1}\" cy=\"{py:F1}\" r=\"4\" fill=\"{ds.Color}\" stroke=\"white\" stroke-width=\"2\"/>");
        }

        sb.AppendLine("</svg>");
        return sb.ToString();
    }

    // ─── Pie / Donut Chart (SVG) ─────────────────────────────────────────

    private static string RenderPieChart(List<string> labels, List<Dataset> datasets, bool isDonut)
    {
        var values = datasets.Count > 0 ? datasets[0].Values : new List<double>();
        var total = values.Sum();
        if (total <= 0) total = 1;

        int cx = 150, cy = 150, r = 120;
        var sb = new StringBuilder();
        sb.AppendLine($"<div style=\"display:flex;align-items:center;gap:24px;flex-wrap:wrap;\">");
        sb.AppendLine($"<svg viewBox=\"0 0 300 300\" width=\"260\" height=\"260\">");

        double startAngle = -90;
        for (int i = 0; i < Math.Min(values.Count, labels.Count); i++)
        {
            var pct = values[i] / total;
            var angle = pct * 360;
            var endAngle = startAngle + angle;

            var x1 = cx + r * Math.Cos(startAngle * Math.PI / 180);
            var y1 = cy + r * Math.Sin(startAngle * Math.PI / 180);
            var x2 = cx + r * Math.Cos(endAngle * Math.PI / 180);
            var y2 = cy + r * Math.Sin(endAngle * Math.PI / 180);
            var largeArc = angle > 180 ? 1 : 0;

            var color = i < Palette.Length ? Palette[i] : Palette[i % Palette.Length];
            sb.AppendLine($"<path d=\"M{cx},{cy} L{x1:F1},{y1:F1} A{r},{r} 0 {largeArc},1 {x2:F1},{y2:F1} Z\" fill=\"{color}\"/>");
            startAngle = endAngle;
        }

        if (isDonut)
            sb.AppendLine($"<circle cx=\"{cx}\" cy=\"{cy}\" r=\"{r * 0.55}\" fill=\"white\"/>");

        sb.AppendLine("</svg>");

        // 범례
        sb.AppendLine("<div class=\"pie-legend\">");
        for (int i = 0; i < Math.Min(values.Count, labels.Count); i++)
        {
            var color = i < Palette.Length ? Palette[i] : Palette[i % Palette.Length];
            var pct = values[i] / total * 100;
            sb.AppendLine($"<div class=\"pie-legend-item\"><span class=\"legend-dot\" style=\"background:{color}\"></span>{Escape(labels[i])} <span style=\"color:#6B7280;font-size:12px;\">({pct:F1}%)</span></div>");
        }
        sb.AppendLine("</div></div>");

        return sb.ToString();
    }

    // ─── Progress Chart ──────────────────────────────────────────────────

    private static string RenderProgressChart(List<string> labels, List<Dataset> datasets, string unit)
    {
        var values = datasets.Count > 0 ? datasets[0].Values : new List<double>();
        var sb = new StringBuilder();
        for (int i = 0; i < Math.Min(labels.Count, values.Count); i++)
        {
            var pct = Math.Clamp(values[i], 0, 100);
            var color = i < Palette.Length ? Palette[i] : Palette[i % Palette.Length];
            if (datasets.Count > 0 && !string.IsNullOrEmpty(datasets[0].Color))
                color = datasets[0].Color;
            sb.AppendLine($"<div style=\"margin-bottom:12px;\"><div style=\"display:flex;justify-content:space-between;margin-bottom:4px;\"><span style=\"font-size:13px;font-weight:600;\">{Escape(labels[i])}</span><span style=\"font-size:13px;color:#6B7280;\">{values[i]:G}{unit}</span></div>");
            sb.AppendLine($"<div class=\"progress\"><div class=\"progress-fill\" style=\"width:{pct}%;background:{color};\"></div></div></div>");
        }
        return sb.ToString();
    }

    // ─── Comparison Chart ────────────────────────────────────────────────

    private static string RenderComparisonChart(List<string> labels, List<Dataset> datasets, string unit)
    {
        var sb = new StringBuilder();
        sb.AppendLine("<table style=\"width:100%;border-collapse:collapse;\">");
        sb.AppendLine("<tr><th style=\"text-align:left;padding:8px 12px;\">항목</th>");
        foreach (var ds in datasets)
            sb.AppendLine($"<th style=\"text-align:center;padding:8px 12px;color:{ds.Color};\">{Escape(ds.Name)}</th>");
        sb.AppendLine("</tr>");
        for (int i = 0; i < labels.Count; i++)
        {
            sb.Append($"<tr style=\"border-top:1px solid #E5E7EB;\"><td style=\"padding:8px 12px;font-weight:500;\">{Escape(labels[i])}</td>");
            foreach (var ds in datasets)
            {
                var val = i < ds.Values.Count ? ds.Values[i] : 0;
                sb.Append($"<td style=\"text-align:center;padding:8px 12px;\">{val:G}{unit}</td>");
            }
            sb.AppendLine("</tr>");
        }
        sb.AppendLine("</table>");
        return sb.ToString();
    }

    // ─── Radar Chart (SVG) ───────────────────────────────────────────────

    private static string RenderRadarChart(List<string> labels, List<Dataset> datasets)
    {
        int cx = 150, cy = 150, r = 110;
        var n = labels.Count;
        if (n < 3) return "<p>레이더 차트는 최소 3개 항목이 필요합니다.</p>";

        var sb = new StringBuilder();
        sb.AppendLine($"<svg viewBox=\"0 0 300 300\" width=\"300\" height=\"300\">");

        // 그리드
        for (int level = 1; level <= 4; level++)
        {
            var lr = r * level / 4.0;
            var points = string.Join(" ", Enumerable.Range(0, n).Select(i =>
            {
                var angle = (360.0 / n * i - 90) * Math.PI / 180;
                return $"{cx + lr * Math.Cos(angle):F1},{cy + lr * Math.Sin(angle):F1}";
            }));
            sb.AppendLine($"<polygon points=\"{points}\" fill=\"none\" stroke=\"#E5E7EB\" stroke-width=\"1\"/>");
        }

        // 축선 + 라벨
        for (int i = 0; i < n; i++)
        {
            var angle = (360.0 / n * i - 90) * Math.PI / 180;
            var x = cx + r * Math.Cos(angle);
            var y = cy + r * Math.Sin(angle);
            sb.AppendLine($"<line x1=\"{cx}\" y1=\"{cy}\" x2=\"{x:F1}\" y2=\"{y:F1}\" stroke=\"#D1D5DB\" stroke-width=\"1\"/>");
            var lx = cx + (r + 16) * Math.Cos(angle);
            var ly = cy + (r + 16) * Math.Sin(angle);
            sb.AppendLine($"<text x=\"{lx:F0}\" y=\"{ly + 4:F0}\" text-anchor=\"middle\" fill=\"#374151\" font-size=\"11\">{Escape(labels[i])}</text>");
        }

        // 데이터
        var maxVal = datasets.SelectMany(d => d.Values).DefaultIfEmpty(1).Max();
        if (maxVal <= 0) maxVal = 1;
        foreach (var ds in datasets)
        {
            var points = string.Join(" ", Enumerable.Range(0, n).Select(i =>
            {
                var val = i < ds.Values.Count ? ds.Values[i] : 0;
                var dr = r * val / maxVal;
                var angle = (360.0 / n * i - 90) * Math.PI / 180;
                return $"{cx + dr * Math.Cos(angle):F1},{cy + dr * Math.Sin(angle):F1}";
            }));
            sb.AppendLine($"<polygon points=\"{points}\" fill=\"{ds.Color}\" fill-opacity=\"0.2\" stroke=\"{ds.Color}\" stroke-width=\"2\"/>");
        }

        sb.AppendLine("</svg>");
        return sb.ToString();
    }

    // ─── Helpers ─────────────────────────────────────────────────────────

    private static List<string> ParseStringArray(JsonElement parent, string prop)
    {
        if (!parent.TryGetProperty(prop, out var arr) || arr.ValueKind != JsonValueKind.Array)
            return new();
        return arr.EnumerateArray().Select(e => e.GetString() ?? "").ToList();
    }

    private List<Dataset> ParseDatasets(JsonElement chart)
    {
        if (!chart.TryGetProperty("datasets", out var dsArr) || dsArr.ValueKind != JsonValueKind.Array)
        {
            // datasets 없으면 values 배열에서 단일 데이터셋 생성
            if (chart.TryGetProperty("values", out var vals) && vals.ValueKind == JsonValueKind.Array)
            {
                return new()
                {
                    new Dataset
                    {
                        Name = "Data",
                        Values = vals.EnumerateArray().Select(v => v.TryGetDouble(out var d) ? d : 0).ToList(),
                        Color = Palette[0],
                    }
                };
            }
            return new();
        }

        var list = new List<Dataset>();
        int colorIdx = 0;
        foreach (var ds in dsArr.EnumerateArray())
        {
            var name = ds.TryGetProperty("name", out var n) ? n.GetString() ?? $"Series{colorIdx + 1}" : $"Series{colorIdx + 1}";
            var color = ds.TryGetProperty("color", out var c) ? c.GetString() ?? Palette[colorIdx % Palette.Length] : Palette[colorIdx % Palette.Length];
            var values = new List<double>();
            if (ds.TryGetProperty("values", out var v) && v.ValueKind == JsonValueKind.Array)
                values = v.EnumerateArray().Select(e => e.TryGetDouble(out var d) ? d : 0).ToList();
            list.Add(new Dataset { Name = name, Values = values, Color = color });
            colorIdx++;
        }
        return list;
    }

    private static string Escape(string s) =>
        s.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "&quot;");

    private static string FormatSize(long bytes) =>
        bytes switch { < 1024 => $"{bytes}B", < 1048576 => $"{bytes / 1024.0:F1}KB", _ => $"{bytes / 1048576.0:F1}MB" };

    private sealed class Dataset
    {
        public string Name { get; init; } = "";
        public List<double> Values { get; init; } = new();
        public string Color { get; init; } = "#4B5EFC";
    }

    // ─── Chart CSS ───────────────────────────────────────────────────────

    private const string ChartCss = @"
/* Vertical Bar Chart */
.vbar-chart { margin: 16px 0; }
.vbar-bars { display: flex; align-items: flex-end; gap: 8px; height: 220px; padding: 0 8px; border-bottom: 2px solid #E5E7EB; }
.vbar-group { flex: 1; display: flex; gap: 3px; align-items: flex-end; position: relative; }
.vbar-bar { flex: 1; min-width: 18px; border-radius: 4px 4px 0 0; transition: opacity 0.2s; cursor: default; }
.vbar-bar:hover { opacity: 0.8; }
.vbar-label { text-align: center; font-size: 11px; color: #6B7280; margin-top: 6px; position: absolute; bottom: -24px; left: 0; right: 0; }

/* Horizontal Bar Chart */
.hbar-chart { margin: 12px 0; }
.hbar-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.hbar-label { min-width: 80px; text-align: right; font-size: 12px; color: #374151; font-weight: 500; }
.hbar-track { flex: 1; height: 22px; background: #F3F4F6; border-radius: 6px; overflow: hidden; }
.hbar-fill { height: 100%; border-radius: 6px; transition: width 0.6s ease; }
.hbar-value { min-width: 50px; font-size: 12px; color: #6B7280; font-weight: 600; }

/* Line/Area Chart */
.line-chart-svg { width: 100%; max-width: 600px; height: auto; }

/* Legend */
.chart-legend { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 12px; padding-top: 8px; border-top: 1px solid #F3F4F6; }
.legend-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: #374151; }
.legend-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }

/* Pie Legend */
.pie-legend { display: flex; flex-direction: column; gap: 6px; }
.pie-legend-item { display: flex; align-items: center; gap: 8px; font-size: 13px; color: #374151; }
";
}
