using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Hotline.CallCenter.Configs;
using Hotline.CallCenter.Devices;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Wex.Sdk;
using XF.Domain.Cache;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;

namespace Hotline.Wex
{
    public class WexTokenManager : ITokenManager, ISingletonDependency
    {
        private readonly IServiceScopeFactory _serviceScopeFactory;
        private const string WexToken = "WexToken";

        public WexTokenManager(IServiceScopeFactory serviceScopeFactory)
        {
            _serviceScopeFactory = serviceScopeFactory;
        }

        public async Task<string> GetTokenAsync(CancellationToken cancellationToken)
        {
            using var scope = _serviceScopeFactory.CreateScope();
            var cacheWexToken = scope.ServiceProvider.GetService<ITypedCache<WexToken>>();

            var token = await cacheWexToken.GetAsync(WexToken, cancellationToken);
            if (token is null)
            {
                token = await GetWexTokenAsync(scope, cancellationToken);
                if (token == null) throw new UserFriendlyException("未获取到呼叫中心请求token");
                var success = DateTime.TryParse(token.ExpireTime, out var expire);
                var ts = success ? expire.AddMinutes(-5) - DateTime.Now : TimeSpan.FromHours(2);
                await cacheWexToken.SetAsync(WexToken, token, ts, cancellationToken);
            }

            return token.Token;
        }

        public async Task RefreshTokenAsync(CancellationToken cancellationToken)
        {
            using var scope = _serviceScopeFactory.CreateScope();
            var cacheWexToken = scope.ServiceProvider.GetService<ITypedCache<WexToken>>();

            var token = await GetWexTokenAsync(scope, cancellationToken);
            if (token == null) throw new UserFriendlyException("未获取到呼叫中心请求token");
            var success = DateTime.TryParse(token.ExpireTime, out var expire);
            var ts = success ? expire.AddMinutes(-5) - DateTime.Now : TimeSpan.FromHours(2);
            await cacheWexToken.SetAsync(WexToken, token, ts, cancellationToken);
        }

        private async Task<WexToken> GetWexTokenAsync(IServiceScope scope, CancellationToken cancellationToken)
        {
            var callCenterConfiguration =
                scope.ServiceProvider.GetService<IOptionsSnapshot<CallCenterConfiguration>>();
            var wexClient = scope.ServiceProvider.GetService<IWexClient>();
            var wexConfig = callCenterConfiguration.Value.Wex;
            var request = new TokenRequest
            {
                Username = wexConfig.Username,
                Password = wexConfig.Password,
            };
            return await wexClient.GetTokenAsync(request, cancellationToken);
        }
    }
}
