﻿using System;
using System.Collections.Generic;
using System.IO;
using JLGames.RocketDriver.CSharp.Utils;
using JLGames.RocketDriver.Actions.Utils;
using UnityEngine;

namespace JLGames.RocketDriver.Actions.Loaderx
{
    public static class CacheInstance
    {
        public static readonly ILoaderCacheManager CacheManager = new LoaderCacheManager();
        public static readonly Hash128 EmptyHash = new Hash128();
    }

    public interface ILoaderCache
    {
        /// <summary>
        /// Cache name
        /// 缓存名称
        /// </summary>
        string CacheName { get; }

        /// <summary>
        /// Current cache
        /// 当前缓存
        /// </summary>
        Cache Cache { get; }

        /// <summary>
        /// Clear cache by hash
        /// 清除指定Hash缓存
        /// </summary>
        /// <param name="bundleName">AssetBundle名称</param>
        /// <param name="hash">要清除的版本信息</param>
        /// <returns></returns>
        bool ClearVersion(string bundleName, Hash128 hash);

        /// <summary>
        /// Clear caches except the Hash
        /// 清除除指定Hash外的缓存
        /// </summary>
        /// <param name="bundleName">AssetBundle名称</param>
        /// <param name="hash">要保留的版本信息</param>
        /// <returns></returns>
        bool ClearOtherVersions(string bundleName, Hash128 hash);

        /// <summary>
        /// Clear caches that exceeds the limit.
        /// 清除缓存
        /// </summary>
        /// <param name="bundleName">AssetBundle名称</param>
        /// <param name="max">允许保留的版本数量</param>
        /// <returns></returns>
        int ClearOverVersions(string bundleName, int max);

        /// <summary>
        /// Clear caches that exceeds the limit.
        /// 清除缓存
        /// </summary>
        /// <param name="bundleName">AssetBundle名称</param>
        /// <param name="max">允许保留的版本数量</param>
        /// <param name="keep">要保留的版本信息</param>
        /// <returns></returns>
        int ClearOverVersions(string bundleName, int max, Hash128 keep);
    }

    internal class LoaderCache : ILoaderCache, IDisposable
    {
        private readonly string m_Name;
        private readonly Cache m_Cache;

        private readonly List<Hash128> m_TmpHash = new List<Hash128>();
        private readonly List<Ver> m_TmpVersions = new List<Ver>();

        private struct Ver : IComparable<Ver>
        {
            public readonly long InitTicks;
            public readonly DirectoryInfo Dir;

            public Ver(long initTicks, DirectoryInfo dir)
            {
                InitTicks = initTicks;
                Dir = dir;
            }

            // 降序
            public int CompareTo(Ver obj)
            {
                return obj.InitTicks.CompareTo(InitTicks);
            }
        }

        public LoaderCache(string name, Cache cache)
        {
            m_Name = name;
            m_Cache = cache;
        }

        public string CacheName => m_Name;
        public Cache Cache => m_Cache;

        public bool ClearVersion(string bundleName, Hash128 hash)
        {
            return Caching.ClearCachedVersion(bundleName, hash);
        }

        public bool ClearOtherVersions(string bundleName, Hash128 hash)
        {
            return Caching.ClearOtherCachedVersions(bundleName, hash);
        }

        public int ClearOverVersions(string bundleName, int max)
        {
            return ClearOverVersions(bundleName, max, CacheInstance.EmptyHash);
        }

        public int ClearOverVersions(string bundleName, int max, Hash128 keep)
        {
//            DebugUtil.Log("LoaderCache.ClearOverVersions", bundleName, max, keep);
            m_TmpHash.Clear();
            Caching.GetCachedVersions(bundleName, m_TmpHash);
            var count = m_TmpHash.Count;
            if (count <= max)
            {
                return 0;
            }

            m_TmpVersions.Clear();
            foreach (var hash in m_TmpHash)
            {
                var p = new DirectoryInfo(UnityPathUtil.CombineUnityPath(m_Cache.path, bundleName, hash.ToString()));
                if (!p.Exists)
                {
                    m_TmpVersions.Add(new Ver(0, null));
                    continue;
                }

                m_TmpVersions.Add(new Ver(hash == keep ? long.MaxValue : p.CreationTimeUtc.Ticks, p));
            }

            m_TmpVersions.Sort();
            var rs = 0;
            while (count > max)
            {
                var v = m_TmpVersions[count - 1];
                if (v.InitTicks == 0)
                {
                    count--;
                    continue;
                }

                v.Dir.Delete(true);
                count--;
                rs++;
            }

            return rs;
        }

        public void Dispose()
        {
            Caching.RemoveCache(m_Cache);
        }
    }
}