using System.Collections.Generic;
using UnityEngine;

namespace AvatarRefinery.Editor.Core
{
    /// <summary>
    /// ルールに渡す診断コンテキスト。ルールは読み取り専用でなければならない(シーン・アセットを変更しない)。
    /// </summary>
    public sealed class RuleContext
    {
        /// <summary>診断対象のオリジナル(シーン上)。Issueのターゲットはこちらを指す。</summary>
        public GameObject AvatarRoot;

        /// <summary>NDMFでビルド後の姿にしたクローン(存在しない場合はnull)。性能算定・ビルド後の構造確認に使う。破棄はRunnerが行う。</summary>
        public GameObject BakedRoot;

        /// <summary>SDK統計(ベイク後 or オリジナル)。ルールから参照可能。nullならSDK無し。</summary>
        public PerfSnapshot Perf;
        public PerfSnapshot PerfPreBake;

        public bool HasVrcSdk, HasNdmf, HasModularAvatar, HasAao;

        /// <summary>NDMFベイク中に報告されたメッセージ(ベイクしていなければ空)</summary>
        public List<NdmfMessage> NdmfMessages = new List<NdmfMessage>();
        /// <summary>NDMFベイクを試みて失敗した理由(成功/未実施はnull)</summary>
        public string BakeError;

        public Transform Root => AvatarRoot != null ? AvatarRoot.transform : null;

        /// <summary>診断対象階層のコンポーネント列挙(非アクティブ含む)。EditorOnlyタグは対象外にしない(実際のアップロードではEditorOnlyは除去されるため、ルール側で判断)。</summary>
        public T[] GetAll<T>() where T : Component => AvatarRoot != null ? AvatarRoot.GetComponentsInChildren<T>(true) : new T[0];
    }

    /// <summary>診断ルールの契約。1ルール=1診断観点。</summary>
    public interface IRule
    {
        /// <summary>知識データのキー。"category.name" 形式。</summary>
        string Id { get; }

        /// <summary>実行前提(例: VRChat SDK必須)。満たさない場合は実行されない。</summary>
        bool CanRun(RuleContext ctx);

        /// <summary>問題を列挙する。何も無ければ空。例外はRunnerが捕捉し、レポートに記録する。</summary>
        IEnumerable<Issue> Evaluate(RuleContext ctx);
    }
}
