using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.Build;
using UnityEngine;
using UnityEngine.Rendering;

namespace Davanci.Nexus.Editor
{
    public enum DoctorStatus { Ok, Warning, Error }

    public class DoctorCheck
    {
        public string Title;
        public DoctorStatus Status;
        public string Message;
        public Action Fix;        // null when nothing to auto-fix
        public string FixLabel = "Fix";
    }

    // Project validator: scans common mobile build settings and offers one-click fixes.
    public static class NexusDoctor
    {
        public static List<DoctorCheck> RunAll()
        {
            var checks = new List<DoctorCheck>
            {
                CheckBuildTargetMobile(),
                CheckColorSpace(),
                CheckAndroidMinSdk(),
                CheckAndroidTargetSdk(),
                CheckAndroidIl2CppArm64(),
                CheckIosMinVersion(),
                CheckAndroidTextureCompression(),
                CheckStrippingLevel(),
                CheckNexusConfig(),
                CheckRemoteConfig(),
            };
            return checks;
        }

        public static void FixAll()
        {
            foreach (var c in RunAll())
                if (c.Status != DoctorStatus.Ok && c.Fix != null)
                    c.Fix();
            AssetDatabase.SaveAssets();
        }

        // Build-time SDK plumbing (CocoaPods / Gradle) that lives outside Player Settings.
        // These are the errors that only surface in Xcode/Android Studio, so we surface
        // them earlier, e.g. "'AppsFlyerLib.h' file not found".
        public static List<DoctorCheck> RunNativeChecks()
        {
            return new List<DoctorCheck>
            {
                CheckStaleDefines(),
                CheckExternalDependencyManager(),
                CheckIosPods(),
                CheckAndroidCloudSave(),
                CheckIap(),
                CheckNotifications(),
                CheckRetentionNotifications(),
            };
        }

        static DoctorCheck CheckNotifications()
        {
            const string title = "Push Notifications (Mobile Notifications)";

            var cfg = NexusConfig.Load();
            if (cfg == null || !cfg.requestNotifications)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = "Notification prompt is off. Enable it in Nexus Setup → Notifications if you need it.",
                    Fix = null,
                };

            if (NexusNotificationsInstaller.InstallInProgress)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Warning,
                    Message = "Installing Mobile Notifications…",
                    Fix = null,
                };

