using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ASHermed.SinoInterface.Api.ContractModel.BlindBox.Dto;
using ASHermed.SinoInterface.Api.ContractModel.BlindBox.Entity;
using ASHermed.SinoInterface.Api.IRepository.BlindBox;
using ASHermed.SinoInterface.Api.IService.BlindBox;
using ASHermed.SinoInterface.ContractModel;
using ASHermed.SinoInterface.Tools;
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Microsoft.Extensions.Logging;

namespace ASHermed.SinoInterface.Api.Service.BlindBox
{
    /// <summary>
    /// 盲盒服务
    /// </summary>
    public class BlindBoxService : BaseService, IBlindBoxService
    {
        private readonly IBlindBoxRepository _blindBoxRepository;
        private readonly RedisHelperClient _redisHelperClient;
        private readonly ILogger<BlindBoxService> _logger;

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="blindBoxRepository"></param>
        /// <param name="logger"></param>
        /// <param name="redisHelperClient"></param>
        public BlindBoxService(
            IBlindBoxRepository blindBoxRepository,
            RedisHelperClient redisHelperClient,
            ILogger<BlindBoxService> logger)
        {
            _blindBoxRepository = blindBoxRepository;
            _redisHelperClient = redisHelperClient;
            _logger = logger;
        }

        #region 医生端

        /// <summary>
        /// 盲盒活动登录
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseResponse<BlindBoxLoginOutput>> LoginAsync(BlindBoxLoginInput input)
        {
            var token = await GenerateTokenAsync(input.Account);

            return new BaseResponse<BlindBoxLoginOutput>
            {
                Code = 1,
                Msg = "成功",
                Data = new BlindBoxLoginOutput
                {
                    BlindBoxToken = token
                }
            };
        }

        /// <summary>
        /// 获取诊所的总领取人数和总领取次数
        /// </summary>
        /// <param name="clinic">诊所标识</param>
        /// <returns></returns>
        public async Task<BaseResponse<BlindBoxUvPvDto>> QueryUvPvAsync(int clinic)
        {
            var blindBoxList = await _blindBoxRepository.QueryAsync(clinic);

            if (!blindBoxList.Any())
            {
                return new BaseResponse<BlindBoxUvPvDto>
                {
                    Code = 1,
                    Msg = "暂无数据",
                    Data = new BlindBoxUvPvDto()
                };
            }

            return new BaseResponse<BlindBoxUvPvDto>
            {
                Code = 1,
                Msg = "成功",
                Data = new BlindBoxUvPvDto
                {
                    Pv = blindBoxList.Count,
                    Uv = blindBoxList.GroupBy(x => x.UserId).Count()
                }
            };
        }

        /// <summary>
        /// 列表查询
        /// </summary>
        /// <param name="hosId"></param>
        /// <param name="searchText"></param>
        /// <param name="language">语言</param>
        /// <returns></returns>
        public async Task<BaseResponse<List<BlindBoxDto>>> QueryAsync(int hosId, string searchText, int language)
        {
            var blindBoxList = await _blindBoxRepository.QueryAsync(hosId, searchText);

            if (!blindBoxList.Any())
            {
                return new BaseResponse<List<BlindBoxDto>>
                {
                    Code = 1,
                    Msg = "暂无数据",
                    Data = new List<BlindBoxDto>()
                };
            }

            foreach (var blindBoxDto in blindBoxList)
            {
                var timeDiff = DateTime.Now.Subtract(blindBoxDto.CreateTime);

                blindBoxDto.ReceiveTime = blindBoxDto.CreateTime.ToString(timeDiff.Days == 0 ? "hh:mm" : "M月-dd日 hh:mm");
            }

            return new BaseResponse<List<BlindBoxDto>>
            {
                Code = 1,
                Msg = "成功",
                Data = blindBoxList
            };
        }

        #endregion

        #region 患者端

        /// <summary>
        /// 查询用户已领取次数
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="language"></param>
        /// <returns></returns>
        public async Task<BaseResponse<GetItNowOutput>> GetItCountAsync(int userId, int language)
        {
            var count = await _blindBoxRepository.GetCountByUserIdAsync(userId);

            return new BaseResponse<GetItNowOutput>
            {
                Code = 1,
                Msg = "成功",
                Data = new GetItNowOutput
                {
                    Count = count
                }
            };
        }

        /// <summary>
        /// 立即领取
        /// </summary>
        /// <param name="input"></param>
        /// <param name="language"></param>
        /// <returns></returns>
        public async Task<BaseResponse<GetItNowOutput>> GetItNowAsync(GetItNowInput input, int language)
        {
            if (input.UserId <= 0 || input.HosId <= 0)
            {
                return new BaseResponse<GetItNowOutput>
                {
                    Code = 0,
                    Msg = "信息获取失败"
                };
            }

            var count = await _blindBoxRepository.GetCountByUserIdAsync(input.UserId);

            if (count >= 10)
            {
                return new BaseResponse<GetItNowOutput>
                {
                    Code = 0,
                    Msg = language == 1 ? "盲盒领取数量已达上限啦！" : "Your Mystery Boxes have reached the maximum(╯▽╰)"
                };
            }

            var blindBox = new PubBlindBox
            {
                UserId = input.UserId,
                HosId = input.HosId,
                CreateTime = DateTime.Now
            };

            var addResult = await _blindBoxRepository.AddAsync(blindBox);

            if (addResult <= 0)
            {
                return new BaseResponse<GetItNowOutput>
                {
                    Code = 0,
                    Msg = "盲盒领取失败"
                };
            }

            _logger.LogInformation($"GetItNow:user-{input.UserId},clinic-{input.HosId}");

            return new BaseResponse<GetItNowOutput>
            {
                Code = 1,
                Msg = "盲盒领取成功",
                Data = new GetItNowOutput
                {
                    Count = count + 1
                }
            };
        }

        #endregion

        #region private method

        /// <summary>
        /// 生成盲盒活动医生端token
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        private async Task<string> GenerateTokenAsync(string account)
        {
            IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
            IJsonSerializer serializer = new JsonNetSerializer();
            IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
            IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);

            var payload = new Dictionary<string, object>
            {
                { "account", account }
            };

            var token = encoder.Encode(payload, "blingbox2022");

            await _redisHelperClient.StringSetAsync($"blindbox_{account}", token, TimeSpan.FromDays(1));

            return token;
        }

        #endregion

    }
}