using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor.TestTools.TestRunner.Api;
using UnityEngine;
using UnityEngine.TestRunner.NUnitExtensions.Runner;
namespace UnityEditor.TestTools.TestRunner
{
    /// 
    /// Handles deserialization of TestSettings from a provided json file path.
    /// 
    internal class TestSettingsDeserializer : ITestSettingsDeserializer
    {
        private static readonly SettingsMap[] s_SettingsMapping =
        {
            new SettingsMap("scriptingBackend", (settings, value) => settings.scriptingBackend = value),
            new SettingsMap("architecture", (settings, value) => settings.Architecture = value),
            new SettingsMap("apiProfile", (settings, value) => settings.apiProfile = value),
            new SettingsMap("appleEnableAutomaticSigning", (settings, value) => settings.appleEnableAutomaticSigning = value),
            new SettingsMap("appleDeveloperTeamID", (settings, value) => settings.appleDeveloperTeamID = value),
            new SettingsMap("iOSManualProvisioningProfileType", (settings, value) => settings.iOSManualProvisioningProfileType = value),
            new SettingsMap("iOSManualProvisioningProfileID", (settings, value) => settings.iOSManualProvisioningProfileID = value),
            new SettingsMap("iOSTargetSDK", (settings, value) => settings.iOSTargetSDK = value),
            new SettingsMap("tvOSManualProvisioningProfileType", (settings, value) => settings.tvOSManualProvisioningProfileType = value),
            new SettingsMap("tvOSManualProvisioningProfileID", (settings, value) => settings.tvOSManualProvisioningProfileID = value),
            new SettingsMap("tvOSTargetSDK", (settings, value) => settings.tvOSTargetSDK = value),
            new SettingsMap("playerGraphicsAPI", (settings, value) =>
            {
                settings.autoGraphicsAPIs = false;
                settings.playerGraphicsAPIs = new[] {value};
            }),
            new SettingsMap("androidBuildAppBundle", (settings, value) =>
            {
                settings.androidBuildAppBundle = value;
            }),
            new SettingsMap>("ignoreTests", (settings, list) =>
            {
                settings.ignoreTests = list.Select(item =>
                {
                    var dictionary = (Dictionary)item;
                    if (dictionary.ContainsKey("test") && dictionary.ContainsKey("ignoreComment"))
                    {
                        return new IgnoreTest()
                        {
                            test = dictionary["test"] as string,
                            ignoreComment = dictionary["ignoreComment"] as string
                        };
                    }
                    throw new Exception("Wrong format for ignore test. Expected \"test\" and \"ignoreComment\".");
                }).ToArray();
            }),
            new SettingsMap>("featureFlags", (settings, dictionary) =>
            {
                var converted = dictionary.ToDictionary(pair => pair.Key, pair => (bool)pair.Value);
                var featureFlags = new FeatureFlags();
                if (converted.ContainsKey("fileCleanUpCheck"))
                {
                    featureFlags.fileCleanUpCheck = converted["fileCleanUpCheck"];
                }
                if (converted.ContainsKey("strictDomainReload"))
                {
                    featureFlags.strictDomainReload = converted["strictDomainReload"];
                }
                if (converted.ContainsKey("requiresSplashScreen"))
                {
                    featureFlags.requiresSplashScreen = converted["requiresSplashScreen"];
                }
                if (converted.ContainsKey("disableNestedEnumeratorBugfix"))
                {
                    featureFlags.disableNestedEnumeratorBugfix = converted["disableNestedEnumeratorBugfix"];
                }
                settings.featureFlags = featureFlags;
            }),
#if UNITY_2023_2_OR_NEWER
            new SettingsMap("webGLClientBrowserType", (settings, value) => settings.webGLClientBrowserType = value),
            new SettingsMap("webGLClientBrowserPath", (settings, value) => settings.webGLClientBrowserPath = value),
#endif
        };
        private readonly Func m_TestSettingsFactory;
        public TestSettingsDeserializer(Func testSettingsFactory)
        {
            m_TestSettingsFactory = testSettingsFactory;
        }
        public ITestSettings GetSettingsFromJsonFile(string jsonFilePath)
        {
            var text = File.ReadAllText(jsonFilePath);
            var settingsDictionary = Json.Deserialize(text) as Dictionary;
            var testSettings = m_TestSettingsFactory();
            if (settingsDictionary == null)
            {
                return testSettings;
            }
            foreach (var settingsMap in s_SettingsMapping)
            {
                if (!settingsDictionary.ContainsKey(settingsMap.Key))
                {
                    continue;
                }
                if (settingsMap.Type.IsEnum)
                {
                    SetEnumValue(settingsMap.Key, settingsDictionary[settingsMap.Key], settingsMap.Type, value => settingsMap.ApplyToSettings(testSettings, value));
                }
                else
                {
                    SetValue(settingsMap.Key, settingsDictionary[settingsMap.Key], settingsMap.Type, value => settingsMap.ApplyToSettings(testSettings, value));
                }
            }
            return testSettings;
        }
        private abstract class SettingsMap
        {
            public string Key { get; }
            public Type Type { get; }
            protected SettingsMap(string key, Type type)
            {
                Key = key;
                Type = type;
            }
            public abstract void ApplyToSettings(ITestSettings settings, object value);
        }
        private class SettingsMap : SettingsMap
        {
            private Action m_Setter;
            public SettingsMap(string key, Action setter) : base(key, typeof(T))
            {
                m_Setter = setter;
            }
            public override void ApplyToSettings(ITestSettings settings, object value)
            {
                m_Setter(settings, (T)value);
            }
        }
        private static void SetEnumValue(string key, object value, Type type, Action