            if (!NexusNotificationsInstaller.Installed)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = "Request Notifications is on but com.unity.mobile.notifications isn't installed. The prompt will not run.",
                    Fix = () => NexusNotificationsInstaller.Install(),
                    FixLabel = "Install Mobile Notifications",
                };

            if (!NexusNotificationsInstaller.DefineSet)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Warning,
                    Message = "Mobile Notifications is installed but DAVANCI_NOTIFICATIONS is missing — permission code is compiled out.",
                    Fix = () => NexusNotificationsInstaller.SetDefine(true),
                    FixLabel = "Set define",
                };

            return new DoctorCheck
            {
                Title = title,
                Status = DoctorStatus.Ok,
                Message = "Mobile Notifications installed, DAVANCI_NOTIFICATIONS set. Retention copy is edited in Nexus Setup → Notifications.",
                Fix = null,
            };
        }

        static DoctorCheck CheckRetentionNotifications()
        {
            const string title = "Retention notifications (D1 / D3 / D7)";

            var cfg = NexusConfig.Load();
            if (cfg == null || !cfg.enableRetentionNotifications)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = "Retention reminders are off.",
                    Fix = null,
                };

            if (!cfg.requestNotifications)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Warning,
                    Message = "Retention is on but notification permission is off — reminders will never schedule.",
                    Fix = NexusSetupWindow.Open,
                    FixLabel = "Open Nexus Setup",
                };

            if (string.IsNullOrWhiteSpace(cfg.retentionD1Body)
                && string.IsNullOrWhiteSpace(cfg.retentionD3Body)
                && string.IsNullOrWhiteSpace(cfg.retentionD7Body))
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Warning,
                    Message = "Retention is on but all day messages are empty. Add title + message in Nexus Setup → Notifications.",
                    Fix = NexusSetupWindow.Open,
                    FixLabel = "Open Nexus Setup",
                };

            return new DoctorCheck
            {
                Title = title,
                Status = DoctorStatus.Ok,
                Message = $"Retention enabled — sends at {cfg.retentionSendHourLocal:00}:00 local on enabled days after the first session.",
                Fix = null,
            };
        }

        // In-app purchases run on Unity IAP (com.unity.purchasing). Surfaces package, catalog,
        // receipt-validation tangles, and common misconfigurations before a device build.
        static DoctorCheck CheckIap()
        {
            const string title = "In-App Purchases (Unity IAP)";

            var cfg = NexusConfig.Load();
            if (cfg == null || !cfg.enableIap)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = "IAP is off, nothing to check. Enable it in Nexus Setup → Monetization.",
                    Fix = null,
                };

            if (!NexusIapInstaller.Installed)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = "IAP is on but Unity IAP (com.unity.purchasing) isn't installed. Purchases will not work.",
                    Fix = () => NexusIapInstaller.Install(),
                    FixLabel = "Install Unity IAP",
                };

            if (!NexusIapInstaller.DefineSet)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Warning,
                    Message = "Unity IAP is installed but DAVANCI_IAP is missing — the real store provider is compiled out.",
                    Fix = () => NexusIapInstaller.SetDefine(true),
                    FixLabel = "Set define",
                };

            var products = cfg.iapProducts ?? new List<NexusProduct>();
            int total = products.Count;
            var empty = products.Where(p => p == null || string.IsNullOrWhiteSpace(p.id)).ToList();
            var valid = products.Where(p => p != null && !string.IsNullOrWhiteSpace(p.id)).Select(p => p.id.Trim()).ToList();
            var dupes = valid.GroupBy(id => id).Where(g => g.Count() > 1).Select(g => g.Key).ToList();

            if (total == 0)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = "No products in NexusConfig. Add your App Store / Play Console product IDs in Nexus Setup → Monetization.",
                    Fix = NexusSetupWindow.Open,
                    FixLabel = "Open Nexus Setup",
                };

            if (empty.Count > 0)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = $"{empty.Count} product row(s) have an empty ID. Fill every ID or remove the row.",
                    Fix = NexusSetupWindow.Open,
                    FixLabel = "Open Nexus Setup",
                };

            if (dupes.Count > 0)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Warning,
                    Message = $"Duplicate product ID(s): {string.Join(", ", dupes)}. Each store SKU must be unique.",
                    Fix = NexusSetupWindow.Open,
                    FixLabel = "Open Nexus Setup",
                };

            if (NexusIapInstaller.ValidationEnabled && !NexusIapValidationInstaller.AppleTanglePresent)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = "Receipt validation is on but AppleTangle.cs is missing. Enable IAP in Nexus Setup to auto-generate, or press Regenerate receipt tangles.",
                    Fix = NexusSetupWindow.Open,
                    FixLabel = "Open Nexus Setup",
                };

            if (!NexusUnityPurchasingServices.IsEnabled)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Warning,
                    Message = "Unity Services In-App Purchasing is off. Nexus enables it when IAP is on — re-toggle Enable IAP in Nexus Setup.",
                    Fix = () => NexusIapPipeline.SyncFromConfig(cfg),
                    FixLabel = "Sync IAP pipeline",
                };

            string tangleNote;
            if (NexusIapValidationInstaller.TanglesPresent)
            {
                var parts = new List<string>();
                if (NexusIapValidationInstaller.AppleTanglePresent) parts.Add("AppleTangle");
                if (NexusIapValidationInstaller.GoogleTanglePresent) parts.Add("GooglePlayTangle");
                tangleNote = NexusIapInstaller.ValidationEnabled
                    ? $"Receipt validation on ({string.Join(" + ", parts)})."
                    : $"Tangle files found ({string.Join(", ", parts)}) but validation is off — enable in Nexus Setup for production.";
            }
            else
            {
                tangleNote = "Receipt validation off — enable IAP in Nexus Setup to auto-generate AppleTangle.";
            }

            string editorNote = "";
