/*
<copyright file="BGAssetLoaderManagerYooAsset.cs" company="BansheeGz">
    Copyright (c) 2018-2022 All Rights Reserved
</copyright>
*/

using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using YooAsset.Editor;
using Object = UnityEngine.Object;

namespace BansheeGz.BGDatabase.Editor
{
    public class BGAssetLoaderManagerYooAsset : BGAssetLoaderManagerA, BGAssetLoaderManagerA.UpdatableCache
    {
        private static readonly LocationsCacheI cache = new Cache();

        protected virtual LocationsCacheI MyCache => cache;

        public void Update() => MyCache.UpdateCache();

        public override T TryToLoad<T>(string location, BGAssetLoaderA loader)
        {
            if (string.IsNullOrEmpty(location)) return null;
            var path = MyCache.GetPath(location);
            if (path == null) return null;
            var result = AssetDatabase.LoadAssetAtPath<T>(path);
            return result;
        }

        public override T[] TryToLoadAll<T>(string location, BGAssetLoaderA loader)
        {
            if (string.IsNullOrEmpty(location)) return null;
            var path = MyCache.GetPath(location);
            var result = AssetDatabase.LoadAllAssetsAtPath(path);
            if (result == null || result.Length == 0) return null;
            var resultT = new List<T>();
            for (var i = 0; i < result.Length; i++)
            {
                var obj = result[i];
                if (!(obj is T t)) continue;
                resultT.Add(t);
            }

            return resultT.ToArray();
        }

        public override void ChosePath(BGAssetLoaderA loader, string extensions, Action<string> newPathAction)
        {
            BGEditorUtility.OpenFileInProject("Choose an asset", BGEditorPrefs.AssetDirectory, extensions, s =>
            {
                BGEditorPrefs.AssetDirectory = s;

                string location = null;
                var localPath = BGEditorUtility.GetRelativePath(s);
                if (localPath != null)
                {
                    localPath = localPath.Replace('\\', '/');
                    try
                    {
                        location = ResolvePath(localPath);
                    }
                    catch
                    {
                        //ignore
                    }
                }

                if (location == null)
                {
                    BGEditorUtility.ShowInfo(
                        "Error: can not find a location for this asset in YooAssets settings. If the setting exists, click on 'Update cache' button to update the locations cache");
                    return;
                }

                newPathAction(location);
                BGRepoWindow.RepaintInstance();
            });
        }

        public override string ResolvePath(BGAssetLoaderA assetLoader, Object obj) => ResolvePath(AssetDatabase.GetAssetPath(obj));

        private string ResolvePath(string path)
        {
            if (string.IsNullOrEmpty(path)) throw new Exception("Can not find a path for this asset");
            var myCache = MyCache;
            var location = myCache.GetLocation(path);
            if (location != null) return location;
            myCache.UpdateCache();
            location = myCache.GetLocation(path);
            if (location != null) return location;
            throw new Exception("Can not find location for this asset");
        }

        protected interface LocationsCacheI
        {
            void UpdateCache();
            string GetLocation(string path);
            string GetPath(string location);
        }

        private class Cache : LocationsCacheI
        {
            private readonly HashSet<string> availablePaths = new HashSet<string>();
            private bool initialized;

            public void UpdateCache()
            {
                initialized = true;
                availablePaths.Clear();
                try
                {
                    var assets = AssetBundleCollectorSettingData.Setting.GetAllCollectAssets(EBuildMode.SimulateBuild);
                    foreach (var asset in assets) availablePaths.Add(asset.AssetPath);
                }
                catch (Exception e)
                {
                    Debug.LogException(e);
                }
            }

            public string GetLocation(string path)
            {
                if (!initialized) UpdateCache();
                return availablePaths.Contains(path) ? path : null;
            }

            public string GetPath(string location) => GetLocation(location);
        }
    }
}