using System.Collections.Generic;

namespace AvatarRefinery.Editor.Core
{
    /// <summary>1ルール分の説明文。UIは「症状 → 検出 → 原因 → 影響 → 対応」の順で表示する。</summary>
    public sealed class Explanation
    {
        /// <summary>症状で書いた見出し(技術用語を先頭に置かない)</summary>
        public string Title;
        /// <summary>ユーザーが体験する症状</summary>
        public string Symptom;
        /// <summary>なぜ起きるか(1〜2文、専門用語には1行の翻訳)</summary>
        public string Cause;
        /// <summary>放置するとどうなるか(読者の体験で書く)</summary>
        public string Impact;
        /// <summary>直し方(手順)。Liteでは表示、有料版では自動修正の説明も兼ねる</summary>
        public string[] FixSteps;
        /// <summary>公式ドキュメント等へのリンク(詳細モードで表示)</summary>
        public string DocUrl;
        /// <summary>有料版で自動修正対象か</summary>
        public bool AutoFixable;
        /// <summary>意図的にそうしている可能性がある(「無視」を促す注記)</summary>
        public string MaybeIntentional;
    }

    /// <summary>
    /// 診断ルールID → 説明文。文言はコード変更なしで差し替えられるよう、ここに集約する。
    /// (v0.1は静的辞書。将来はScriptableObject/JSONへ外出し可能)
    /// </summary>
    public static class KnowledgeBase
    {
        public static Explanation Get(string ruleId)
        {
            var map = L10n.IsEnglish ? EnglishKnowledgeBase.Map : Map;
            return map.TryGetValue(ruleId, out var e) ? e : new Explanation
            {
                Title = ruleId,
                Symptom = L10n.T("(この項目の説明文はまだ用意されていません)", "(No explanation is available for this check yet.)"),
                Cause = "", Impact = "", FixSteps = new string[0]
            };
        }

        public static IEnumerable<string> AllIds => Map.Keys;

