using System.Linq;
using System.Text;
using AvatarRefinery.Editor.Core.Rules;

namespace AvatarRefinery.Editor.Core
{
    /// <summary>診断結果を人間向け Markdown に整形する(質問・依頼の添付、記録用)。</summary>
    public static class MarkdownReport
    {
        public static string SeverityLabel(Severity s)
        {
            switch (s)
            {
                case Severity.Blocker: return L10n.T("⛔ アップロードを止める問題", "⛔ Upload blocker");
                case Severity.Broken: return L10n.T("⚠ 見た目・動作がおかしくなる問題", "⚠ Broken appearance or behavior");
                case Severity.Performance: return L10n.T("📉 ランクを下げている項目", "📉 Performance regression");
                default: return L10n.T("ℹ 情報", "ℹ Information");
            }
        }
        public static string SeverityIcon(Severity s)
        {
            switch (s) { case Severity.Blocker: return "⛔"; case Severity.Broken: return "⚠"; case Severity.Performance: return "📉"; default: return "ℹ"; }
        }

        public static string Build(DiagnosisReport r, bool detailed = true)
        {
            var sb = new StringBuilder();
            sb.AppendLine(L10n.IsEnglish ? $"# Avatar Refinery Preflight Report: {r.AvatarName}" : $"# Avatar Refinery 診断レポート: {r.AvatarName}");
            sb.AppendLine();
            sb.AppendLine(L10n.IsEnglish ? $"- Date: {r.Timestamp:yyyy-MM-dd HH:mm}" : $"- 日時: {r.Timestamp:yyyy-MM-dd HH:mm}");
            sb.AppendLine(L10n.IsEnglish
                ? $"- Environment: Unity {r.UnityVersion} / VRChat SDK {r.SdkVersion} / NDMF {L10n.YesNo(r.HasNdmf)} / Modular Avatar {L10n.YesNo(r.HasModularAvatar)} / AAO {L10n.YesNo(r.HasAao)}"
                : $"- 環境: Unity {r.UnityVersion} / VRChat SDK {r.SdkVersion} / NDMF {L10n.YesNo(r.HasNdmf)} / Modular Avatar {L10n.YesNo(r.HasModularAvatar)} / AAO {L10n.YesNo(r.HasAao)}");
            sb.AppendLine(L10n.IsEnglish
                ? $"- Measurement: {(r.StatsFromBakedAvatar ? "performance measured from the built avatar after NDMF" : "performance measured from the Scene avatar")}{(string.IsNullOrEmpty(r.BakeError) ? "" : " (NDMF build failed: " + r.BakeError + ")")}"
                : $"- 診断方式: {(r.StatsFromBakedAvatar ? "ビルド後の姿(NDMF適用後)で性能を算定" : "シーン上の状態で算定")}{(string.IsNullOrEmpty(r.BakeError) ? "" : "(ベイク失敗: " + r.BakeError + ")")}");
            sb.AppendLine($"- Avatar Refinery {r.ToolVersion}");
            sb.AppendLine();

            sb.AppendLine(L10n.T("## 総合判定", "## Summary"));
            sb.AppendLine();
            sb.AppendLine(L10n.T("| プラットフォーム | ランク | 意味 |", "| Platform | Rank | What it means |"));
            sb.AppendLine($"|---|---|---|");
            sb.AppendLine($"| PC | **{PerformanceRule.JpRank(r.PcOverall)}** | {PcMeaning(r.PcOverall)} |");
            sb.AppendLine($"| {L10n.T("Quest / スマホ", "Quest / Mobile")} | **{PerformanceRule.JpRank(r.AndroidOverall)}** | {AndroidMeaning(r.AndroidOverall)} |");
            sb.AppendLine();
            sb.AppendLine($"- {SeverityLabel(Severity.Blocker)}: {r.Count(Severity.Blocker)}{L10n.T(" 件", "")}");
            sb.AppendLine($"- {SeverityLabel(Severity.Broken)}: {r.Count(Severity.Broken)}{L10n.T(" 件", "")}");
            sb.AppendLine($"- {SeverityLabel(Severity.Performance)}: {r.Count(Severity.Performance)}{L10n.T(" 件", "")}");
            sb.AppendLine($"- {SeverityLabel(Severity.Info)}: {r.Count(Severity.Info)}{L10n.T(" 件", "")}");
            sb.AppendLine();

            sb.AppendLine(L10n.T("## 問題一覧", "## Findings"));
            sb.AppendLine();
            if (r.Issues.Count == 0) sb.AppendLine(L10n.T("問題は見つかりませんでした。", "No problems found."));
            int n = 1;
            foreach (var issue in r.Sorted())
            {
                var k = KnowledgeBase.Get(issue.RuleId);
                sb.AppendLine($"### {n++}. {SeverityIcon(issue.Severity)} {issue.TitleOverride ?? k.Title}");
                sb.AppendLine();
                if (!string.IsNullOrEmpty(k.Symptom)) sb.AppendLine($"- {L10n.T("症状", "Symptom")}: {k.Symptom}");
                if (!string.IsNullOrEmpty(issue.Detail))
                {
                    if (issue.Detail.Contains("\n"))
                    {
                        // 複数行は同格の箇条書きとして同じインデントで出す(先頭の "- " の有無を正規化)
                        sb.AppendLine($"- {L10n.T("検出", "Detected")}:");
                        foreach (var raw in issue.Detail.Replace("\r", "").Split('\n'))
                        {
                            var line = raw.Trim();
                            if (line.Length == 0) continue;
                            if (line.StartsWith("- ")) line = line.Substring(2);
                            sb.AppendLine("  - " + line);
                        }
                    }
                    else sb.AppendLine($"- {L10n.T("検出", "Detected")}: {issue.Detail}");
                }
                if (detailed && !string.IsNullOrEmpty(k.Cause)) sb.AppendLine($"- {L10n.T("原因", "Cause")}: {k.Cause}");
                if (detailed && !string.IsNullOrEmpty(k.Impact)) sb.AppendLine($"- {L10n.T("影響", "Impact")}: {k.Impact}");
                if (k.FixSteps != null && k.FixSteps.Length > 0)
                {
                    sb.AppendLine($"- {L10n.T("対応", "What to do")}:");
                    for (int i = 0; i < k.FixSteps.Length; i++) sb.AppendLine($"  {i + 1}. {k.FixSteps[i]}");
                }
                if (!string.IsNullOrEmpty(issue.ExtraHint)) sb.AppendLine($"- {L10n.T("ヒント", "Tip")}: {issue.ExtraHint}");
                if (!string.IsNullOrEmpty(k.MaybeIntentional)) sb.AppendLine($"- {L10n.T("注記", "Note")}: {k.MaybeIntentional}");
                if (issue.TargetPaths.Count > 0) sb.AppendLine(L10n.IsEnglish
                    ? $"- Targets: {string.Join(", ", issue.TargetPaths.Take(10))}{(issue.TargetPaths.Count > 10 ? $" … ({issue.TargetPaths.Count} total)" : "")}"
                    : $"- 対象: {string.Join(", ", issue.TargetPaths.Take(10))}{(issue.TargetPaths.Count > 10 ? $" …(計 {issue.TargetPaths.Count})" : "")}");
                if (issue.AutoFixable) sb.AppendLine(L10n.T("- 自動修正: 対応可能(Avatar Refinery 製品版)", "- Automatic fix: supported by Avatar Refinery Pro"));
                if (detailed && !string.IsNullOrEmpty(k.DocUrl)) sb.AppendLine($"- {L10n.T("参考", "Reference")}: {k.DocUrl}");
                sb.AppendLine();
            }

            if (detailed && r.PerfCategories.Count > 0)
            {
                sb.AppendLine(L10n.T("## パフォーマンス内訳", "## Performance Details"));
                sb.AppendLine();
                bool showPre = r.PerfCategoriesPreBake.Count > 0 && r.StatsFromBakedAvatar;
                sb.AppendLine(showPre
                    ? L10n.T("| 項目 | 値(ビルド後) | シーン上 | PC | Quest |", "| Category | Built Value | Scene Value | PC | Quest |")
                    : L10n.T("| 項目 | 値 | PC | Quest |", "| Category | Value | PC | Quest |"));
                sb.AppendLine(showPre ? "|---|---|---|---|---|" : "|---|---|---|---|");
                foreach (var c in r.PerfCategories)
                {
                    if (string.IsNullOrEmpty(c.Value) && c.PcRating == "None") continue;
                    // 使っていない項目(0 / False で両方 Excellent)は省く
                    if ((c.Value == "0" || c.Value == "False") && c.PcRating == "Excellent" && c.AndroidRating == "Excellent") continue;
                    var pre = showPre ? r.PerfCategoriesPreBake.FirstOrDefault(p => p.Category == c.Category)?.Value ?? "" : null;
                    sb.AppendLine(showPre
                        ? $"| {PerformanceRule.JpCategory(c.Category)} | {c.Value} | {pre} | {PerformanceRule.JpRank(c.PcRating)} | {PerformanceRule.JpRank(c.AndroidRating)} |"
                        : $"| {PerformanceRule.JpCategory(c.Category)} | {c.Value} | {PerformanceRule.JpRank(c.PcRating)} | {PerformanceRule.JpRank(c.AndroidRating)} |");
                }
                sb.AppendLine();
            }

            if (detailed && r.NdmfMessages.Count > 0)
            {
                sb.AppendLine(L10n.T("## 非破壊ツール(NDMF)からのメッセージ", "## Messages from NDMF Tools"));
                sb.AppendLine();
                foreach (var m in r.NdmfMessages)
                {
                    var first = (m.Message ?? "").Replace("\r", "").Split('\n');
                    sb.AppendLine($"- [{m.Severity}] {first[0].Trim()}");
                    foreach (var extra in first.Skip(1)) if (!string.IsNullOrWhiteSpace(extra)) sb.AppendLine($"  {extra.Trim()}");
                }
                sb.AppendLine();
            }

            if (r.RuleErrors.Count > 0)
            {
                sb.AppendLine(L10n.T("## 診断ツールのエラー(不具合報告にご協力ください)", "## Internal Preflight-Check Errors (please include these in a bug report)"));
                foreach (var e in r.RuleErrors) sb.AppendLine($"- {e}");
                sb.AppendLine();
            }
            sb.AppendLine(L10n.IsEnglish
                ? $"_Processing time: build {r.BakeMs} ms / stats {r.StatsMs} ms / rules {r.RulesMs} ms_"
                : $"_処理時間: ベイク {r.BakeMs} ms / 統計 {r.StatsMs} ms / ルール {r.RulesMs} ms_");
            return sb.ToString();
        }

