using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Data;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Serializer;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.BaseInfo.Models;
using Hncore.Pass.BaseInfo.Request;
using Hncore.Pass.BaseInfo.Request.Manager;
using Hncore.Pass.BaseInfo.Response;
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Hncore.Pass.BaseInfo.Service
{
    public class ManageService
    {
        private static string _secret = "etor_yh_lzh_20f_2020_YES";

        private UserDbContext _dbContext;

        public ManageService(UserDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        public async Task<LoginResponse> Login(LoginRequest request)
        {
            if (request == null
               // || !request.Code.Has()
                || !request.CodeKey.Has()
                || !request.Logincode.Has()
                || !request.Password.Has()
            )
            {
                BusinessException.Throw("登陆信息异常");
            }

            //string valCode = await RedisHelper.GetAsync(request.CodeKey);
            //if (!valCode.Has() || valCode.ToLower() != request.Code.ToLower())
            //{
            //    BusinessException.Throw("验证码错误");
            //}

            var manage = await _dbContext.Set<Manager>()
                .FirstOrDefaultAsync(m => (m.LoginCode == request.Logincode || m.Phone == request.Logincode)                                         
                                          && m.State == (int)ManagerState.Enabled);

            if (manage == null)
            {
                BusinessException.Throw("登录名不存在");
            }

            if (HashPassword(request.Password).ToUpper() != manage.Password.ToUpper())
            {
                BusinessException.Throw("密码错误");
            }

            return await LoginInternal(manage);
        }

        public async Task<LoginResponse> LoginTemp(LoginRequest request)
        {
            if (request == null
                || !request.Logincode.Has()
                || !request.Password.Has()
            )
            {
                BusinessException.Throw("登陆信息异常");
            }

            var manage = await _dbContext.Set<Manager>()
                .FirstOrDefaultAsync(m => (m.LoginCode == request.Logincode || m.Phone == request.Logincode)                                        
                                          && m.State == (int)ManagerState.Enabled);

            if (manage == null)
            {
                BusinessException.Throw("登录名不存在");
            }

            if (HashPassword(request.Password).ToUpper() != manage.Password.ToUpper())
            {
                BusinessException.Throw("密码错误");
            }

            return await LoginInternal(manage);
        }

        public async Task<LoginAndroidManagerResponse> LoginAndroidTemp(LoginRequest request)
        {
            if (request == null
                || !request.Logincode.Has()
                || !request.Password.Has()
            )
            {
                BusinessException.Throw("登陆信息异常");
            }

            var manage = await _dbContext.Set<Manager>()
                .FirstOrDefaultAsync(m => (m.LoginCode == request.Logincode || m.Phone == request.Logincode)
                                          && m.DeleteTag == 0
                                          && m.State == (int)ManagerState.Enabled);

            if (manage == null)
            {
                BusinessException.Throw("登录名不存在");
            }

            if (HashPassword(request.Password).ToUpper() != manage.Password.ToUpper())
            {
                BusinessException.Throw("密码错误");
            }

            return await LoginAndroidInternal(manage);
        }

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

        public async Task<LoginResponse> LoginOpenid(string openId)
        {
            if (string.IsNullOrWhiteSpace(openId))
            {
                BusinessException.Throw("登陆信息异常");
            }

            openId = openId.Trim();
            var manage = await _dbContext.Set<Manager>()
                .FirstOrDefaultAsync(m => (m.WxOpenid == openId
                                          && m.DeleteTag == 0
                                          && m.State == (int)ManagerState.Enabled));
            if (manage == null)
            {
                BusinessException.Throw("没有绑定微信登录");
            }

            return await LoginInternal(manage);
        }

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

        public async Task<string> GenerateTokenByOpenid(string openId)
        {
            if (string.IsNullOrWhiteSpace(openId))
            {
                BusinessException.Throw("登陆信息异常");
            }

            openId = openId.Trim();
            var manage = await _dbContext.Set<Manager>()
                .FirstOrDefaultAsync(m => (m.WxOpenid == openId
                                          && m.DeleteTag == 0
                                          && m.State == (int)ManagerState.Enabled));
            if (manage == null)
            {
                BusinessException.Throw("没有绑定微信登录");
            }

            var tokenDic = new Dictionary<string, object>()
            {
                {"OpenId",openId},
                {"LoginName", manage.LoginCode},
                {"RoleName", ""},
                {"OperaterID", manage.Id},
                {"TenantId", manage.TenantId}
            };

            var token = GenerateToken(tokenDic);
            return token;
        }

        private async Task<LoginResponse> LoginInternal(Manager manage)
        {
            var tokenDic = new Dictionary<string, object>()
            {
                {"LoginName", manage.LoginCode},
                {"RoleName", ""},
                {"OperaterID", manage.Id},
                {"RealName", manage.RealName},
                {"TenantId", manage.TenantId}
            };

            if (manage.IsRoot != 1)
            {
                //int[] domains = await _dbContext.Set<etor_authority_managerdatadomain>()
                //    .Where(p => p.owner_id == manage.TenantId && p.DeleteTag == 0 && p.managerid == manage.Id)
                //    .Select(t => t.projectcode)
                //    .ToArrayAsync();

                //tokenDic.Add("DataDomain", domains);
            }

            var token = GenerateToken(tokenDic);

            var response = new LoginManagerResponse().FromEntity(manage);  
            return new LoginResponse()
            {
                Token = token,
                Manager = response
            };
        }
        /// <summary>
        /// 重新获取token
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        internal async Task<string> AgainGetToken(RequestBase<AgainTokenDTO> request)
        {
            if (null == request|| request.Data==null) BusinessException.Throw("参数错误");
            var token = request.Data.Token;
            var ManageUserInfo = new ManageUserInfo();
            if (CheckToken(request.Data.Token, out ManageUserInfo))
            {
                var tokenDic = new Dictionary<string, object>()
                    {
                        {"LoginName", ManageUserInfo.LoginName},
                        {"RoleName", ManageUserInfo.RoleName},
                        {"OperaterID", ManageUserInfo.OperaterId},
                        {"OwnerID", ManageUserInfo.TenantId}
                    };
                switch (request.Data.Type)
                {
                    case AgainTokenType.Expire:
                        break;
                    //case AgainTokenType.Project:
                    //    var manager = await _dbContext.Set<Manager>()
                    //                .FirstOrDefaultAsync(s=>s.Id == request.OperaterId);
                    //    if (manager.IsRoot != 1)
                    //    {
                    //        int[] domains = await _dbContext.Set<etor_authority_managerdatadomain>()
                    //            .Where(p => p.owner_id == manager.TenantId && p.DeleteTag == 0 && p.managerid == manager.Id)
                    //            .Select(t => t.projectcode)
                    //            .ToArrayAsync();

                    //        tokenDic.Add("DataDomain", domains);
                    //    }
                    //    break;
                    default:
                        break;
                }
                token = GenerateToken(tokenDic);
            }
            else
            {
                BusinessException.Throw("参数错误");
            }
            return token;
        }

        private async Task<LoginAndroidManagerResponse> LoginAndroidInternal(Manager manage)
        {
            var response = new LoginAndroidManagerResponse().FromEntity(manage);           
            return 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"] = now + Math.Max(0, timeoutMinutes) * 60; //过期时间

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

            return token;
        }

        public bool CheckToken(string token, out ManageUserInfo userInfo)
        {
            userInfo = null;
            try
            {
                IJsonSerializer serializer = new JsonNetSerializer();
                IDateTimeProvider provider = new UtcDateTimeProvider();
                IJwtValidator validator = new JwtValidator(serializer, provider);
                IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
                IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);
                var payload = decoder.Decode(token, _secret, verify: true);

                userInfo = payload.FromJsonTo<ManageUserInfo>();

                if (userInfo == null || userInfo.TenantId == 0)
                {
                    return false;
                }

                if (userInfo.IssueTimestamp == 0
                    || DateTimeHelper.UnixTimeStampToDateTime(userInfo.IssueTimestamp) <
                    DateTime.Now.AddHours(-4))
                {
                    return false;
                }
                return true;
            }
            catch (TokenExpiredException ex)
            {
                LogHelper.Error("oken has expired", ex.Message);
                return false;
            }
            catch (Exception ex)
            {
                LogHelper.Error("CheckToken失败", ex.Message);
                return false;
            }
        }

        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<Manager> GetById(int id)
        {
            var manage = await _dbContext.Set<Manager>().FindAsync(id);

            return manage;

        }
    }
}