﻿using CSRedis;
using Enyim.Caching;
using Enyim.Caching.Configuration;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Caching.Redis;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Wicture.DbRESTFul.Cache
{
    public static class CacheProviderFactory
    {
        public static Dictionary<string, ICacheProvider> CacheProviders { get; set; } = new Dictionary<string, ICacheProvider>();
        
        public static void Init(IApplicationBuilder app)
        {
            var memoryCache = app.ApplicationServices.GetService<IMemoryCache>();
            if(memoryCache != null) CacheProviders[MemoryCacheProvider.Name] = new MemoryCacheProvider(memoryCache);

            var memcachedClient = app.ApplicationServices.GetService<IMemcachedClient>();
            if (memcachedClient != null) CacheProviders[MemCachedProvider.Name] = new MemCachedProvider(memcachedClient);

            var distributedCache = app.ApplicationServices.GetService<IDistributedCache>();
            if (distributedCache != null) CacheProviders[RedisCacheProvider.Name] = new RedisCacheProvider(distributedCache);
        }

        public static void Set(string type, string key, object data, int expiration)
        {
            if(CacheProviders.ContainsKey(type))
            {
                CacheProviders[type].Set(key, data, expiration);
            }
        }

        public static JToken Get(string type, string key)
        {
            if (CacheProviders.ContainsKey(type))
            {
                return CacheProviders[type].Get(key);
            }

            return null;
        }
    }

    public static class CacheProviderService
    {
        public static IServiceCollection UseCache(this IServiceCollection services)
        {
            var cfg = ConfigurationManager.Settings?.CacheConfigs?.FirstOrDefault(c => c.Type == MemoryCacheProvider.Name);
            if (cfg != null)
            {
                services.AddMemoryCache();
            }

            cfg = ConfigurationManager.Settings?.CacheConfigs?.FirstOrDefault(c => c.Type == MemCachedProvider.Name);
            if (cfg != null)
            {
                services.AddEnyimMemcached(options =>
                {
                    options.Servers.Add(cfg.Config.ToObject<Server>());
                });
            }

            cfg = ConfigurationManager.Settings?.CacheConfigs?.FirstOrDefault(c => c.Type == RedisCacheProvider.Name);
            if (cfg != null)
            {
                var connectionStrings = cfg.Config.Value<string>("ConnectionString").Split(";".ToArray(), StringSplitOptions.RemoveEmptyEntries);
                var csredis = new CSRedisClient(null, connectionStrings);
                RedisHelper.Initialization(csredis, value => JsonConvert.SerializeObject(value), deserialize: (data, type) => JsonConvert.DeserializeObject(data, type));
                services.AddSingleton<IDistributedCache>(new CSRedisCache(RedisHelper.Instance));
            }

            return services;
        }
    }
}