        public static string PcMeaning(string rank)
        {
            switch (rank)
            {
                case "Excellent": case "Good": return L10n.T("ほぼ全ての環境で表示されます", "Visible with most users' settings");
                case "Medium": return L10n.T("標準設定で表示されます", "Visible with the standard performance settings");
                case "Poor": return L10n.T("多くの環境で表示されますが、制限の厳しいインスタンスでは代替表示になることがあります", "Usually visible, but stricter settings may show an impostor or fallback");
                case "VeryPoor": return L10n.T("「Very Poor を非表示」設定の人には代替表示(インポスター)になります", "Users who hide Very Poor avatars will see an impostor or fallback");
                default: return L10n.T("算定できませんでした", "Could not calculate");
            }
        }
        public static string AndroidMeaning(string rank)
        {
            switch (rank)
            {
                case "Excellent": case "Good": case "Medium": return L10n.T("Quest / スマホの人にも表示されます", "Visible to Quest and mobile users");
                case "Poor": return L10n.T("Quest / スマホでは代替表示になることがあります", "Quest and mobile users may see an impostor or fallback");
                case "VeryPoor": return L10n.T("Quest / スマホでは既定で代替表示になります(個別に表示を許可される場合あり)。PC 専用アバターなら問題ありません", "Quest and mobile users see an impostor or fallback by default. This is acceptable for an intentionally PC-only avatar");
                default: return L10n.T("算定できませんでした", "Could not calculate");
            }
        }
    }
}
