using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Data;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Service;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.BaseInfo.Models;
using Hncore.Pass.BaseInfo.Request;
using Hncore.Pass.BaseInfo.Request.User;
using Hncore.Pass.BaseInfo.Response;
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Internal;
using Hncore.Infrastructure.SMS;

namespace Hncore.Pass.BaseInfo.Service
{
    public class UserService : ServiceBase<User>, IFindService
    {
        private static readonly AsyncLock _mutex1 = new AsyncLock();
        private static string _secret = "hncore_yh_lzh_20f_2020_READY";

        private UserDbContext _dbContext;

        private WxAppService m_WxAppService;
        private WxAppUserService m_WxAppUserService;
        private UserScoreService m_UserScoreService;
        private ManageService m_ManageService;
       
        private static ConcurrentDictionary<int, int> manangeDic = new ConcurrentDictionary<int, int>();
        public UserService(UserDbContext dbContext
            , WxAppService _WxAppService
            , WxAppUserService _WxAppUserService
            ,UserScoreService _UserScoreService
            , ManageService _ManageService
            , IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
        {
            _dbContext = dbContext;
            m_WxAppUserService = _WxAppUserService;
            m_WxAppService = _WxAppService;
            m_UserScoreService = _UserScoreService;
            m_ManageService = _ManageService;
        }

        /// <summary>
        /// 通过微信的opid登录
        /// </summary>
        /// <param name="openId"></param>
        /// <returns></returns>

        public async Task<UserLoginResponse> LoginAndBindWx(WxLoginRequest request)
        {

            if (request == null || request.Openid.NotHas() || request.AppId.NotHas())
            {
                BusinessException.Throw("登陆信息异常");
            }

            var existWxUserInfo = await m_WxAppUserService.GetWxAppUserInfo(request.AppId, request.Openid);
            if (existWxUserInfo == null || existWxUserInfo.UserId == 0)
            {
                var wxApp = await m_WxAppService.GetApp(request.AppId);
                if (wxApp == null)
                    BusinessException.Throw("没有关联公众号");
                var userEntity = new User()
                {
                    Name = request.UserName,
                    PhotoUrl = request.HeadImgUrl,
                    Sex = request.Sex,
                    TenantId = wxApp.TenantId,
                    Password = RandomHelper.GetRandomString(6)
                };
                await this.Add(userEntity);
                var wxUserInfo = request.MapTo<WxAppUserEntity>();
                wxUserInfo.UserId = userEntity.Id;
                wxUserInfo.TenantId = wxApp.TenantId;
                wxUserInfo.StoreId = wxApp.StoreId;
                existWxUserInfo = await m_WxAppUserService.Bind(wxUserInfo);
            }
            var user = new User()
            {
                TenantId = existWxUserInfo.TenantId,
                Id = existWxUserInfo.UserId
            };
            var ret = LoginInternal(user, existWxUserInfo);
            ret.MpUser = new WxMpUserModel()
            {
                AppId = request.AppId,
                OpenId = existWxUserInfo.Openid,
            };
            return ret;
        }

        /// <summary>
        /// 通过微信的opid登录
        /// </summary>
        /// <param name="openId"></param>
        /// <returns></returns>

        public async Task<UserLoginResponse> Login(LoginRequest request)
        {

            if (request == null || request.Logincode.NotHas() || request.Password.NotHas())
            {
                BusinessException.Throw("用户名或者密码为空");
            }
            var userInfo = await this.Query(m => (m.Phone == request.Logincode && m.Password == HashPassword(request.Password))||(m.LoginCode == request.Logincode && m.Password == HashPassword(request.Password))||(m.TaoBao == request.Logincode && m.Password == HashPassword(request.Password))).FirstOrDefaultAsync();
            if (userInfo == null)
            {
                BusinessException.Throw("用户名或者密码不正确");
            }
            var ret = LoginInternal(userInfo);
         
            return ret;
        }


        public UserLoginResponse LoginInternal(User manage, WxAppUserEntity wxUser)
        {
            var tokenDic = new Dictionary<string, object>()
            {
                {"LoginName", manage.LoginCode},
                { "Name", wxUser.NickName},
                {"UserId", manage.Id},
                {"TenantId", manage.TenantId},
                {"OpenId", wxUser.Openid},
                {"AppType", wxUser.AppType},
                {"AppId", wxUser.Appid},
                 {"StoreId", wxUser.StoreId},
            };
            var token = GenerateToken(tokenDic);
            var response = new UserLoginModel().FromEntity(manage);
            return new UserLoginResponse()
            {
                Token = token,
                User = response
            };
        }
        private UserLoginResponse LoginInternal(User manage)
        {
            var tokenDic = new Dictionary<string, object>()
            {
                {"LoginName", manage.LoginCode},
                { "Name", manage.Name},
                {"UserId", manage.Id},
                {"TenantId", manage.TenantId},
                {"OpenId", ""},
                {"AppType", ""},
                {"AppId", ""},
                 {"StoreId", "0"},
            };
            var token = GenerateToken(tokenDic);
            var response = new UserLoginModel().FromEntity(manage);
            return new UserLoginResponse()
            {
                Token = token,
                User = response
            };
        }

        private static string GenerateToken(Dictionary<string, object> param, int timeoutMinutes = 180)
        {
            IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
            IJsonSerializer serializer = new JsonNetSerializer();
            IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
            IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);

            long now = DateTimeHelper.ToUnixTimestamp(DateTime.Now);

            param["iat"] = now; //签发时间
            param["exp"] = DateTimeHelper.ToUnixTimestamp(DateTime.Now.AddDays(10)); //now + Math.Max(0, timeoutMinutes) * 60; //过期时间

            var token = encoder.Encode(param, _secret);

            return token;
        }


