using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XF.Domain.Cache
{
    public interface ITypedCache<TValue> //where TValue : class
    {
        /*
TrySet/TrySetAsync
Set/SetAsync
SetAll/SetAllAsync
Get/GetAsync(with data retriever)
Get/GetAsync(without data retriever)
GetByPrefix/GetByPrefixAsync
GetAll/GetAllAsync
Remove/RemoveAsync
RemoveByPrefix/RemoveByPrefixAsync
RemoveAll/RemoveAllAsync
Flush/FlushAsync
GetCount
GetExpiration/GetExpirationAsync
         */

        void Set(string key, TValue value, TimeSpan? expiration = null);
        Task SetAsync(string key, TValue value, TimeSpan? expiration = null, CancellationToken cancellationToken = default);

        TValue? Get(string key);
        Task<TValue?> GetAsync(string key, CancellationToken cancellationToken);

        void Remove(string key);
        Task RemoveAsync(string key, CancellationToken cancellationToken);

        bool Exists(string key);
        Task<bool> ExistsAsync(string key, CancellationToken cancellationToken);

        bool TrySet(string key, TValue value, TimeSpan? expiration = null);
        Task<bool> TrySetAsync(string key, TValue value, TimeSpan? expiration = null, CancellationToken cancellationToken = default);

        void SetAll(IDictionary<string, TValue> values, TimeSpan? expiration = null);
        Task SetAllAsync(IDictionary<string, TValue> values, TimeSpan? expiration = null, CancellationToken cancellationToken = default);

        IDictionary<string, TValue> GetByPrefix();
        Task<IDictionary<string, TValue>> GetByPrefixAsync(CancellationToken cancellationToken);

        IReadOnlyList<TValue> GetListByPrefix(string? prefix = null);
        Task<IReadOnlyList<TValue>> GetListByPrefixAsync(CancellationToken cancellationToken);

        //void RemoveByPrefix(string prefix);
        //Task RemoveByPrefixAsync(string prefix, CancellationToken cancellationToken);

        /// <summary>
        /// get the cache value, if cache not exists, set the value to cache then return
        /// </summary>
        TValue GetOrSet(string key, TValue value, TimeSpan? expiration = null);
        TValue? GetOrSet(string key, Func<string, TValue> valueFactory, TimeSpan? expiration = null);
        Task<TValue> GetOrSetAsync(string key, TValue value, TimeSpan? expiration = null, CancellationToken cancellationToken = default);
        Task<TValue?> GetOrSetAsync(string key, Func<string, TValue> valueFactory, TimeSpan? expiration = null, CancellationToken cancellationToken = default);

        //TValue GetOrAdd(string key, TValue value, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null);

        //TValue GetOrAdd(string key, Func<string, TValue> valueFactory, ExpireMode? expireMode = ExpireMode.None, TimeSpan? timeout = null);

        string CombinePrefix(string key);
    }

    public enum ExpireMode
    {
        /// <summary>Defines no expiration.</summary>
        None,
        /// <summary>
        /// Defines sliding expiration. The expiration timeout will be refreshed on every access.
        /// </summary>
        Sliding,
        /// <summary>
        /// Defines absolute expiration. The item will expire after the expiration timeout.
        /// </summary>
        Absolute,
    }
}