        private static readonly Dictionary<string, Explanation> Map = new Dictionary<string, Explanation>
        {
            // ------------------------------------------------------------------ 環境
            ["env.unity_version"] = new Explanation
            {
                Title = "Unityのバージョンが VRChat の対応バージョンではありません",
                Symptom = "アップロードに失敗する、またはアップロードできても VRChat 内でアバターが読み込まれないことがあります。",
                Cause = "VRChat は特定の Unity バージョン(現在は 2022.3.22f1)でのみコンテンツを受け付けます。",
                Impact = "新しすぎるバージョンで作ったアバターはサーバー側で拒否されるか、正しく表示されません。",
                FixSteps = new[]
                {
                    "Unity Hub で 2022.3.22f1 をインストールする(ダウンロードアーカイブから追加できます)",
                    "VCC / ALCOM からプロジェクトを 2022.3.22f1 で開き直す",
                    "他のバージョンで保存した場合は、開き直した後にエラーが出ていないか Console を確認する",
                },
                DocUrl = "https://creators.vrchat.com/sdk/upgrade/current-unity-version/",
            },
            ["env.sdk_missing"] = new Explanation
            {
                Title = "VRChat SDK が見つかりません(汎用診断モードで実行しました)",
                Symptom = "パフォーマンスランクや VRChat 固有の項目(Descriptor・表情・PhysBone 等)は診断できません。",
                Cause = "このプロジェクトに VRChat SDK(Avatars)が導入されていません。",
                Impact = "ジオメトリ・マテリアル・リグの一般的な診断のみを行っています。",
                FixSteps = new[]
                {
                    "VCC / ALCOM で「VRChat SDK - Avatars」をプロジェクトに追加する",
                    "追加後にもう一度診断すると、全項目が有効になります",
                },
                DocUrl = "https://vcc.docs.vrchat.com/",
            },
            ["env.sdk_version"] = new Explanation
            {
                Title = "VRChat SDK が古すぎます",
                Symptom = "SDK のビルド画面でアップロードがブロックされます。",
                Cause = "VRChat は古い SDK からのアップロードを受け付けません。",
                Impact = "SDK を更新するまでアップロードできません。",
                FixSteps = new[]
                {
                    "VCC / ALCOM のプロジェクト管理画面で VRChat SDK - Avatars を更新する",
                    "Unity を開き直し、Console のエラーを解消してからもう一度診断する",
                },
                DocUrl = "https://creators.vrchat.com/sdk/upgrade/",
            },
            ["env.legacy_dynamic_bone"] = new Explanation
            {
                Title = "古い揺れもの(Dynamic Bone)が残っています",
                Symptom = "SDK のビルド画面で警告が出る、または揺れものが VRChat 内で動きません。",
                Cause = "VRChat の揺れものは PhysBone に移行しており、Dynamic Bone はアップロード時に無視されます(SDK が自動変換を提案することもあります)。",
                Impact = "Dynamic Bone で設定した髪やスカートは VRChat 内で揺れません(PhysBone へ変換してください)。",
                FixSteps = new[]
                {
                    "VRChat SDK のビルド画面(VRChat SDK > Show Control Panel > Builder)で「Auto Fix」または変換ボタンを使う",
                    "変換後、Dynamic Bone コンポーネントが残っていないか確認する",
                    "揺れ方が変わった場合は PhysBone の設定(Pull / Spring / Stiffness)を調整する",
                },
                DocUrl = "https://creators.vrchat.com/avatars/avatar-dynamics/physbones/",
            },

            // ------------------------------------------------------------------ Descriptor / VRChat設定
            ["vrc.descriptor_missing"] = new Explanation
            {
                Title = "VRC Avatar Descriptor が付いていません(このままではアップロードできません)",
                Symptom = "SDK のビルド画面にアバターとして表示されず、アップロードの選択肢に出てきません。",
                Cause = "VRChat は「VRC Avatar Descriptor」というコンポーネントが付いたオブジェクトをアバターとして認識します。",
                Impact = "アップロード自体ができません。VRM や FBX を読み込んだ直後はこの状態です。",
                FixSteps = new[]
                {
                    "アバターのルート(一番上のオブジェクト)を選び、Inspector の Add Component から「VRC Avatar Descriptor」を追加する",
                    "View Position(視点位置)を目の高さに合わせる(Edit ボタンで球を目の間に置く)",
                    "LipSync(口パク)と Eye Look を設定する(この診断の別項目で確認できます)",
                },
                DocUrl = "https://creators.vrchat.com/avatars/creating-your-first-avatar/",
            },
            ["vrc.view_position"] = new Explanation
            {
                Title = "視点位置(View Position)が不自然な場所にあります",
                Symptom = "VRChat に入ると視点が床の中・体の外・頭のはるか上などになり、自分の体が見えない/巨大に見えることがあります。",
                Cause = "VRC Avatar Descriptor の View Position は「目の位置」を手動で設定する必要があり、初期値のままだと頭の位置と合いません。",
                Impact = "主な症状は自分の視点ですが、View Position の高さは Avatar Scaling(身長調整)の基準値としても使われます。極端な値は身長調整時の見え方にも影響します。",
                FixSteps = new[]
                {
                    "VRC Avatar Descriptor の View Position 横の「Edit」を押す",
                    "Scene ビューで灰色の球を両目の間・少し前(顔の表面より 3〜5cm 前)に移動する",
                    "「Return」で確定する",
                },
                DocUrl = "https://creators.vrchat.com/avatars/creating-your-first-avatar/",
                MaybeIntentional = "背の低い/高いアバター、頭が無いアバターでは意図的な場合があります。",
            },
            ["vrc.viseme_broken"] = new Explanation
            {
                Title = "口パク(リップシンク)の設定が壊れています",
                Symptom = "話しても口が動かない、または SDK のビルド画面で Viseme の警告が出ます。",
                Cause = "LipSync が「Viseme Blend Shape」モードなのに、顔メッシュが未指定、または指定した BlendShape 名がメッシュに存在しません。改変で顔メッシュを差し替えた後に起きやすい問題です。",
                Impact = "口が動かないだけで、アップロードは可能です。",
                FixSteps = new[]
                {
                    "VRC Avatar Descriptor > LipSync の Face Mesh に顔の SkinnedMeshRenderer を設定する",
                    "「Auto Detect!」を押して Viseme を自動割り当てする(vrc.v_aa 等の名前があれば自動で埋まります)",
                    "自動で埋まらない場合は各 Viseme に対応する BlendShape を手で選ぶ",
                },
                DocUrl = "https://creators.vrchat.com/avatars/creating-your-first-avatar/",
            },
            ["vrc.eyelook_broken"] = new Explanation
            {
                Title = "アイトラッキング(Eye Look)の設定に参照切れがあります",
                Symptom = "目が動かない、まばたきしない、または SDK のビルド画面で警告が出ます。",
                Cause = "Eye Look が有効なのに、目のボーンやまばたき用 BlendShape の参照が空、または存在しないものを指しています。",
                Impact = "目の自動追従・まばたきが無効になります。アップロードは可能です。",
                FixSteps = new[]
                {
                    "VRC Avatar Descriptor > Eye Look で Transforms(LeftEye / RightEye)に目のボーンを設定する",
                    "Eyelids を使う場合は Eyelid Mesh と Blink 用 BlendShape を選び直す",
                    "目を動かさない設計なら Eye Look を「Disable」にすると警告は消えます",
                },
                DocUrl = "https://creators.vrchat.com/avatars/",
                MaybeIntentional = "目が固定のデザインなら Eye Look を無効化するだけで問題ありません。",
            },
            ["vrc.expression_params_over"] = new Explanation
            {
                Title = "Expression Parameters の容量(256bit)を超えています",
                Symptom = "SDK のビルド画面でエラーになりアップロードできません。",
                Cause = "アバターの同期パラメータは合計 256bit まで(Bool=1、Int/Float=8)。衣装やギミックを足していくと超えやすくなります。",
                Impact = "アップロードできません。",
                FixSteps = new[]
                {
                    "Expression Parameters を開き、使っていないパラメータを削除する",
                    "同期不要なもの(自分だけ見えればよい演出等)は「Synced」のチェックを外す(容量に数えられなくなります)",
                    "Int を Bool 数個に分ける、Float を Int にするなど、型を見直す",
                    "Modular Avatar 等を使っている場合は、ツール側の生成分も合算されることに注意する",
                },
                DocUrl = "https://creators.vrchat.com/avatars/animator-parameters/",
                AutoFixable = true,
            },
            ["vrc.expression_refs_missing"] = new Explanation
            {
                Title = "Expression Menu / Parameters の設定が片方だけ、または空です",
                Symptom = "VRChat 内でメニュー(Expression Menu)を開いても何も出ない、または SDK が警告を出します。",
                Cause = "VRC Avatar Descriptor の Expressions は Menu と Parameters をセットで設定する必要があります。",
                Impact = "メニュー操作(表情・衣装切替など)が使えません。",
                FixSteps = new[]
                {
                    "VRC Avatar Descriptor > Expressions で「Customize」を押し、Menu と Parameters の両方にアセットを設定する",
                    "アセットが無い場合は Project ウィンドウで右クリック > Create > VRChat > Avatars > Expressions Menu / Parameters で作成する",
                    "Modular Avatar 等でメニューを生成している場合は、ビルド後に自動設定されるので無視して構いません",
                },
                DocUrl = "https://creators.vrchat.com/avatars/expression-menu-and-controls/",
                MaybeIntentional = "非破壊ツール(Modular Avatar 等)がビルド時に生成する構成では、この状態が正常です。",
            },
            ["vrc.fx_write_defaults_mixed"] = new Explanation
            {
                Title = "表情アニメーションの設定(Write Defaults)が混在しています",
                Symptom = "表情が戻らない、別の表情と混ざる、衣装トグルが効かないなど「アニメーションが正しく再生されない」症状が出ます。",
                Cause = "Write Defaults(=アニメーションしていない値を自動で初期値に戻す設定)が ON のステートと OFF のステートが混ざると、値の戻し方が食い違うことがあります。VRChat 公式はアバター全体で統一することを推奨しています(Additive レイヤーや Direct Blend Tree など ON が適切な例外もあります)。この診断は FX レイヤーのみを確認しています。",
                Impact = "表情や衣装切替の不具合のよくある原因の一つです。アップロードは可能です。",
                FixSteps = new[]
                {
                    "FX レイヤーの Animator Controller を開き、各ステートの Write Defaults を ON か OFF のどちらかに統一する(例外は使用ツールの説明書に従う)",
                    "統一先は、使っているギミックの説明書に従う(近年は OFF 統一が多数派。表情ツールによっては ON 前提のものもある)",
                    "Modular Avatar を使っている場合は、ツールが自動で揃える設定(Write Defaults の一致)を確認する",
                },
                DocUrl = "https://creators.vrchat.com/avatars/",
                MaybeIntentional = "混在させても動くよう設計されたギミック(Direct Blend Tree 等)もあります。表情や切替に問題が無ければ無視して構いません。",
            },
            ["vrc.missing_script"] = new Explanation
            {
                Title = "壊れたコンポーネント(Missing Script)が残っています(アップロードを止める可能性があります)",
                Symptom = "Inspector に「The associated script can not be loaded」と表示され、SDK のビルドがエラーになることがあります。",
                Cause = "元々付いていたスクリプト(古い Dynamic Bone、他ツールのコンポーネント等)がプロジェクトに存在しないため、参照だけが残っています。",
                Impact = "SDK によってはアップロードがブロックされます。参照先が本当に不要と確認できた場合は、消しても機能は失われません(既に動いていないため)。",
                FixSteps = new[]
                {
                    "まず、そのスクリプトが「導入し忘れたパッケージ」のものでないか確認する(アバターやギミックの説明書に必要パッケージが書かれています)。必要なら先に元のパッケージを導入する",
                    "不要と確認できたら、対象のオブジェクトを選び、Inspector で「Missing (Mono Script)」と表示されているコンポーネントの ⋮ から Remove Component を選ぶ",
                    "数が多い場合は VRChat SDK のビルド画面の「Auto Fix」や、Missing Script 一括削除ツールを使う",
                },
                DocUrl = "https://creators.vrchat.com/avatars/creating-your-first-avatar/",
                AutoFixable = true,
            },

            ["vrc.expression_blink_conflict"] = new Explanation
            {
                Title = "表情アニメーションがまばたきと競合しています(半目・白目になることがあります)",
                Symptom = "表情を出すと目が半分だけ閉じる、白目になる、まばたきが途中で止まる、といった症状が出ます。",
                Cause = "Eye Look の「まぶた(Eyelids)」に指定した BlendShape を、表情アニメーション(FX)も同時に動かしています。VRChat の自動まばたきと表情が同じ BlendShape を取り合うため、値が中途半端になります。",
                Impact = "見た目のみ。アップロードは可能です。表情ギミックを追加した後によく起きます。",
                FixSteps = new[]
                {
                    "表情のステートに VRC Animator Tracking Control を付け、Eyes & Eyelids を「Animation」にする(表情中は自動まばたきを止める。表情を戻すステートでは「Tracking」に戻す)",
                    "または、表情アニメーションからまばたき用 BlendShape のカーブを外す(全 BlendShape を 0 にする「リセット」系アニメーションに含まれていることが多い)",
                    "表情ツール(FaceEmo 等)を使っている場合は、ツール側の「まばたき制御」設定を確認する",
                },
                DocUrl = "https://creators.vrchat.com/avatars/state-behaviors/",
                MaybeIntentional = "表情ステートに Tracking Control(Eyes = Animation)を付けている場合、この診断は除外します。付けていない場合でも設計上問題なければ無視して構いません。",
            },
            ["vrc.expression_viseme_conflict"] = new Explanation
            {
                Title = "表情アニメーションが口パク(リップシンク)と競合しています",
                Symptom = "特定の表情のあいだ口が動かない、または口が半開きのまま固定されます。",
                Cause = "口パク(Viseme)用の BlendShape を、表情アニメーション(FX)も動かしています。リップシンクと表情が同じ BlendShape を取り合います。",
                Impact = "見た目のみ。アップロードは可能です。",
                FixSteps = new[]
                {
                    "口を閉じたい表情なら、ステートに VRC Animator Tracking Control を付けて Mouth & Jaw を「Animation」にする(戻すステートでは「Tracking」)",
                    "そうでなければ、表情アニメーションから Viseme 用 BlendShape(vrc.v_aa 等)のカーブを外す",
                },
                DocUrl = "https://creators.vrchat.com/avatars/state-behaviors/",
                MaybeIntentional = "口を固定したい表情(あくび・キス等)では意図的です。Tracking Control(Mouth = Animation)を付けていれば診断から除外されます。",
            },
            ["vrc.expression_menu_broken"] = new Explanation
            {
                Title = "Expression Menu に、押しても動かない項目があります(参照切れ)",
                Symptom = "VRChat 内でメニューの項目を押しても何も起きない、サブメニューが開かない。",
                Cause = "メニューの項目が指しているパラメータが Expression Parameters に無い、またはサブメニューが未設定です。衣装・ギミックの導入時にパラメータの追加を忘れた場合や、名前の変更後によく起きます。",
                Impact = "その項目だけ機能しません。アップロードは可能です。",
                FixSteps = new[]
                {
                    "「検出」欄の項目を Expression Menu アセットで開き、Parameter のプルダウンから正しいパラメータを選び直す",
                    "パラメータ自体が無い場合は Expression Parameters に追加する(名前・型をギミックの説明書に合わせる)",
                    "Modular Avatar 等でメニューを生成している場合は、ビルド後の状態で判定しています。ツール側の設定(MA Menu Item / MA Parameters)を確認してください",
                },
                DocUrl = "https://creators.vrchat.com/avatars/expression-menu-and-controls/",
            },
            ["vrc.physbone_invalid"] = new Explanation
            {
                Title = "PhysBone の設定に無効な箇所があります",
                Symptom = "揺れものが動かない、意図しないボーンが揺れる、SDK が警告を出す、ランクの PhysBone 数だけ無駄に消費する、といった症状です。",
                Cause = "Root Transform がアバター外を指している / 揺れる対象の子ボーンが無い / Colliders や Ignore Transforms に空欄がある / 2 つの PhysBone が同じボーンを動かそうとしている(重なり)、のいずれかです。",
                Impact = "重なりは挙動が不安定になり、空の PhysBone はランクの PhysBone 数を無駄に消費します。アップロードは概ね可能です。",
                FixSteps = new[]
                {
                    "対象を選択し、Inspector の PhysBone を確認する: Root Transform を正しいボーンにする / 空欄(None)の要素は「−」で削除する",
                    "揺れる対象が無い PhysBone は削除する(または Endpoint Position を設定する)",
                    "重なっている場合は、片方の Ignore Transforms にもう片方の Root を入れるか、PhysBone を 1 つにまとめる",
                },
                DocUrl = "https://creators.vrchat.com/avatars/avatar-dynamics/physbones/",
                MaybeIntentional = "重なりは意図的に多段で揺らす設計の場合もあります。動きに問題がなければ無視して構いません。",
            },

            // ------------------------------------------------------------------ マテリアル / テクスチャ
            ["material.missing_shader"] = new Explanation
            {
                Title = "マテリアルがピンク色(シェーダー無し)で表示されます",
                Symptom = "アバターの一部または全体が真っピンクになります。",
                Cause = "マテリアルが使うシェーダー(lilToon / Poiyomi 等)がプロジェクトに入っていない、または読み込み順の問題でシェーダーが見つかりません。シェーダーのコンパイルエラー、Built-in / URP の不一致、Android(Quest)非対応のシェーダーでも同じ表示になります。",
                Impact = "そのままアップロードすると VRChat 内でもピンクのままです。",
                FixSteps = new[]
                {
                    "対象のマテリアルを選び、Inspector 上部の Shader が「Hidden/InternalErrorShader」や「Missing」になっていないか確認する",
                    "アバターの説明書にあるシェーダー(多くは lilToon)を先に導入し、その後アバター本体を再インポートする",
                    "それでも直らない場合は、マテリアルの Shader ドロップダウンから正しいシェーダーを選び直す",
                },
                DocUrl = "https://lilxyzw.github.io/lilToon/",
            },
            ["material.slot_empty"] = new Explanation
            {
                Title = "マテリアルが設定されていない部分があります(表示されない/ピンクになる)",
                Symptom = "その部分がピンク、または透明になります。",
                Cause = "Renderer のマテリアルスロットが空(None)です。マテリアルの差し替え中に消してしまった、またはインポート時に対応付けが失敗しています。",
                Impact = "見た目の欠けが VRChat 内でも起きます。",
                FixSteps = new[]
                {
                    "対象の Renderer を選び、Materials の空きスロットにマテリアルをドラッグする",
                    "どのマテリアルか分からない場合は、同じアバターの元プレハブ(Project ウィンドウ)を選んで Materials を見比べる",
                },
                DocUrl = "https://docs.unity3d.com/Manual/Materials.html",
            },
            ["texture.streaming_mipmaps_off"] = new Explanation
            {
                Title = "テクスチャの Streaming Mip Maps が無効です(SDK が警告/ブロックします)",
                Symptom = "SDK のビルド画面に「Enable Streaming Mip Maps」系の警告が出ます。",
                Cause = "VRChat は表示距離に応じてテクスチャの解像度を切り替える設定(Streaming Mip Maps)を全テクスチャで要求します。VRM や外部素材を読み込んだ直後は OFF のことがあります。",
                Impact = "警告のままではアップロードできない場合があります。ON にしても通常時の見た目はほぼ変わりません(メモリ不足時や遠距離では低い解像度が使われ、ぼやけて見えることがあります)。",
                FixSteps = new[]
                {
                    "SDK のビルド画面の「Auto Fix」を押す(全テクスチャに一括で設定されます)",
                    "手動の場合はテクスチャを選び、Inspector > Advanced > Streaming Mipmaps にチェックを入れて Apply",
                },
                DocUrl = "https://creators.vrchat.com/avatars/avatar-optimizing-tips/",
                AutoFixable = true,
            },
            ["texture.uncompressed"] = new Explanation
            {
                Title = "圧縮されていないテクスチャがあります(VRAM を大きく消費します)",
                Symptom = "パフォーマンスランクの「Texture Memory」が悪化し、Very Poor の原因になります。",
                Cause = "テクスチャのインポート設定が非圧縮(RGBA32 等)になっています。VRM から読み込んだ直後や、外部素材をそのまま使うとこの状態です。非圧縮は圧縮の 4〜8 倍のメモリを使います。",
                Impact = "他のプレイヤーの VRAM を余計に使い、ランクが下がります。Quest では表示されない原因にもなります。",
                FixSteps = new[]
                {
                    "テクスチャを選び、Inspector の Compression を「Normal Quality」にして Apply(プレビューで劣化を確認し、気になる素材だけ High Quality を検討)",
                    "Max Size を下げる(例: 2048 → 1024)のも効果が大きい。元ファイルは変わらないので、いつでも戻せます",
                    "注意: Crunch Compression はダウンロードサイズだけを減らし、Texture Memory(VRAM)は減りません",
                    "VRM を直接読み込んだ状態(テクスチャが .vrm 内蔵)では圧縮設定を変えられません。Project で .vrm を選び、Inspector の「Extract Textures」で画像を書き出してから設定します",
                    "多数ある場合は lilAvatarUtils 等の一括変更ツールが便利です",
                },
                DocUrl = "https://creators.vrchat.com/avatars/avatar-optimizing-tips/",
                AutoFixable = true,
            },
            ["texture.oversized"] = new Explanation
            {
                Title = "解像度の大きなテクスチャがあります(4096 以上)",
                Symptom = "Texture Memory が増え、ランクを下げる要因になります。",
                Cause = "4K テクスチャは 2K の 4 倍のメモリを使います。通常の交流距離では 2K との差が小さいことが多いですが、撮影用途や UV の密度によります。",
                Impact = "VRAM 消費とダウンロードサイズが増えます。",
                FixSteps = new[]
                {
                    "テクスチャを選び、Inspector の Max Size を 2048 にして Apply(元ファイルは変わらないので、いつでも戻せます)",
                    "顔・目など近くで見る部位だけ大きめに残す判断もあります",
                },
                DocUrl = "https://creators.vrchat.com/avatars/avatar-optimizing-tips/",
                AutoFixable = true,
                MaybeIntentional = "撮影用など高解像度が必要な用途では意図的な場合があります。",
            },

            // ------------------------------------------------------------------ リグ
            ["rig.animator_missing"] = new Explanation
            {
                Title = "Animator コンポーネントまたは Avatar 定義がありません",
                Symptom = "SDK にアバターとして認識されない、または T ポーズで固まります。",
                Cause = "アバターのルートに Animator が無い、または Animator の Avatar 欄が空です。",
                Impact = "アップロードできません。",
                FixSteps = new[]
                {
                    "ルートに Animator を追加し、Avatar 欄にモデルの Avatar 定義(FBX の子アセット)を設定する",
                    "FBX の Rig タブで Animation Type を Humanoid にして Apply すると Avatar が生成されます",
                },
                DocUrl = "https://creators.vrchat.com/avatars/creating-your-first-avatar/",
            },
            ["rig.not_humanoid"] = new Explanation
            {
                Title = "リグが Humanoid になっていません",
                Symptom = "SDK でエラーになる、または手足が動きません。",
                Cause = "FBX の Rig 設定が Generic/None のままです。VRChat のアバターは Humanoid が必須です。",
                Impact = "アップロードできません。",
                FixSteps = new[]
                {
                    "Project で FBX を選び、Inspector > Rig > Animation Type を Humanoid にして Apply",
                    "「Configure...」でボーンの対応付けにエラー(赤)が無いか確認する",
                },
                DocUrl = "https://creators.vrchat.com/avatars/creating-your-first-avatar/",
            },
            ["rig.bones_missing"] = new Explanation
            {
                Title = "Humanoid の必須ボーンが足りません",
                Symptom = "手や足が動かない、体が変形する、SDK でエラーになります。",
                Cause = "Humanoid の必須ボーン(腰・背骨・頭・上腕・前腕・手・太もも・すね・足)のいずれかが対応付けられていません。",
                Impact = "アップロードできない、または動きが破綻します。",
                FixSteps = new[]
                {
                    "FBX の Rig > Configure... で、赤くなっているボーンにモデル内の対応するボーンを割り当てる",
                    "元モデルにボーン自体が無い場合は、Blender 等でボーンを追加する必要があります",
                },
                DocUrl = "https://docs.unity3d.com/Manual/ConfiguringtheAvatar.html",
            },
            ["rig.no_fingers"] = new Explanation
            {
                Title = "指のボーンがありません(標準のハンドジェスチャーで指が動きません)",
                Symptom = "VRChat 内で手の形(ピース・グー等)が標準のジェスチャーでは変わりません。",
                Cause = "Humanoid の指ボーンが割り当てられていません(SDK3 では指ボーン無しのリグ自体は許容されます)。",
                Impact = "見た目のみ。アップロードは可能です。",
                FixSteps = new[]
                {
                    "モデルに指ボーンがあるなら、Rig > Configure... で Left/Right Hand の指に割り当てる",
                    "指ボーンが無いモデルはそういう仕様として使うのが一般的です(アニメーションや BlendShape で表現する方式もあります)",
                },
                DocUrl = "https://creators.vrchat.com/avatars/rig-requirements/",
                MaybeIntentional = "ローポリ・獣人など指の無いデザインや、別方式で手の形を表現しているアバターでは正常です。",
            },

            // ------------------------------------------------------------------ 描画
            ["render.anchor_override_mixed"] = new Explanation
            {
                Title = "体の一部だけ明るさが違って見えることがあります(Anchor Override が不統一)",
                Symptom = "顔だけ暗い、服の色が場所によって変わる、動くと明るさがチラつく、と他の人から見えることがあります。",
                Cause = "各メッシュが「どの位置のライト情報を基準にするか」(Anchor Override)がバラバラ、または未設定です。ワールドのライトの当たり方がメッシュごとに違って計算されます。",
                Impact = "見た目のみ。性能・ランクには影響しません。",
                FixSteps = new[]
                {
                    "全ての Renderer(SkinnedMeshRenderer / MeshRenderer)の Anchor Override に、同じ Transform(一般に Hips か Chest)を設定する",
                    "衣装を追加した時は、衣装側のメッシュにも同じ Anchor を設定する",
                    "Modular Avatar 等の一部ツールは自動で統一してくれます(ビルド後の姿で確認)",
                },
                DocUrl = "https://lilxyzw.github.io/matome/ja/avatar/optimization.html",
                AutoFixable = true,
            },
            ["render.bounds_abnormal"] = new Explanation
            {
                Title = "メッシュの表示範囲(Bounds)が異常です(視点によってメッシュが消える/常に描画される)",
                Symptom = "特定の角度で髪や服が消える、または画面外でも描画され続けて負荷が上がります。",
                Cause = "SkinnedMeshRenderer の Bounds(描画判定用の箱)が小さすぎる・大きすぎる・位置がずれています。改変やスケール変更後に起きやすい問題です。",
                Impact = "小さすぎると消える、大きすぎると無駄な描画負荷になります。",
                FixSteps = new[]
                {
                    "対象の SkinnedMeshRenderer の Bounds を、アニメーション時の最大の変形範囲を覆う最小限の大きさにする(目安: 中心=体の中央、サイズ=身長 × 1.5 程度。元プレハブの値と見比べる)",
                    "一律の値に変えると消失や過大描画の原因になるため、Scene ビューで動かして確認する",
                    "多くの改変ツールは Bounds を統一する機能を持っています(AAO の Trace and Optimize 等)",
                },
                DocUrl = "https://lilxyzw.github.io/matome/ja/avatar/optimization.html",
                AutoFixable = true,
            },
            ["render.mesh_missing"] = new Explanation
            {
                Title = "メッシュの参照が切れている Renderer があります",
                Symptom = "その部分が表示されず、Inspector の Mesh 欄が None です。",
                Cause = "元のメッシュアセットが削除・移動されたか、インポートに失敗しています。",
                Impact = "その部位が消えたままアップロードされます。",
                FixSteps = new[]
                {
                    "元の FBX/プレハブからメッシュを再設定するか、Renderer ごと削除する",
                    "不要な空 Renderer はランクの Skinned Mesh 数にも数えられるため、消した方が得です",
                },
                DocUrl = "https://docs.unity3d.com/Manual/class-SkinnedMeshRenderer.html",
            },

            // ------------------------------------------------------------------ パフォーマンス
            ["perf.pc"] = new Explanation
            {
                Title = "PC でのパフォーマンスランクを下げている項目があります",
                Symptom = "他のプレイヤーの設定(Avatar Performance 制限)によっては、あなたのアバターが表示されず代替表示(インポスター/ロボット)になります。",
                Cause = "VRChat は項目ごとの上限でランクを決め、最も悪い項目が全体ランクになります。1 項目でも Very Poor なら全体が Very Poor です。",
                Impact = "Poor またはそれより良いランクなら多くの環境で表示されます。Very Poor は「見せたい相手に見えない」リスクが高くなります。",
                FixSteps = new[]
                {
                    "この一覧の中で最もランクが悪い項目から直す(全体ランクは最悪の項目で決まるため)",
                    "テクスチャ: 圧縮・Max Size 縮小(見た目の劣化は小さい)",
                    "マテリアル/メッシュ数: AAO(Avatar Optimizer)の Trace and Optimize や TexTransTool でまとめる",
                    "PhysBone: 使っていない揺れものを減らす、Root を統合する",
                },
                DocUrl = "https://creators.vrchat.com/avatars/avatar-performance-ranking-system/",
            },
            ["perf.android"] = new Explanation
            {
                Title = "Quest / スマホ版でのランクを下げている項目があります",
                Symptom = "Quest やスマホのプレイヤーからは、Very Poor のアバターは既定で代替表示になります。さらに PhysBone・Contact・Constraint がモバイルの上限を超えている場合は、その種類のコンポーネントがまとめて削除されます。",
                Cause = "モバイル版は PC より大幅に厳しい上限(例: 三角形 20,000、テクスチャ 40MB、マテリアル 4)が適用されます。",
                Impact = "PC 版のアバターをそのまま Quest 対応にすると、ほぼ確実に Very Poor になります。個別に表示を許可してもらえる場合もありますが、将来 Very Poor の表示自体が廃止される可能性が公式に予告されています。",
                FixSteps = new[]
                {
                    "Quest 対応が不要なら、この項目は無視して構いません(PC 専用アバターとして扱われます)",
                    "Quest 対応するなら VRCQuestTools で変換し、テクスチャ縮小・メッシュ/マテリアル統合を行う",
                    "ダウンロードサイズ上限(10MB)にも注意する",
                },
                DocUrl = "https://creators.vrchat.com/platforms/android/quest-content-limitations/",
                MaybeIntentional = "PC 専用アバターなら無視して問題ありません。",
            },

            // ------------------------------------------------------------------ NDMF(非破壊ツール)
            ["ndmf.build_error"] = new Explanation
            {
                Title = "非破壊ツール(Modular Avatar / AAO 等)のビルド処理でエラーが報告されました",
                Symptom = "このままアップロードすると、ビルドが失敗するか、衣装やギミックが意図どおりに組み込まれない可能性があります。",
                Cause = "NDMF(非破壊改変の基盤)でアバターをビルドした際に、いずれかのツールがエラーを報告しました。参照先のオブジェクト・ボーンが見つからない、設定の不整合などが典型です。",
                Impact = "エラーの内容によります。「検出」欄のメッセージを確認してください。",
                FixSteps = new[]
                {
                    "「検出」欄のメッセージを読み、どのツール・どのオブジェクトの設定かを確認する",
                    "詳細は NDMF のコンソール(Tools > NDM Framework > Show error report)でも確認できます",
                    "そのツールの説明書に沿って設定を直し、もう一度診断する",
                },
                DocUrl = "https://modular-avatar.nadena.dev/ja/",
            },
            ["ndmf.build_warning"] = new Explanation
            {
                Title = "非破壊ツール(Modular Avatar / AAO 等)から注意メッセージがあります",
                Symptom = "ビルドは成功しますが、ツールが「意図と違うかもしれない設定」を見つけています。",
                Cause = "NDMF でのビルド中に、致命的でない警告が報告されました。",
                Impact = "多くの場合そのままでも動きますが、意図した結果になっているか確認してください。",
                FixSteps = new[]
                {
                    "「検出」欄のメッセージを確認し、心当たりがあれば該当ツールの設定を見直す",
                    "問題なければ無視して構いません",
                },
                DocUrl = "https://modular-avatar.nadena.dev/ja/",
                MaybeIntentional = "意図した設定であれば無視して構いません。",
            },

            // ------------------------------------------------------------------ VRM
            ["vrm.imported_state"] = new Explanation
            {
                Title = "VRM を読み込んだ直後の状態です(VRChat 向けの変換がまだです)",
                Symptom = "揺れものが動かない、Quest で表示されない、テクスチャメモリが大きい、表情メニューが無い、といった状態になります。",
                Cause = "VRM(VRoid Studio 等)のアバターは VRChat と仕様が異なります。SpringBone → PhysBone、MToon → VRChat 対応シェーダー、表情 → Expression Menu などの変換が必要です。",
                Impact = "VRC Avatar Descriptor などの必須設定を追加すればアップロード自体は可能ですが、変換していない機能(揺れもの・表情など)は動かず、ランクも低くなりがちです。",
                FixSteps = new[]
                {
                    "「VRM Converter for VRChat」等の変換ツールで一括変換する(SpringBone→PhysBone、表情、Viseme などをまとめて生成)",
                    "テクスチャを圧縮する(この診断の別項目を参照)",
                    "MToon のままでも PC では表示できますが、Quest 対応する場合は VRChat/Mobile 系シェーダーに変更する",
                },
                DocUrl = "https://vrm.dev/",
                MaybeIntentional = "既に手動で変換済みで、VRM のメタ情報だけ残している場合もあります。",
            },
        };
    }
}