        public static string HashPassword(string password)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(password));
                return Convert.ToBase64String(bytes);
            }
        }

        public async Task<ApiResult> Regist(User entity)
        {
            if (entity.LoginCode.NotHas() || entity.Phone.NotHas())
            {
                return new ApiResult(ResultCode.C_LONGIN_NAME_ERROR, "账号或者手机号为空");
            }

            if (this.Exist(m => m.LoginCode == entity.LoginCode || m.Phone == entity.Phone || m.TaoBao == entity.Phone))
            {
                return new ApiResult(ResultCode.C_ALREADY_EXISTS_ERROR, "该账号或者手机号被注册了");
            }
            entity.Password = HashPassword(entity.Password);
            entity.id_code="";

            entity = await this.Add(entity);

            // await RandomAssignManager(entity.Id);

            return new ApiResult(entity);
        }

        public async Task<User> GetByPhone(string phone)
        {            
            var entity = await this.Query(m => m.Phone == phone).FirstOrDefaultAsync();
            return entity;
        }

        public async Task<ApiResult> UpdatePwd(int userId, string oldPwd, string newPwd)
        {
            var entity = await this.GetById(userId);
            if (newPwd.NotHas())
            {
                return new ApiResult(ResultCode.C_INVALID_ERROR, "新密码不能为空");
            }
            if (entity.Password != HashPassword(oldPwd))
            {
                return new ApiResult(ResultCode.C_INVALID_ERROR, "密码不正确");
            }
            entity.Password = HashPassword(newPwd);
            await this.Update(entity);
            return new ApiResult(entity);
        }

        public async Task<ApiResult> UpdatePwd(User entity, string newPwd)
        {
            if (newPwd.NotHas())
            {
                return new ApiResult(ResultCode.C_INVALID_ERROR, "新密码不能为空");
            }
            entity.Password = HashPassword(newPwd);
            await this.Update(entity);
            return new ApiResult(ResultCode.C_SUCCESS,"重置成功");
        }

        public async Task<ApiResult> UpdateAmount(UpdateAmountRequest request,String product="",String package="",String account="")
        {
            using (await _mutex1.LockAsync())
            {
                var entity = await this.GetById(request.UserId);
                if (entity == null)
                    return new ApiResult(ResultCode.C_NOT_EXISTS_ERROR, "用户不存在");
                if (request.Amount <= 0)
                    return new ApiResult(ResultCode.C_INVALID_ERROR, "金额必须大于0");
                
                var remark = request.AttchInfo;
                if (product != "") {
                    remark = product+"-"+package+"-"+account;
                }

                var userScore = new UserScore()
                {
                    UserId = request.UserId,
                    UserName = entity.LoginCode,
                    ScoreType = request.OpAmountType,
                    ScoreValue = request.Amount,
                    ScoreTypeName = request.OpAmountType.GetEnumDisplayName(),
                    Remark = remark,
                    OperateUserName = request.OperateUserName
                };

                if (request.OpAmountType == ScoreType.ManagerDeduct || request.OpAmountType == ScoreType.Pay)
                {
                    if (entity.RestAmount < request.Amount)
                    {
                        return new ApiResult(ResultCode.C_INVALID_ERROR, "余额不足");
                    }
                    userScore.RestAmount1 = entity.RestAmount;
                    entity.RestAmount -= request.Amount;
                    userScore.RestAmount2 = entity.RestAmount;

                }
                else
                {
                    userScore.RestAmount1 = entity.RestAmount;
                    entity.RestAmount += request.Amount;
                    userScore.RestAmount2 = entity.RestAmount;
                }

                using (var tran = await m_DbContextBase.Database.BeginTransactionAsync())
                {
                    try
                    {
                        await m_UserScoreService.Add(userScore);
                        await this.Update(entity);
                        tran.Commit();
                        return new ApiResult(ResultCode.C_SUCCESS);
                    }
                    catch (Exception ex)
                    {
                        tran.Rollback();
                        LogHelper.Error("UpdateAmount", ex.Message);
                        return new ApiResult(ResultCode.C_INVALID_ERROR);
                    }
                }
            
            }
        }

        public async Task<bool> RandomAssignManager(int userId)
        {
            var userEntity = await this.GetById(userId);
            var manage = await _dbContext.Set<Manager>()
               .Where(m => m.RoleId == 100).ToListAsync();

            if (manage == null || manage.Count == 0)
                return false;

            manage.ForEach(m =>
            {

                if (!manangeDic.ContainsKey(m.Id))
                    manangeDic[m.Id] = 1;


            });

            var removeIds = manangeDic.Where(m => !manage.Select(p => p.Id).Contains(m.Key));


            foreach (var kv in removeIds)
            {
                manangeDic.TryRemove(kv.Key, out int data);                
            }

            var minKv = manangeDic.OrderBy(m => m.Value).FirstOrDefault();      

            //获取管理员信息
            var manger_info = manage.FirstOrDefault(m => m.Id == minKv.Key); 

            userEntity.ManagerId = minKv.Key;
            userEntity.ManagerName = manger_info.RealName;

            await this.Update(userEntity);

            manangeDic[minKv.Key] = manangeDic[minKv.Key] + 1;

            if (manger_info.RoleId == 100 && manger_info.TenantId == 1 && DateTime.Now.Hour<23 && DateTime.Now.Hour>8) { 
                AliSmsService.Send("SMS_462001365", new { name = manger_info.RealName,phone=userEntity.Phone }, "聚IP", manger_info.Phone);
            }

            return true;
        }
    }
}