using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using _Core;

namespace _Combo
{
    public class Reflector : Singleton<Reflector>
    {
        // Add a cache for module instances
        private Dictionary<Module, object> moduleCache = new Dictionary<Module, object>();

        public class ComboSDKModuleBuildInfo
        {
            public string dllName;
            public string className;

            public ComboSDKModuleBuildInfo(string dllName, string className)
            {
                this.dllName = dllName;
                this.className = className;
            }
        }

        private Dictionary<Module, ComboSDKModuleBuildInfo> moduleMapping = new Dictionary<Module, ComboSDKModuleBuildInfo>
        {
            { Module.SeayooAccount, new ComboSDKModuleBuildInfo("ComboSDK-SeayooAccount", "Seayoo.ComboSDK.Windows.Account.SeayooAccount")},
            { Module.SeayooStore, new ComboSDKModuleBuildInfo("ComboSDK_SeayooStore", "Seayoo.ComboSDK.Windows.Store.SeayooStore")},
            { Module.TapTap, new ComboSDKModuleBuildInfo("ComboSDK_TapTap", "Seayoo.ComboSDK.Windows.TapTap.TapTap")},
            { Module.Sentry, new ComboSDKModuleBuildInfo("ComboSDK", "Combo.Core.SentryTracking")},
            { Module.Lenovo, new ComboSDKModuleBuildInfo("ComboSDK_Lenovo", "Seayoo.ComboSDK.Windows.Lenovo.Lenovo")},
        };

        public T CreateModules<T>(Module module) where T : class
        {
            ComboSDKModuleBuildInfo moduleInfo = null;
            string dllName = "";
            string className = "";
            
            if (moduleMapping.TryGetValue(module, out moduleInfo))
            {
                dllName = moduleInfo.dllName;
                className = moduleInfo.className;
            }

            if (moduleCache.TryGetValue(module, out object instance) && instance is T)
            {
                return (T)instance;
            }

            Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == dllName);
            if (assembly == null)
            {
                Log.E($"Failed to find assembly: {dllName}");
                return default(T);
            }
            try
            {
                Type type = assembly.GetType(className);
                instance = Activator.CreateInstance(type) as T;

                // Cache the instance for future use
                moduleCache[module] = instance;

                return (T)instance;
            }
            catch (System.Exception e)
            {
                Log.E($"Failed to create module, message = {e.Message}");
                return default(T);
            }
        }
    }
}