#if UNITY_EDITOR
            if (cfg.iapUseRealStoreInEditor)
                editorNote = " Editor uses the real store (experimental).";
            else
                editorNote = " Editor uses the fake store — test purchases on device.";
#endif

            var status = NexusIapInstaller.ValidationEnabled || NexusIapValidationInstaller.AppleTanglePresent
                ? DoctorStatus.Ok
                : DoctorStatus.Warning;

            string androidNote = "";
            if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android &&
                string.IsNullOrWhiteSpace(cfg.googlePlayLicensingKey) &&
                !NexusIapValidationInstaller.GoogleTanglePresent)
            {
                status = DoctorStatus.Warning;
                androidNote = " Paste Google Play licensing key in Nexus Setup for Android receipt validation.";
            }

            return new DoctorCheck
            {
                Title = title,
                Status = status,
                Message = $"Unity IAP ready — {valid.Count} product(s): {string.Join(", ", valid)}. {tangleNote}{editorNote}{androidNote}",
                Fix = !NexusIapInstaller.ValidationEnabled && NexusIapValidationInstaller.TanglesPresent
                    ? (Action)(() => NexusIapInstaller.SetValidation(true))
                    : null,
                FixLabel = "Enable receipt validation",
            };
        }

        static DoctorCheck CheckStaleDefines()
        {
            const string title = "SDK define symbols";
            var stale = NexusInstaller.StaleDefineSdks()
                .Select(s => s.Define)
                .Distinct()
                .ToList();

            if (stale.Count == 0)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = "Scripting defines match installed SDKs.",
                    Fix = null,
                };

            return new DoctorCheck
            {
                Title = title,
                Status = DoctorStatus.Error,
                Message = "SDK plugin(s) were removed but scripting defines remain (" +
                          string.Join(", ", stale) + "). Nexus will not compile until these are cleared.",
                Fix = () => NexusInstaller.SyncDefines(),
                FixLabel = "Clear stale defines",
            };
        }

        static DoctorCheck CheckAndroidCloudSave()
        {
            const string title = "Android Cloud Save (Google Play Games)";

            var cfg = NexusConfig.Load();
            if (cfg == null || !cfg.enableCloudSave)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = "Cloud Save is off, nothing to check. Enable it in Nexus Setup → Cloud Save.",
                    Fix = null,
                };

            if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = "n/a. Switch to Android to check the Play Games cloud slot.",
                    Fix = null,
                };

            var gpgs = NexusInstaller.Sdks.FirstOrDefault(s => s.Id == "gpgs");
            bool installed = gpgs != null && gpgs.IsInstalled;
            bool defined = NexusInstaller.HasDefine("DAVANCI_GPGS");

            if (!installed)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = "Cloud Save is on but the Google Play Games plugin isn't installed, Android saves stay " +
                              "on-device only. Install it in Nexus Setup → Install SDKs, then finish Play Games setup.",
                    Fix = gpgs == null ? null : () => NexusInstaller.Import(gpgs),
                    FixLabel = "Install Play Games",
                };

            if (!defined)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Warning,
                    Message = "Play Games plugin found but the DAVANCI_GPGS define is missing, the Android cloud " +
                              "provider is compiled out. Set the define, then rebuild.",
                    Fix = () => NexusInstaller.SetDefine("DAVANCI_GPGS", true),
                    FixLabel = "Set define",
                };

            if (!NexusGpgsSetup.IsConfigured)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Warning,
                    Message = "Play Games is installed but Android setup has not run yet. Paste your Play Console " +
                              "resources in Nexus Setup → Play Games and click Apply setup.",
                    Fix = NexusSetupWindow.Open,
                    FixLabel = "Open Nexus Setup",
                };

            return new DoctorCheck
            {
                Title = title,
                Status = DoctorStatus.Ok,
                Message = "Play Games installed, DAVANCI_GPGS set, and Android setup complete.",
                Fix = null,
            };
        }

        static DoctorCheck CheckExternalDependencyManager()
        {
            const string title = "External Dependency Manager (EDM4U)";

            var edm = NexusInstaller.Sdks.FirstOrDefault(s => s.Id == "edm");
            bool edmInstalled = edm != null && edm.IsInstalled;

            var installedNative = NexusInstaller.Sdks
                .Where(s => (s.Id == "appsflyer" || s.Id == "firebase") && s.IsInstalled)
                .Select(s => s.DisplayName)
                .ToList();

            if (installedNative.Count == 0)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = "Not needed yet. No SDK that requires native dependency resolution is installed.",
                    Fix = null,
                };

            if (edmInstalled)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = $"Installed. Resolves iOS (CocoaPods) and Android (Gradle) deps for {string.Join(", ", installedNative)}.",
                    Fix = null,
                };

            return new DoctorCheck
            {
                Title = title,
                Status = DoctorStatus.Error,
                Message = $"{string.Join(" & ", installedNative)} installed, but EDM4U is missing. " +
                          "Native pods/gradle libraries won't be resolved, this is what causes " +
                          "\"'AppsFlyerLib.h' file not found\" in Xcode. Install EDM4U, then rebuild.",
                Fix = () =>
                {
                    var pkg = NexusInstaller.Sdks.FirstOrDefault(s => s.Id == "edm");
                    if (pkg != null) NexusInstaller.Import(pkg);
                },
                FixLabel = "Install EDM4U",
            };
        }

        static DoctorCheck CheckIosPods()
        {
            const string title = "iOS CocoaPods resolution";

            bool anyNative = NexusInstaller.Sdks
                .Any(s => (s.Id == "appsflyer" || s.Id == "firebase") && s.IsInstalled);

            string buildPath = EditorPrefs.GetString(NexusPostBuildProcessor.LastIosBuildKey, "");
            bool haveBuild = !string.IsNullOrEmpty(buildPath) && Directory.Exists(buildPath);

            if (!haveBuild)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = anyNative
                        ? "No iOS build inspected yet. Build for iOS, then re-scan to confirm pods resolved."
                        : "No native iOS SDKs installed, CocoaPods not required.",
                    Fix = null,
                };

            bool hasPodfile  = File.Exists(Path.Combine(buildPath, "Podfile"));
            bool hasPods     = Directory.Exists(Path.Combine(buildPath, "Pods"));
            bool hasWorkspace = Directory.Exists(Path.Combine(buildPath, "Unity-iPhone.xcworkspace"));

            if (anyNative && !hasPodfile)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = "Last iOS build has no Podfile, EDM4U didn't add native dependencies. " +
                              "Run Assets → External Dependency Manager → iOS Resolver → Force Resolve, then rebuild.",
                    Fix = () => EditorApplication.ExecuteMenuItem(
                        "Assets/External Dependency Manager/iOS Resolver/Install Cocoapods Dependencies"),
                    FixLabel = "Force Resolve",
                };

            if (hasPodfile && !hasPods)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = $"Podfile found but no Pods/ folder, 'pod install' hasn't run in {buildPath}. " +
                              "Open the folder and run 'pod install' (install CocoaPods first if needed), then open the .xcworkspace.",
                    Fix = () => EditorUtility.RevealInFinder(buildPath),
                    FixLabel = "Open build folder",
                };

            if (hasPods && hasWorkspace)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = "Pods resolved. Important: open Unity-iPhone.xcworkspace (not .xcodeproj), " +
                              "the .xcodeproj alone omits the pods and triggers 'AppsFlyerLib.h not found'.",
                    Fix = null,
                };

            return new DoctorCheck
            {
                Title = title,
                Status = DoctorStatus.Ok,
                Message = "No CocoaPods issues detected in the last iOS build.",
                Fix = null,
            };
        }

        // Rendering, performance and build-size settings that make a mobile game leaner
        // and smoother. Each check self-suppresses to "n/a" when it doesn't apply to the
        // active build target, so the section stays quiet and relevant.
        public static List<DoctorCheck> RunPerformanceChecks()
        {
            return new List<DoctorCheck>
            {
                CheckGraphicsApis(),
                CheckMultithreadedRendering(),
                CheckGpuSkinning(),
                CheckAccelerometer(),
                CheckVSync(),
                CheckStripEngineCode(),
                CheckAndroidAppBundle(),
            };
        }

        static DoctorCheck CheckGraphicsApis()
        {
            const string title = "Graphics APIs";
            var t = EditorUserBuildSettings.activeBuildTarget;

            if (t == BuildTarget.Android)
            {
                var apis = PlayerSettings.GetGraphicsAPIs(BuildTarget.Android);
                bool hasVulkan = apis.Contains(GraphicsDeviceType.Vulkan);
                // Prefer Vulkan first for modern Android GPUs, keeping GLES3 as a fallback.
                bool ok = !PlayerSettings.GetUseDefaultGraphicsAPIs(BuildTarget.Android)
                          && hasVulkan && apis[0] == GraphicsDeviceType.Vulkan;
                return new DoctorCheck
                {
                    Title = title,
                    Status = ok ? DoctorStatus.Ok : DoctorStatus.Warning,
                    Message = ok ? "Vulkan (GLES3 fallback)"
                                 : "Prefer Vulkan for modern Android GPUs, with GLES3 as a fallback.",
                    Fix = ok ? (Action)null : () =>
                    {
                        PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.Android, false);
                        PlayerSettings.SetGraphicsAPIs(BuildTarget.Android,
                            new[] { GraphicsDeviceType.Vulkan, GraphicsDeviceType.OpenGLES3 });
                    },
                    FixLabel = "Vulkan + GLES3",
                };
            }

            // iOS only supports Metal on supported Unity versions, nothing to change.
            if (t == BuildTarget.iOS)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = "Metal is the only supported iOS graphics API.",
                    Fix = null,
                };

            return new DoctorCheck
            {
                Title = title,
                Status = DoctorStatus.Ok,
                Message = "n/a. Switch to Android or iOS to check graphics APIs.",
                Fix = null,
            };
        }

        static DoctorCheck CheckMultithreadedRendering()
        {
            var group = ActiveTargetGroup(out string label, out bool mobile);
            bool on = mobile && PlayerSettings.GetMobileMTRendering(group);
            return new DoctorCheck
            {
                Title = "Multithreaded rendering",
                Status = !mobile ? DoctorStatus.Ok : (on ? DoctorStatus.Ok : DoctorStatus.Warning),
                Message = !mobile ? "n/a. Set a mobile target to check."
                                  : (on ? $"Enabled ({label})"
                                        : $"Off ({label}), enable to move rendering off the main thread."),
                Fix = (!mobile || on) ? (Action)null : () => PlayerSettings.SetMobileMTRendering(group, true),
                FixLabel = "Enable",
            };
        }

        static DoctorCheck CheckGpuSkinning()
        {
            bool on = PlayerSettings.gpuSkinning;
            return new DoctorCheck
            {
                Title = "GPU skinning",
                Status = on ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = on ? "Enabled" : "Off, offload skinned-mesh deformation to the GPU.",
                Fix = on ? (Action)null : () => PlayerSettings.gpuSkinning = true,
                FixLabel = "Enable",
            };
        }

        static DoctorCheck CheckAccelerometer()
        {
            bool off = PlayerSettings.accelerometerFrequency == 0;
            return new DoctorCheck
            {
                Title = "Accelerometer polling",
                Status = off ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = off ? "Disabled" : $"{PlayerSettings.accelerometerFrequency} Hz, disable if you don't read the accelerometer; it costs battery.",
                Fix = off ? (Action)null : () => PlayerSettings.accelerometerFrequency = 0,
                FixLabel = "Disable",
            };
        }

        static DoctorCheck CheckVSync()
        {
            bool off = QualitySettings.vSyncCount == 0;
            return new DoctorCheck
            {
                Title = "VSync",
                Status = off ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = off ? "Off, Application.targetFrameRate controls the cap."
                              : "On, on mobile, turn VSync off and cap with Application.targetFrameRate instead.",
                Fix = off ? (Action)null : () => QualitySettings.vSyncCount = 0,
                FixLabel = "Turn off",
            };
        }

        static DoctorCheck CheckStripEngineCode()
        {
            var t = EditorUserBuildSettings.activeBuildTarget;
            if (t != BuildTarget.iOS && t != BuildTarget.Android)
                return new DoctorCheck
                {
                    Title = "Strip engine code",
                    Status = DoctorStatus.Ok,
                    Message = "n/a. Set a mobile target to check.",
                    Fix = null,
                };

            bool on = PlayerSettings.stripEngineCode;
            return new DoctorCheck
            {
                Title = "Strip engine code",
                Status = on ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = on ? "Enabled" : "Off, strip unused engine modules to shrink the build.",
                Fix = on ? (Action)null : () => PlayerSettings.stripEngineCode = true,
                FixLabel = "Enable",
            };
        }

        static DoctorCheck CheckAndroidAppBundle()
        {
            if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android)
                return new DoctorCheck
                {
                    Title = "Android App Bundle (AAB)",
                    Status = DoctorStatus.Ok,
                    Message = "n/a. Switch to Android to check.",
                    Fix = null,
                };

            bool aab = EditorUserBuildSettings.buildAppBundle;
            return new DoctorCheck
            {
                Title = "Android App Bundle (AAB)",
                Status = aab ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = aab ? "Building .aab" : "Building .apk, Google Play prefers .aab for smaller per-device downloads.",
                Fix = aab ? (Action)null : () => EditorUserBuildSettings.buildAppBundle = true,
                FixLabel = "Build AAB",
            };
        }

        static NamedBuildTarget ActiveTargetGroup(out string label, out bool mobile)
        {
            var t = EditorUserBuildSettings.activeBuildTarget;
            if (t == BuildTarget.Android) { label = "Android"; mobile = true; return NamedBuildTarget.Android; }
            if (t == BuildTarget.iOS)     { label = "iOS";     mobile = true; return NamedBuildTarget.iOS; }
            label = t.ToString(); mobile = false; return NamedBuildTarget.Standalone;
        }

        static DoctorCheck CheckBuildTargetMobile()
        {
            var t = EditorUserBuildSettings.activeBuildTarget;
            bool mobile = t == BuildTarget.iOS || t == BuildTarget.Android;
            return new DoctorCheck
            {
                Title = "Active build target",
                Status = mobile ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = mobile ? $"{t}" : $"{t}, switch to iOS or Android for mobile analytics builds.",
                Fix = null,
            };
        }

        static DoctorCheck CheckColorSpace()
        {
            bool linear = PlayerSettings.colorSpace == ColorSpace.Linear;
            return new DoctorCheck
            {
                Title = "Color space",
                Status = linear ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = linear ? "Linear" : "Gamma, Linear is recommended for modern mobile rendering.",
                Fix = linear ? (Action)null : () => PlayerSettings.colorSpace = ColorSpace.Linear,
                FixLabel = "Set Linear",
            };
        }

        static DoctorCheck CheckAndroidMinSdk()
        {
            var min = PlayerSettings.Android.minSdkVersion;
            bool ok = (int)min >= 25;
            return new DoctorCheck
            {
                Title = "Android min SDK",
                Status = ok ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = ok ? $"API {(int)min}" : $"API {(int)min}, Firebase/AppsFlyer want API 25+.",
                Fix = ok ? (Action)null : () => PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel25,
                FixLabel = "Set API 25",
            };
        }

        static DoctorCheck CheckAndroidTargetSdk()
        {
            var target = PlayerSettings.Android.targetSdkVersion;
            // Auto = uses highest installed; Play currently requires API 34+.
            bool ok = target == AndroidSdkVersions.AndroidApiLevelAuto || (int)target >= 34;
            return new DoctorCheck
            {
                Title = "Android target SDK",
                Status = ok ? DoctorStatus.Ok : DoctorStatus.Error,
                Message = ok ? (target == AndroidSdkVersions.AndroidApiLevelAuto ? "Auto (highest installed)" : $"API {(int)target}")
                             : $"API {(int)target}, Google Play requires API 34+.",
                Fix = ok ? (Action)null : () => PlayerSettings.Android.targetSdkVersion = AndroidSdkVersions.AndroidApiLevelAuto,
                FixLabel = "Set Auto",
            };
        }

        static DoctorCheck CheckAndroidIl2CppArm64()
        {
            var backend = PlayerSettings.GetScriptingBackend(NamedBuildTarget.Android);
            bool il2cpp = backend == ScriptingImplementation.IL2CPP;
            bool arm64 = (PlayerSettings.Android.targetArchitectures & AndroidArchitecture.ARM64) != 0;
            bool ok = il2cpp && arm64;
            return new DoctorCheck
            {
                Title = "Android 64-bit (IL2CPP + ARM64)",
                Status = ok ? DoctorStatus.Ok : DoctorStatus.Error,
                Message = ok ? "IL2CPP + ARM64"
                             : "Google Play requires a 64-bit build (IL2CPP + ARM64).",
                Fix = ok ? (Action)null : () =>
                {
                    PlayerSettings.SetScriptingBackend(NamedBuildTarget.Android, ScriptingImplementation.IL2CPP);
                    PlayerSettings.Android.targetArchitectures |= AndroidArchitecture.ARM64;
                },
                FixLabel = "Enable",
            };
        }

        static DoctorCheck CheckIosMinVersion()
        {
            string raw = PlayerSettings.iOS.targetOSVersionString;
            float.TryParse(raw, System.Globalization.NumberStyles.Float,
                System.Globalization.CultureInfo.InvariantCulture, out float ver);
            bool ok = ver >= 13f;
            return new DoctorCheck
            {
                Title = "iOS minimum version",
                Status = ok ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = ok ? $"iOS {raw}" : $"iOS {raw}, Firebase/ATT need iOS 13+.",
                Fix = ok ? (Action)null : () => PlayerSettings.iOS.targetOSVersionString = "13.0",
                FixLabel = "Set 13.0",
            };
        }

        static DoctorCheck CheckAndroidTextureCompression()
        {
            var sub = EditorUserBuildSettings.androidBuildSubtarget;
            bool ok = sub == MobileTextureSubtarget.ASTC;
            return new DoctorCheck
            {
                Title = "Android texture compression",
                Status = ok ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = ok ? "ASTC" : $"{sub}, ASTC gives the best size/quality on modern devices.",
                Fix = ok ? (Action)null : () => EditorUserBuildSettings.androidBuildSubtarget = MobileTextureSubtarget.ASTC,
                FixLabel = "Use ASTC",
            };
        }

        static DoctorCheck CheckStrippingLevel()
        {
            var lvl = PlayerSettings.GetManagedStrippingLevel(NamedBuildTarget.Android);
            bool ok = lvl != ManagedStrippingLevel.Disabled;
            return new DoctorCheck
            {
                Title = "Managed code stripping (Android)",
                Status = ok ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = ok ? lvl.ToString() : "Disabled, enable stripping to reduce build size.",
                Fix = ok ? (Action)null : () => PlayerSettings.SetManagedStrippingLevel(NamedBuildTarget.Android, ManagedStrippingLevel.Low),
                FixLabel = "Set Low",
            };
        }

        // Remote Config is fetch-or-fallback, so a broken setup never crashes, it just
        // silently serves defaults forever. That is exactly what this surfaces.
        static DoctorCheck CheckRemoteConfig()
        {
            const string title = "Remote Config";

            var cfg = NexusConfig.Load();
            if (cfg == null)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = "n/a. No NexusConfig yet.",
                    Fix = null,
                };

            if (!cfg.enableRemoteConfig)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Ok,
                    Message = "Off. Get* calls return the defaults you pass and no request is made. " +
                              "Turn it on in Nexus Setup → Remote Config.",
                    Fix = null,
                };

            if (string.IsNullOrWhiteSpace(cfg.gameId))
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = "Enabled, but the Game ID is empty so no fetch ever runs and every key falls back " +
                              "to its default. Paste the Game ID from the game's dashboard page.",
                    Fix = NexusSetupWindow.Open,
                    FixLabel = "Open Nexus Setup",
                };

            // Realtime Database keys may not contain . $ # [ ] / — a Game ID carrying one
            // addresses a node that cannot exist, and the fetch 404s forever.
            int bad = cfg.gameId.Trim().IndexOfAny(new[] { '.', '$', '#', '[', ']', '/' });
            if (bad >= 0)
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = $"The Game ID contains '{cfg.gameId.Trim()[bad]}', which a Realtime Database key can't " +
                              "hold (. $ # [ ] / are all illegal). No such node can exist, so every fetch fails.",
                    Fix = NexusSetupWindow.Open,
                    FixLabel = "Open Nexus Setup",
                };

            string url = NexusRemoteConfig.BuildUrl(cfg);
            if (url == null || !Uri.IsWellFormedUriString(url, UriKind.Absolute))
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = $"The Game ID doesn't form a usable URL against {NexusRemoteConfig.DatabaseUrl}.",
                    Fix = NexusSetupWindow.Open,
                    FixLabel = "Open Nexus Setup",
                };

            string cached = NexusRemoteConfig.CachedPayload;
            if (string.IsNullOrEmpty(cached))
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Warning,
                    Message = $"Never fetched in this editor, so the round trip is unproven. Click Fetch now in " +
                              $"Nexus Setup → Remote Config to test {url}",
                    Fix = NexusSetupWindow.Open,
                    FixLabel = "Open Nexus Setup",
                };

            if (!NexusRemoteConfig.Validate(cached, out string error, out string summary))
                return new DoctorCheck
                {
                    Title = title,
                    Status = DoctorStatus.Error,
                    Message = $"The last payload doesn't match the schema ({error}). Clients ignore a payload like " +
                              "this and keep their previous values, so fix the publish on the dashboard and fetch again.",
                    Fix = NexusRemoteConfig.ClearCache,
                    FixLabel = "Clear cache",
                };

            var when = NexusRemoteConfig.LastFetchUtc;
            string age = when.HasValue ? DescribeAge(DateTime.UtcNow - when.Value) : "at an unknown time";
            return new DoctorCheck
            {
                Title = title,
                Status = DoctorStatus.Ok,
                Message = $"{summary}, fetched {age} for game \"{cfg.gameId.Trim()}\".",
                Fix = null,
            };
        }

        static string DescribeAge(TimeSpan span)
        {
            if (span.TotalMinutes < 1) return "just now";
            if (span.TotalHours < 1) return $"{(int)span.TotalMinutes} min ago";
            if (span.TotalDays < 1) return $"{(int)span.TotalHours} h ago";
            return $"{(int)span.TotalDays} day(s) ago";
        }

        static DoctorCheck CheckNexusConfig()
        {
            var cfg = NexusConfig.Load();
            bool ok = cfg != null;
            return new DoctorCheck
            {
                Title = "NexusConfig present",
                Status = ok ? DoctorStatus.Ok : DoctorStatus.Warning,
                Message = ok ? "Found in Resources" : "Missing, open the Configure step to create it.",
                Fix = null,
            };
        }
    }
}
