#if USING_ADDRESSABLES

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor;
using UnityEditor.AddressableAssets.Build;
using System.Collections.Generic;
using System.IO;
using Ionic.Zip;


namespace SimplifyXR
{


    /// <summary>
    /// Addressables Bridge Adapter for Editor Module Management
    /// </summary>
    public class AddressablesBridge : IModuleManager
    {

        const string moduleGroupName = "simpleAR Modules";
        private string archivePath
        {
            get
            {
                return Application.dataPath.Replace("/Assets", "/ModuleArchives");
            }
        }


        public AddressableAssetSettings Settings
        {
            get
            {
                var settings = AddressableAssetSettingsDefaultObject.Settings;
                if (settings == null) settings =
                         AddressableAssetSettingsDefaultObject.GetSettings(true);
                return settings;
            }
        }

        /// <summary>
        /// Sets the build path for the Asset Bundle catalog
        /// </summary>
        /// <param name="buildPath"></param>
        public void SetBuildPath(string buildPath)
        {

            buildPath = Application.dataPath.Replace("/Assets", $"/{buildPath}");

            Settings.profileSettings
            .SetValue(Settings.activeProfileId, "RemoteBuildPath",
            buildPath + "\\" + PlatformMappingService.GetPlatformPathSubFolder());

            var group = Settings.FindGroup(moduleGroupName);
            group.Settings.profileSettings
                .SetValue(group.Settings.activeProfileId, "RemoteBuildPath",
                buildPath + "\\" + PlatformMappingService.GetPlatformPathSubFolder());

        }

        /// <summary>
        /// Gets the build path for the addressables
        /// </summary>
        /// <returns></returns>
        public string GetRemoteBuildPath()
        {
            var group = Settings.FindGroup(moduleGroupName);
            return group.Settings.profileSettings
                .GetValueByName(group.Settings.activeProfileId, "RemoteBuildPath");
        }

        /// <summary>
        /// Gets the remote load path for the addressables
        /// </summary>
        /// <returns></returns>
        public string GetRemoteLoadPath()
        {
            var group = Settings.FindGroup(moduleGroupName);
            return group.Settings.profileSettings
                .GetValueByName(group.Settings.activeProfileId, "RemoteLoadPath");
        }


        /// <summary>
        /// Creates an archive folder with the build at the archive path
        /// </summary>
        public void CreateBuildArchive()
        {
            //return null;
            using (ZipFile zip = new ZipFile())
            {
                zip.AddDirectory(GetRemoteBuildPath());
                if (!Directory.Exists(archivePath)) Directory.CreateDirectory(archivePath);
                zip.Save(Path.Combine(archivePath, "modules.zip"));
            }

            //delete existing bundle files
            DirectoryInfo di = new DirectoryInfo(GetRemoteBuildPath());
            foreach (FileInfo file in di.GetFiles())
            {
                file.Delete();
            }
        }


        private void SetLocalLoadPath(string loadPath)
        {
            var group = Settings.FindGroup(moduleGroupName);
            group.Settings.profileSettings
                .SetValue(group.Settings.activeProfileId, "RemoteLoadPath",
                loadPath);
        }


        public void SetLoadPath(string loadPath)
        {

            Settings.profileSettings
                .SetValue(Settings.activeProfileId, "RemoteLoadPath", loadPath);

            var group = Settings.FindGroup(moduleGroupName);
            group.Settings.profileSettings
                .SetValue(group.Settings.activeProfileId, "RemoteLoadPath",
                loadPath);

        }

        /// <summary>
        /// Adds a given object to an addressable group
        /// </summary>
        /// <param name="moduleObject"></param>
        /// <returns></returns>
        string IModuleManager.SetAsModule(Object moduleObject)
        {
            return moduleObject.SetAddressableGroup(moduleGroupName);
        }


        /// <summary>
        /// Checks if the remote load path has changed since the last build
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        bool IModuleManager.LoadPathChanged(string path)
        {
            string contentStateDataPath = ContentUpdateScript.GetContentStateDataPath(false);

            return (!File.Exists(contentStateDataPath)
                || ContentUpdateScript.LoadContentState(contentStateDataPath).remoteCatalogLoadPath
                != GetRemoteLoadPath());
        }

        /// <summary>
        /// Updates a build's Asset Bundle catalog if one exists or creates a new one
        /// </summary>
        void IModuleManager.UpdateBuild()
        {


            SetBuildPath("simpleARModules");
            //SetLocalLoadPath(GetRemoteBuildPath());
            //var group = Settings.FindGroup(moduleGroupName);

            string contentStateDataPath = ContentUpdateScript.GetContentStateDataPath(false);
            if (!File.Exists(contentStateDataPath)
                || ContentUpdateScript.LoadContentState(contentStateDataPath).remoteCatalogLoadPath
                != GetRemoteLoadPath())

            {
                Settings.BuildRemoteCatalog = true;
                AddressableAssetSettings.CleanPlayerContent(
                Settings.ActivePlayerDataBuilder);
                //AddressableAssetSettings.CleanPlayerContent();
                AddressableAssetSettings.BuildPlayerContent();
            }
            else
            {
                ContentUpdateScript.BuildContentUpdate(Settings, contentStateDataPath);
            }
            CreateBuildArchive();
        }

        /// <summary>
        /// Removes a module given a key
        /// </summary>
        /// <param name="key"></param>
        public void RemoveModule(string key)
        {
            var group = Settings.FindGroup(moduleGroupName);
            List<AddressableAssetEntry> entries = new List<AddressableAssetEntry>();
            group.GatherAllAssets(entries, true, true, true);
            entries.ForEach(entry =>
            {
                if (entry.address == key) group.RemoveAssetEntry(entry);
            });
            //group.SetDirty(AddressableAssetSettings.ModificationEvent.EntryRemoved, entry, false, true);
            AssetDatabase.SaveAssets();
        }


        /// <summary>
        /// Checks if the module already exists
        /// </summary>
        /// <param name="moduleObject"></param>
        /// <returns></returns>
        public bool ModuleExists(Object moduleObject)
        {
            var assetpath = AssetDatabase.GetAssetPath(moduleObject);
            var guid = AssetDatabase.AssetPathToGUID(assetpath);
            var group = Settings.FindGroup(moduleGroupName);
            AddressableAssetEntry entry = group?.GetAssetEntry(guid);
            return entry != null;
        }


        /// <summary>
        /// Gets the key for the module's target platform
        /// Appends module upload mode for multi_environment Support
        /// </summary>
        /// <returns></returns>
        public string GetModulePlatform()
        {
            return PlatformMappingService.GetPlatformPathSubFolder() + 
                "_" + AppManagerModuleSetup.ModuleUploadMode.ToString();
        }


        /// <summary>
        /// Gets thee module archive path
        /// </summary>
        /// <returns></returns>
        public string GetModuleArchivePath()
        {
            return Path.Combine(archivePath, "modules.zip");
        }
    }


}

#endif



