using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Etor.Infrastructure.Common;
using Etor.Infrastructure.Data;
using Etor.Infrastructure.Extension;
using Etor.PSIP.Manage.Models;
using Etor.PSIP.Manage.Request;
using Etor.PSIP.Manage.Response;
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Microsoft.EntityFrameworkCore;

namespace Etor.PSIP.Manage.Service
{
    public class ManageService
    {
        private static string _secret = "etor_yh_lzh_20f_2020_YES";

        private EtorPropertyDbContext _dbContext;

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

        public async Task<LoginResponse> Login(LoginRequestData 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<etor_authority_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("密码错误");
            }

            var tokenDic = new Dictionary<string, object>()
            {
                {"LoginName", manage.logincode},
                {"RoleName", ""},
                {"OperaterID", manage.ID},
                {"OwnerID", manage.owner_id}
            };

            var isRoot = await _dbContext.Set<etor_authority_role>().AnyAsync(r => r.DeleteTag == 0
                                                                                   && r.ID == manage.roleid
                                                                                   && r.owner_id == manage.owner_id
                                                                                   && r.isroot);

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

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

            var minutes = (DateTime.Now.AddYears(1) - DateTime.Now).TotalMinutes;
            var token = GenerateToken(tokenDic, Convert.ToInt32(minutes));

            var response = new LoginManagerResponse().FromEntity(manage);

            var property = await _dbContext.Set<etor_property>()
                .FirstOrDefaultAsync(f => f.ID == manage.owner_id && f.DeleteTag == 0);

            response.PropertyCompanyName = property.companyname;
            response.ExpiredTime = property.ExpiredTime;
            response.ValidDays = (property.ExpiredTime - DateTime.Now.Date).Days;
            response.IsRootUser = isRoot;

            if (response.Phone.Has())
            {
                var employee = await _dbContext.EtorNinternalStaff.FirstOrDefaultAsync(_ => _.DeleteTag == 0
                                                                                            && _.Mobile ==
                                                                                            response.Phone);

                if (employee != null)
                {
                    response.WorkerName = employee.Position;

                    var departmentName = await _dbContext.Set<etor_ninternal_department>()
                        .Where(_ => _.DeleteTag == 0 && _.ID == employee.Departmentid)
                        .Select(t => t.departmentname)
                        .FirstOrDefaultAsync();

                    response.DepartmentName = departmentName;
                }
            }

            return new LoginResponse()
            {
                Token = token,
                Manager = response
            };
        }

        private static string GenerateToken(Dictionary<string, object> param, int timeoutMinutes = 120)
        {
            IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
            IJsonSerializer serializer = new JsonNetSerializer();
            IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
            IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
            IDateTimeProvider provider = new UtcDateTimeProvider();
            var now = provider.GetNow();
            var secondsSinceEpoch = Math.Round((now - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);


            param["exp"] = secondsSinceEpoch + Math.Max(0, timeoutMinutes) * 60; //什么时候签发的
            //param["exp"] = secondsSinceEpoch + 1;//什么时候签发的

            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);
            }
        }
    }
}