using System;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using Object = UnityEngine.Object;

namespace AvatarRefinery.Editor.Core
{
    /// <summary>
    /// バッチモード用の診断エントリ(開発時の自動検証・CI用。製品UIとは独立)。
    /// Unity.exe -batchmode -quit -projectPath ... -executeMethod AvatarRefinery.Editor.Core.BatchRunner.Run
    ///   -arAvatars "Assets/A.vrm;Assets/B.prefab" -arOut "<dir>"
    /// </summary>
    public static class BatchRunner
    {
        public static void Run()
        {
            var args = Environment.GetCommandLineArgs();
            string avatars = GetArg(args, "-arAvatars") ?? "";
            string outDir = GetArg(args, "-arOut") ?? Path.Combine(Path.GetDirectoryName(Application.dataPath) ?? ".", "AvatarRefinery_Reports");
            Directory.CreateDirectory(outDir);

            EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
            var index = new StringBuilder();
            index.AppendLine("# Avatar Refinery batch run");
            index.AppendLine($"date: {DateTime.Now:yyyy-MM-dd HH:mm:ss} unity: {Application.unityVersion}");
            int exit = 0;
            foreach (var raw in avatars.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
            {
                var p = raw.Trim();
                GameObject inst = null;
                try
                {
                    var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(p);
                    if (prefab == null) { index.AppendLine($"- {p}: NOT FOUND"); exit = 2; continue; }
                    inst = PrefabUtility.InstantiatePrefab(prefab) as GameObject ?? Object.Instantiate(prefab);
                    inst.name = Path.GetFileNameWithoutExtension(p);

                    // 開発用: -arAddDescriptor true で VRC Avatar Descriptor を付けて「最低限セットアップ済み」状態も検証する
                    if (GetArg(args, "-arAddDescriptor") == "true") TryAddDescriptor(inst);

                    var sw = System.Diagnostics.Stopwatch.StartNew();
                    var report = DiagnosisRunner.Run(inst);
                    var total = sw.ElapsedMilliseconds;

                    var md = MarkdownReport.Build(report, detailed: true);
                    var file = Path.Combine(outDir, SafeName(inst.name) + ".md");
                    File.WriteAllText(file, md, new UTF8Encoding(false));
                    index.AppendLine($"- {inst.name}: PC {report.PcOverall} / Android {report.AndroidOverall} | ⛔{report.Count(Severity.Blocker)} ⚠{report.Count(Severity.Broken)} 📉{report.Count(Severity.Performance)} ℹ{report.Count(Severity.Info)} | baked={report.StatsFromBakedAvatar} | {total} ms | errors={report.RuleErrors.Count} → {file}");
                    if (report.RuleErrors.Count > 0) { exit = Math.Max(exit, 1); foreach (var e in report.RuleErrors) index.AppendLine($"    - RULE ERROR: {e}"); }
                }
                catch (Exception e)
                {
                    index.AppendLine($"- {p}: EXCEPTION {e}");
                    exit = 3;
                }
                finally { if (inst != null) Object.DestroyImmediate(inst); }
            }
            var indexPath = Path.Combine(outDir, "INDEX.md");
            File.WriteAllText(indexPath, index.ToString(), new UTF8Encoding(false));
            Debug.Log("[AvatarRefinery] batch done\n" + index);
            if (Application.isBatchMode) EditorApplication.Exit(exit);
        }

        private static void TryAddDescriptor(GameObject root)
        {
#if AR_VRCSDK3_AVATARS
            if (root.GetComponent<VRC.SDK3.Avatars.Components.VRCAvatarDescriptor>() != null) return;
            var d = root.AddComponent<VRC.SDK3.Avatars.Components.VRCAvatarDescriptor>();
            var anim = root.GetComponent<Animator>();
            var head = anim != null && anim.isHuman ? anim.GetBoneTransform(HumanBodyBones.Head) : null;
            d.ViewPosition = head != null ? root.transform.InverseTransformPoint(head.position) + new Vector3(0, 0.06f, 0.1f) : new Vector3(0, 1.5f, 0.1f);
#endif
        }

        private static string GetArg(string[] args, string name)
        {
            for (int i = 0; i < args.Length - 1; i++) if (args[i] == name) return args[i + 1];
            return null;
        }
        private static string SafeName(string s) { foreach (var c in Path.GetInvalidFileNameChars()) s = s.Replace(c, '_'); return s; }
    }
}
