#if UNITY_EDITOR
namespace NiAkaDev.EzMirror.Editor
{
    using UnityEditor;
    using UnityEngine;

    public partial class EzMirrorEditor
    {
        private void DrawHealthCheck(EzMirror mirror)
        {
            EditorGUILayout.Space(8f);
            using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
            {
                EditorGUILayout.LabelField(
                    L("HealthCheckTitle", "Health Check"),
                    EditorStyles.boldLabel
                );

                EzMirrorValidationReport report = EzMirrorDistributionValidator.ValidateMirrors(
                    new[] { mirror }
                );
                AddSelectedDuplicatePersistKeyWarning(report, mirror);
                EzMirrorHealthState state = GetHealthState(report);
                bool ready = state == EzMirrorHealthState.Ready;
                DrawColoredStatusRow(
                    ready,
                    GetHealthStateTitle(state),
                    GetHealthStateHint(state)
                );
                DrawContextualHealthActions(report, mirror);

            }
        }

        private void DrawContextualHealthActions(EzMirrorValidationReport report, EzMirror mirror)
        {
            if (mirror == null)
                return;

            bool hasSwitchInputIssue = HasSwitchInputIssue(mirror);
            bool hasMissingPersistKey = mirror.usePersist && string.IsNullOrEmpty(mirror.persistKey);
            bool hasProfileArrayIssue = report != null && report.HasIssueCode("EZM004");
            bool hasMissingSfxSource = mirror.enableClickSound && mirror.sfxAudioSource == null;

            if (!hasSwitchInputIssue && !hasMissingPersistKey && !hasProfileArrayIssue && !hasMissingSfxSource)
                return;

            EditorGUILayout.Space(4f);
            using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
            {
                EditorGUILayout.HelpBox(
                    L("ContextualFixHelp", "不足している設定だけ、ここから安全に直せます。素材の掃除や強制再生成などの保守操作は開発者オプションにあります。"),
                    MessageType.Info
                );

                if (hasSwitchInputIssue && GUILayout.Button(L("FixMissingInputButton", "切替入力の不足を直す")))
                {
                    ApplyToTargets(EnsureInputControls, "Repair EzMirror Inputs");
                    GUIUtility.ExitGUI();
                }

                if (hasMissingPersistKey && GUILayout.Button(L("CreatePersistKeyButton", "保存キーを自動作成")))
                {
                    ApplyToTargets(
                        targetMirror => EzMirrorRepairUtility.GeneratePersistKeyForMirror(targetMirror, targets.Length == 1),
                        "Generate EzMirror Persist Key"
                    );
                    GUIUtility.ExitGUI();
                }

                if (hasProfileArrayIssue && GUILayout.Button(L("FixProfileArraysButton", "表示パターン設定をそろえる")))
                {
                    EnsureSerializedProfileArraySizes();
                    if (serializedObject.ApplyModifiedProperties())
                    {
                        CopyAllProxyValuesToUdon();
                        ApplyProfileMaterialParametersToTargets();
                        ApplyInputStateToTargets();
                    }
                    GUIUtility.ExitGUI();
                }

                if (hasMissingSfxSource && GUILayout.Button(L("AutoAssignAudioSourceButton", "AudioSourceを探して設定")))
                {
                    ApplyToTargets(AssignExistingSfxAudioSource, "Assign EzMirror AudioSource");
                    GUIUtility.ExitGUI();
                }
            }
        }

        private static bool HasSwitchInputIssue(EzMirror mirror)
        {
            if (mirror == null)
                return false;
            if (mirror.enableUguiInput && mirror.uiToggle == null)
                return true;
            if (
                mirror.enableInteractInput
                && (mirror.interactInputProxy == null || mirror.inputHitboxCollider == null)
            )
                return true;
            return mirror.enableContactInput && mirror.contactReceiver == null;
        }

        private static void AssignExistingSfxAudioSource(EzMirror mirror)
        {
            if (mirror == null || mirror.sfxAudioSource != null)
                return;
            mirror.sfxAudioSource = mirror.GetComponentInChildren<AudioSource>(true);
            if (mirror.sfxAudioSource == null)
                Debug.LogWarning("[EzMirror] AudioSource was not found under " + mirror.name + ".");
        }

        private static void AddSelectedDuplicatePersistKeyWarning(
            EzMirrorValidationReport report,
            EzMirror mirror
        )
        {
            if (report == null || !IsPersistKeyDuplicatedInLoadedScenes(mirror))
                return;

            report.AddWarning(
                "EZM006",
                GetMirrorLabel(mirror) + ": 保存キーが他のEzMirrorと重複しています: " + mirror.persistKey
            );
        }

