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

    internal static class EzMirrorAssetResolver
    {
        private const string TransBgMaterialGuid = "822dbd31008278e46a3a53f74a2ab802";
        private const string SharedBaseMaterialGuid = "9003ab218f73e424fa0c9ce0277462ff";
        private const string DummyBaseMaterialGuid = "5a6af5654580fcf40b549eb1054ebe93";
        private const string HqProfileAssetGuid = "dede3a7687a3a5b48bcf21cb49c2c958";
        private const string TransparentProfileAssetGuid = "ef8fed9137a3e6d4aa3837ba8c58ad47";
        private const string LqProfileAssetGuid = "5062c1184cd3ae445b1cf76a3c244977";
        private const string DefaultPrefabGuid = "167228cac58b81d44add4713d2f2594b";
        private const string MaterialsFolderGuid = "f026191518c565e408dd11e1ca59ca02";
        private const string GeneratedMaterialFolderGuid = "55dfd391411454c40bd2cfc5890c9ac8";
        private const string EditorPreviewMaterialGuid = "4878576b7f13da94485997861ffe490d";
        private const string ProfileAssetFolderGuid = "82aa86b47d0e02b4697ef217be0145c8";
        private const string DefaultLineIconGuid = "d60fb4b400cc89e47b10114d63917b0b";
        private const string DefaultSwitchModelGuid = "364dc4396262698409fe775080683e76";
        private const string DefaultSwitchAnimatorControllerGuid = "95a7b35db4c46294c98dc008de031fe1";
        private const string DefaultSwitchBaseMaterialGuid = "20524cd0b7e82ba46934972fb83974e0";
        private const string DefaultSwitchLampMaterialGuid = "286fe9571d334ba499e2a4e287eeb357";
        private const string DefaultSwitchButtonMaterialGuid = "103e4457f2f75ae438f5efe8012b98f5";

        private const string FallbackPackageRoot = "Packages/com.niaka.ezmirror";
        private const string FallbackGeneratedMaterialFolder =
            FallbackPackageRoot + "/Runtime/Materials/Generated";
        private const string FallbackProfileAssetFolder =
            FallbackPackageRoot + "/Runtime/Profiles";
        private const string FallbackIconFolder =
            FallbackPackageRoot + "/Runtime/Icons";
        private const string FallbackSwitchModelPath =
            FallbackPackageRoot + "/Runtime/Models/Hari_Switch.fbx";
        private const string FallbackSwitchAnimatorControllerPath =
            FallbackPackageRoot + "/Runtime/Animations/EzMirrorSwitch.controller";
        private const string FallbackSwitchBaseMaterialPath =
            FallbackPackageRoot + "/Runtime/Materials/Switch_Base.mat";
        private const string FallbackSwitchLampMaterialPath =
            FallbackPackageRoot + "/Runtime/Materials/SwitchLamp.mat";
        private const string FallbackSwitchButtonMaterialPath =
            FallbackPackageRoot + "/Runtime/Materials/Switch_Button.mat";
        private const string EditorPreviewMaterialFileName = "EzMirror_EditorPreview.mat";

        internal static Material LoadTransBgMaterial()
        {
            return LoadRequired<Material>(TransBgMaterialGuid, "TransBG.mat");
        }

        internal static Material LoadSharedBaseMaterial()
        {
            return LoadRequired<Material>(SharedBaseMaterialGuid, "_MirrorParent.mat");
        }

        internal static Material LoadDummyBaseMaterial()
        {
            return LoadRequired<Material>(DummyBaseMaterialGuid, "DummyMaterial.mat");
        }

        internal static Material LoadDefaultBaseMaterialForProfile(int profileIndex)
        {
            return LoadSharedBaseMaterial();
        }

        internal static EzMirrorProfileAsset LoadDefaultProfileAsset(int profileIndex)
        {
            return AssetDatabase.LoadAssetAtPath<EzMirrorProfileAsset>(
                GetDefaultProfileAssetPath(profileIndex)
            );
        }

        internal static GameObject LoadDefaultPrefab()
        {
            return LoadRequired<GameObject>(DefaultPrefabGuid, "EzMirror.prefab");
        }

        internal static GameObject LoadDefaultSwitchModel()
        {
            return LoadByGuidOrPath<GameObject>(
                DefaultSwitchModelGuid,
                FallbackSwitchModelPath,
                "Hari_Switch.fbx"
            );
        }

        internal static RuntimeAnimatorController LoadDefaultSwitchAnimatorController()
        {
            return LoadByGuidOrPath<RuntimeAnimatorController>(
                DefaultSwitchAnimatorControllerGuid,
                FallbackSwitchAnimatorControllerPath,
                "EzMirrorSwitch.controller"
            );
        }

        internal static Material LoadDefaultSwitchBaseMaterial()
        {
            return LoadByGuidOrPath<Material>(
                DefaultSwitchBaseMaterialGuid,
                FallbackSwitchBaseMaterialPath,
                "Switch_Base.mat"
            );
        }

        internal static Material LoadDefaultSwitchLampMaterial()
        {
            return LoadByGuidOrPath<Material>(
                DefaultSwitchLampMaterialGuid,
                FallbackSwitchLampMaterialPath,
                "SwitchLamp.mat"
            );
        }

        internal static Material LoadDefaultSwitchButtonMaterial()
        {
            return LoadByGuidOrPath<Material>(
                DefaultSwitchButtonMaterialGuid,
                FallbackSwitchButtonMaterialPath,
                "Switch_Button.mat"
            );
        }

        internal static string GetPackageRootPathNoCreate()
        {
            string runtimeFolder = DeriveRuntimeFolder();
            if (!string.IsNullOrEmpty(runtimeFolder))
                return TrimLastPathSegment(runtimeFolder);

            return FallbackPackageRoot;
        }

        internal static Sprite LoadDefaultIconSprite(int profileIndex)
        {
            return LoadByGuidOrPath<Sprite>(
                DefaultLineIconGuid,
                GetDefaultIconPath(),
                GetDefaultIconFileName() + ".png"
            );
        }

        internal static string GetDefaultProfileAssetPath(int profileIndex)
        {
            string path = GetDefaultProfileAssetPathNoCreate(profileIndex);
            if (!string.IsNullOrEmpty(AssetDatabase.GUIDToAssetPath(GetDefaultProfileAssetGuid(profileIndex))))
                return path;

            EnsureFolder(GetProfileAssetFolder());
            return path;
        }

        internal static string GetDefaultProfileAssetPathNoCreate(int profileIndex)
        {
            string guid = GetDefaultProfileAssetGuid(profileIndex);
            string path = AssetDatabase.GUIDToAssetPath(guid);
            if (!string.IsNullOrEmpty(path))
                return path;

            return GetProfileAssetFolderPathNoCreate() + "/" + GetDefaultProfileAssetFileName(profileIndex);
        }

        internal static string GetGeneratedMaterialFolder()
        {
            string path = GetGeneratedMaterialFolderPathNoCreate();
            EnsureFolder(path);
            return path;
        }

        internal static string GetGeneratedMaterialFolderPathNoCreate()
        {
            string path = AssetDatabase.GUIDToAssetPath(GeneratedMaterialFolderGuid);
            if (string.IsNullOrEmpty(path))
                path = GetMaterialsFolder() + "/Generated";
            return path;
        }

        internal static string GetProfileAssetFolder()
        {
            string path = GetProfileAssetFolderPathNoCreate();
            EnsureFolder(path);
            return path;
        }

        internal static string GetProfileAssetFolderPathNoCreate()
        {
            string path = AssetDatabase.GUIDToAssetPath(ProfileAssetFolderGuid);
            if (string.IsNullOrEmpty(path))
            {
                string runtimeFolder = DeriveRuntimeFolder();
                if (!string.IsNullOrEmpty(runtimeFolder))
                    path = runtimeFolder + "/Profiles";
            }
            if (string.IsNullOrEmpty(path))
                path = FallbackProfileAssetFolder;
            return path;
        }

        internal static string GetEditorPreviewMaterialPath()
        {
            string path = AssetDatabase.GUIDToAssetPath(EditorPreviewMaterialGuid);
            if (!string.IsNullOrEmpty(path))
                return path;

            return GetGeneratedMaterialFolder() + "/" + EditorPreviewMaterialFileName;
        }

        internal static string GetEditorPreviewMaterialPathNoCreate()
        {
            string path = AssetDatabase.GUIDToAssetPath(EditorPreviewMaterialGuid);
            if (!string.IsNullOrEmpty(path))
                return path;

            return GetGeneratedMaterialFolderPathNoCreate() + "/" + EditorPreviewMaterialFileName;
        }

        internal static string GetGeneratedMaterialAssetName(string ownerKey, int profileIndex)
        {
            return "EzMirror_"
                + SanitizeOwnerKey(ownerKey)
                + "_P"
                + Mathf.Max(0, profileIndex).ToString("00", CultureInfo.InvariantCulture);
        }

        internal static string GetGeneratedMaterialPath(string ownerKey, int profileIndex)
        {
            return GetGeneratedMaterialFolder()
                + "/"
                + GetGeneratedMaterialAssetName(ownerKey, profileIndex)
                + ".mat";
        }

        internal static string GenerateProfileAssetPath(string fileName)
        {
            return AssetDatabase.GenerateUniqueAssetPath(
                GetProfileAssetFolder() + "/" + fileName + ".asset"
            );
        }

        internal static bool IsInGeneratedMaterialFolder(string path)
        {
            string folder = GetGeneratedMaterialFolder();
            return IsInFolder(path, folder);
        }

        internal static bool IsInGeneratedMaterialFolderNoCreate(string path)
        {
            string folder = GetGeneratedMaterialFolderPathNoCreate();
            return IsInFolder(path, folder);
        }

        internal static bool IsDummyBaseMaterial(Material material)
        {
            return HasGuid(material, DummyBaseMaterialGuid);
        }

        private static bool IsInFolder(string path, string folder)
        {
            return !string.IsNullOrEmpty(path)
                && !string.IsNullOrEmpty(folder)
                && path.StartsWith(folder + "/", System.StringComparison.Ordinal);
        }

        private static T LoadRequired<T>(string guid, string label)
            where T : Object
        {
            string path = AssetDatabase.GUIDToAssetPath(guid);
            if (string.IsNullOrEmpty(path))
            {
                Debug.LogError("[EzMirror] Required asset GUID is missing: " + label);
                return null;
            }

            T asset = AssetDatabase.LoadAssetAtPath<T>(path);
            if (asset == null)
            {
                Debug.LogError("[EzMirror] Required asset type mismatch: " + label + " at " + path);
                return null;
            }

            return asset;
        }

        private static T LoadByGuidOrPath<T>(string guid, string fallbackPath, string label)
            where T : Object
        {
            string path = AssetDatabase.GUIDToAssetPath(guid);
            if (string.IsNullOrEmpty(path))
                path = fallbackPath;

            T asset = string.IsNullOrEmpty(path) ? null : AssetDatabase.LoadAssetAtPath<T>(path);
            if (asset == null)
            {
                Debug.LogError("[EzMirror] Required asset is missing: " + label);
                return null;
            }

            return asset;
        }

        private static bool HasGuid(Object asset, string expectedGuid)
        {
            if (asset == null)
                return false;

            string path = AssetDatabase.GetAssetPath(asset);
            return !string.IsNullOrEmpty(path)
                && AssetDatabase.AssetPathToGUID(path) == expectedGuid;
        }

        private static string GetMaterialsFolder()
        {
            string path = AssetDatabase.GUIDToAssetPath(MaterialsFolderGuid);
            if (!string.IsNullOrEmpty(path))
                return path;

            string runtimeFolder = DeriveRuntimeFolder();
            if (!string.IsNullOrEmpty(runtimeFolder))
                return runtimeFolder + "/Materials";

            return TrimLastPathSegment(FallbackGeneratedMaterialFolder);
        }

        private static string DeriveRuntimeFolder()
        {
            string sharedBasePath = AssetDatabase.GUIDToAssetPath(SharedBaseMaterialGuid);
            string materialsFolder = TrimLastPathSegment(sharedBasePath);
            return TrimLastPathSegment(materialsFolder);
        }

        private static string TrimLastPathSegment(string path)
        {
            if (string.IsNullOrEmpty(path))
                return null;

            int slashIndex = path.LastIndexOf('/');
            if (slashIndex <= 0)
                return null;
            return path.Substring(0, slashIndex);
        }

        private static string GetDefaultProfileAssetGuid(int profileIndex)
        {
            switch (profileIndex)
            {
                case 1:
                    return HqProfileAssetGuid;
                case 2:
                    return TransparentProfileAssetGuid;
                case 3:
                    return LqProfileAssetGuid;
                default:
                    return HqProfileAssetGuid;
            }
        }

        private static string GetDefaultIconPath()
        {
            string runtimeFolder = DeriveRuntimeFolder();
            string iconFolder = string.IsNullOrEmpty(runtimeFolder)
                ? FallbackIconFolder
                : runtimeFolder + "/Icons";
            return iconFolder + "/" + GetDefaultIconFileName() + ".png";
        }

        private static string GetDefaultIconFileName()
        {
            return "EzMirror_Icon_Line_512";
        }

        private static string GetDefaultProfileAssetFileName(int profileIndex)
        {
            switch (profileIndex)
            {
                case 1:
                    return "HQMirror.asset";
                case 2:
                    return "TransparentMirror.asset";
                case 3:
                    return "LQMirror.asset";
                default:
                    return "HQMirror.asset";
            }
        }

        private static void EnsureFolder(string folder)
        {
            if (string.IsNullOrEmpty(folder) || AssetDatabase.IsValidFolder(folder))
                return;

            string[] parts = folder.Split('/');
            if (parts.Length == 0)
                return;

            string current = parts[0];
            for (int i = 1; i < parts.Length; i++)
            {
                string next = current + "/" + parts[i];
                if (!AssetDatabase.IsValidFolder(next))
                    AssetDatabase.CreateFolder(current, parts[i]);
                current = next;
            }
        }

        private static string SanitizeOwnerKey(string ownerKey)
        {
            if (string.IsNullOrEmpty(ownerKey))
                return "unknown";

            char[] chars = ownerKey.ToCharArray();
            for (int i = 0; i < chars.Length; i++)
            {
                char c = chars[i];
                bool safe =
                    (c >= '0' && c <= '9')
                    || (c >= 'a' && c <= 'z')
                    || (c >= 'A' && c <= 'Z')
                    || c == '-'
                    || c == '_';
                if (!safe)
                    chars[i] = '_';
            }
            return new string(chars);
        }
    }
}
#endif
