using System;
using Microsoft.AspNetCore.Mvc;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Redis;
using Microsoft.AspNetCore.Cors;
using Microsoft.Extensions.Primitives;
using Siger.ApiCommon.Filters;
using Siger.ApiCommon.Utilities;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.Repository.Request;
using Siger.Middlelayer.Common.Extensions;
using LicenseStatus = Siger.Middlelayer.Common.Helpers.LicenseStatus;
using Siger.Middlelayer.Redis.RedisEntities;

namespace Siger.ApiConfig.Controller
{
    [Route("config/[controller]/[action]")]
    [EnableCors("Cors")]
    public class LoginController : ControllerBase
    {
        private readonly ISigerUserRepository _userRepository;
        private readonly ISigerProjectUserRepository _sigerProjectUserRepository;
        private readonly ISigerProjectRepository _sigerProjectRepository;

        public LoginController(ISigerUserRepository userRepository, ISigerProjectUserRepository sigerProjectUserRepository,
            ISigerProjectRepository sigerProjectRepository)
        {
            _userRepository = userRepository;
            _sigerProjectUserRepository = sigerProjectUserRepository;
            _sigerProjectRepository = sigerProjectRepository;
        }

        [HttpPost]
        [TokenValidateFilter]
        public ActionResult Login([FromBody] RequestLogin request)
        {
            var loginInfo = new LoginInfo(request.Mobile.Trim(), MD5Helper.Get32MD5(request.Password));
            var value = GetTokenValue(loginInfo);

            HttpContext.Request.Headers.TryGetValue(ParameterConstant.Token, out StringValues token);
            RedisCache.Client.Del(token);
            RedisCache.Instance.AddToken(token, value);

            //更新用户appkey
            if (!string.IsNullOrWhiteSpace(request.AppKey))
            {
                var tokenValue = RedisCache.Instance.GetTokenValue(token);
                if (tokenValue != null)
                {
                    UpdateUserAppKey(tokenValue.UserId, request.AppKey, tokenValue.ProjectId);
                }
            }
            return new ObjectResult(CommonEnum.Succefull);
        }

        [HttpPost]
        [NoTokenValidateFilter]
        public IActionResult Logout([FromBody]RequestLogout request)
        {
            if (!string.IsNullOrEmpty(request.Token))
            {
                var tokenValue = RedisCache.Client.Get(request.Token);
                if (string.IsNullOrEmpty(tokenValue))
                {
                    return new ObjectResult(CommonEnum.Succefull);
                }
                RedisCache.Client.Del(request.Token);
            }

            return new ObjectResult(CommonEnum.Succefull);
        }

        private string GetTokenValue(LoginInfo loginInfo, bool checkLicense = true)
        {
            var user = _userRepository.Get(f => f.mobile == loginInfo.Mobile && f.status == (int)RowState.Valid);
            if (user != null)
            {
                if (user.password != loginInfo.Password)
                {
                    throw new BadRequestException(ConfigEnum.LoginError);
                }
            }
            else //验证工号
            {
                var projectuser = _sigerProjectUserRepository.Get(f => f.work_code == loginInfo.Mobile && f.status == (int)RowState.Valid);
                if (projectuser == null)
                {
                    throw new BadRequestException(ConfigEnum.ProjectUserNotFound);
                }
                user = _userRepository.Get(f => f.id == projectuser.mid && f.status == (int)RowState.Valid);
                if (user == null || user.password != loginInfo.Password)
                {
                    throw new BadRequestException(ConfigEnum.LoginError);
                }
            }

            if (user.type == (int) UserType.SuperAdmin)
            {
                IniDbNameConfig(0, 0, "");
                return TokenHelper.Splicing("0", 0, user.id, 0);
            }

            var userprojectinfo = _sigerProjectUserRepository.Get(f => f.mid == user.id && f.status == (int)RowState.Valid);
            if (userprojectinfo == null)
            {
                throw new BadRequestException(ConfigEnum.ProjectUserNotFound);
            }

            var project = _sigerProjectRepository.Get(q => q.id == userprojectinfo.projectid && q.status == (int)RowState.Valid);
            if (project == null)
            {
                throw new BadRequestException(ConfigEnum.ProjectNotFound);
            }
            //check license
            if (checkLicense)
            {
                CheckLicense(project.companyid, userprojectinfo.projectid);
            }

            IniDbNameConfig(project.companyid.ToInt(), project.id, project.title);
            return TokenHelper.Splicing(project.companyid, userprojectinfo.projectid, user.id, user.roleid);
        }

        private void IniDbNameConfig(int companyid, int projectid, string title)
        {
            //添加DBNameConfig
            var dbnameconfig = RedisCache.Instance.GetDbName(companyid, projectid);
            if (dbnameconfig == null)
            {
                var entity = new DbNameConfig
                {
                    Cid = companyid,
                    Pid = projectid,
                    CompanyName = title,
                    MysqlDbName = $"{companyid}_{projectid}",
                    RedisDbName = "1",
                };
                RedisCache.Instance.AddDbNameConfig(entity);
            }
        }

        private void CheckLicense(string companyId, int projectId)
        {
            var key = $"{companyId}_{projectId}";
            var status = License.CheckLicenseStatus(key);
            switch (status.Status)
            {
                case LicenseStatus.NotFound:
                    throw new BadRequestException(CommonEnum.LicenseIsEmpty);
                case LicenseStatus.Invalid:
                    throw new BadRequestException(CommonEnum.LicenseIsInvalid);
                case LicenseStatus.HasExpity:
                    throw new BadRequestException(CommonEnum.LicenseHasExpired);
            }
        }

        /// <summary>
        /// 手机端登录后，更新appkey
        /// </summary>
        /// <param name="mid"></param>
        /// <param name="appkey"></param>
        /// <param name="projectId"></param>
        private void UpdateUserAppKey(int mid, string appkey, int projectId)
        {
            if (string.IsNullOrWhiteSpace(appkey))
            {
                throw new BadRequestException(CommonEnum.RegistrationIdNotFound);
            }
            var result = _sigerProjectUserRepository.UpdateUserAppKey(mid, appkey, projectId);
            if (result == 0)
            {
                throw new BadRequestException(CommonEnum.UpdateRegistrationIdFailed);
            }
        }

        [HttpGet]
        [NoTokenValidateFilter]
        public IActionResult GetTime()
        {
            return new ObjectResult(DateTime.Now.ToString(ParameterConstant.DateTimeFormat));
        }
    }

    public class LoginInfo
    {
        public string Mobile { get; private set; }

        public string Password { get; private set; }

        public LoginInfo(string mobile, string password)
        {
            Mobile = mobile;
            Password = password;
        }

        public LoginInfo(string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                throw new BadRequestException(ConfigEnum.EncryptedDataIsEmpty);
            }
            var encryptedData = CryptoJSHelper.Decrypt(data);
            if (string.IsNullOrEmpty(encryptedData))
            {
                throw new BadRequestException(ConfigEnum.ReLoginFailed);
            }

            var loginInfo = encryptedData.Split(',', StringSplitOptions.RemoveEmptyEntries);
            if (loginInfo.Length != 2)
            {
                throw new BadRequestException(ConfigEnum.ReLoginFailed);
            }

            Mobile = loginInfo[0];
            Password = loginInfo[1];
        }
    }
}