        private static bool IsPersistKeyDuplicatedInLoadedScenes(EzMirror mirror)
        {
            if (mirror == null || !mirror.usePersist || string.IsNullOrEmpty(mirror.persistKey))
                return false;

            EzMirror[] mirrors = UnityEngine.Object.FindObjectsOfType<EzMirror>(true);
            for (int i = 0; i < mirrors.Length; i++)
            {
                EzMirror other = mirrors[i];
                if (other == null || other == mirror || !other.usePersist)
                    continue;
                if (other.persistKey == mirror.persistKey)
                    return true;
            }
            return false;
        }

        private static EzMirrorHealthState GetHealthState(EzMirrorValidationReport report)
        {
            if (report == null)
                return EzMirrorHealthState.BrokenReferences;
            if (report.Errors.Length > 0)
                return EzMirrorHealthState.BrokenReferences;
            if (report.HasWarningCode("EZM005"))
                return EzMirrorHealthState.MissingGeneratedMaterials;
            if (report.HasWarningCode("EZM006"))
                return EzMirrorHealthState.DuplicateSaveKey;
            if (report.HasWarningCode("EZM002") || report.HasWarningCode("EZM004"))
                return EzMirrorHealthState.NeedsSetup;
            return EzMirrorHealthState.Ready;
        }

        private static string GetMirrorLabel(EzMirror mirror)
        {
            return mirror == null ? "(null)" : mirror.name;
        }

        private static string GetHealthStateTitle(EzMirrorHealthState state)
        {
            switch (state)
            {
                case EzMirrorHealthState.BrokenReferences:
                    return L("HealthBrokenReferences", "Broken References");
                case EzMirrorHealthState.MissingGeneratedMaterials:
                    return L("HealthMissingGeneratedMaterials", "Missing Generated Materials");
                case EzMirrorHealthState.DuplicateSaveKey:
                    return L("HealthDuplicateSaveKey", "Duplicate Save Key");
                case EzMirrorHealthState.NeedsSetup:
                    return L("HealthNeedsSetup", "Needs Setup");
                default:
                    return L("HealthReady", "Ready");
            }
        }

        private static string GetHealthStateHint(EzMirrorHealthState state)
        {
            switch (state)
            {
                case EzMirrorHealthState.BrokenReferences:
                    return L("HealthBrokenReferencesHint", "Run basic setup or assign missing references.");
                case EzMirrorHealthState.MissingGeneratedMaterials:
                    return L("HealthMissingGeneratedMaterialsHint", "Regenerate profile materials at stable paths.");
                case EzMirrorHealthState.DuplicateSaveKey:
                    return L("HealthDuplicateSaveKeyHint", "Use a unique save key when local save is enabled.");
                case EzMirrorHealthState.NeedsSetup:
                    return L("HealthNeedsSetupHint", "Run setup and check optional input/profile settings.");
                default:
                    return L("HealthReadyHint", "No critical setup issues were found.");
            }
        }

        private void RepairHealthIssues(EzMirror mirror)
        {
            bool changed = EzMirrorRepairUtility.RepairSafeIssues(mirror);
            AssetDatabase.SaveAssets();
            serializedObject.Update();
            Debug.Log(
                changed
                    ? "[EzMirror] Safe repair completed."
                    : "[EzMirror] No safe repair target was found."
            );
        }

        private void RegenerateHealthMaterials(EzMirror mirror)
        {
            bool changed = EnsureDedicatedGeneratedProfileMaterials(mirror);
            AssetDatabase.SaveAssets();
            serializedObject.Update();
            Debug.Log(
                changed
                    ? "[EzMirror] Profile materials were regenerated or updated."
                    : "[EzMirror] Profile materials are already up to date."
            );
        }

        private static void LogHealthReport(EzMirrorValidationReport report)
        {
            if (report.Success && report.Warnings.Length == 0)
                Debug.Log(report.ToLogString());
            else if (report.Success)
                Debug.LogWarning(report.ToLogString());
            else
                Debug.LogError(report.ToLogString());
        }

        private static void OpenReadme()
        {
            TextAsset readme = AssetDatabase.LoadAssetAtPath<TextAsset>(
                EzMirrorPackageDefinition.ReadmePath
            );
            if (readme != null)
            {
                AssetDatabase.OpenAsset(readme);
                return;
            }
            EditorUtility.RevealInFinder(EzMirrorPackageDefinition.ReadmePath);
        }

        private enum EzMirrorHealthState
        {
            BrokenReferences,
            MissingGeneratedMaterials,
            DuplicateSaveKey,
            NeedsSetup,
            Ready
        }
    }
}
#endif
