using System;
using System.Collections.Generic;
using System.IRepositories;
using System.Linq;
using System.Model;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Common;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using SignToken;

namespace TVShoppingCallCenter_ZLJ.Controllers
{
    [Authorize]
    [Route("api/[controller]")]
    public class TokenController : BaseController
    {
        private readonly IConfiguration _configuration;
        private readonly IDistributedCache _cache;
        private readonly ISys_UserAccountRepository _sys_useraccountRepository;
        private readonly ISys_RoleInfoRepository _sys_roleinfoRepository;
        private readonly ISys_SeatGroupRepository _sys_seatgroupRepository;
        private readonly ISys_LoginLogsRepository _sys_login_logsRepository;
        public TokenController(IConfiguration configuration, IDistributedCache cache, ISys_UserAccountRepository sys_useraccountRepository, ISys_RoleInfoRepository sys_roleinfoRepository, ISys_SeatGroupRepository sys_seatgroupRepository, ISys_LoginLogsRepository sys_login_logsRepository)
        {
            _configuration = configuration;
            _cache = cache;
            _sys_useraccountRepository = sys_useraccountRepository;
            _sys_roleinfoRepository = sys_roleinfoRepository;
            _sys_seatgroupRepository = sys_seatgroupRepository;
            _sys_login_logsRepository = sys_login_logsRepository;
        }

        /// <summary>
        /// 登陆
        /// </summary>
        /// <param name="usercode"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost("login")]
        public async Task<IActionResult> LoginAsync(string usercode, string password, int channel = 1, string returnUrl = null)
        {
            #region 获取ip地址
            var ip = IPHelper.GetIp(this.HttpContext);
            #endregion

            #region 用户信息判断及查找

            if (!ValidateHelper.IsAllPlumpString(usercode, password))
            {
                return Error("用户名或密码不能为空！");
            }

            var user = await _sys_useraccountRepository.GetSingle(x => x.F_UserCode == usercode && x.F_Password == password && x.F_DeleteFlag==(int)EnumUserCountState.Enabled);
            if (user == null) { return Error("用户名或密码错误！"); }
            if (user.F_DeleteFlag == (int)EnumUserCountState.Delete) {
                await AddLogAsync(usercode, "当前账户被禁止登录访问", ip, user.F_UserId, channel);
                return Error("当前账户被禁止登录访问！");
            }
            #endregion
            #region 角色判断
            var roleinfo = await _sys_roleinfoRepository.GetSingle(x => x.F_RoleId == user.F_RoleId && x.F_State == (int)EnumDelState.Enabled);

            //查询角色 如若查询不到，反馈  不要直接反馈明显信息
            if (roleinfo == null)
            {
                await AddLogAsync(usercode, "无相关角色信息", ip, user.F_UserId, channel);
                return Error("当前用户涉嫌非法访问！");
            }
            #endregion
            #region 坐席组
            var seatgroupcode = "";
            var seatgroupinfo = await _sys_seatgroupRepository.GetSingle(x => x.F_ZXZID == user.F_SeartGroupID && x.F_State==(int)EnumDelState.Enabled);
            if (seatgroupinfo != null)
                seatgroupcode = seatgroupinfo.F_ZXZCode;
            #endregion

            #region JWT token生成
            var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"].ToString()));
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
            var permissionRequirement = new PermissionRequirement(
                "/api/denied",
                ClaimTypes.Role,
                _configuration["Jwt:Issuer"].ToString(),
                _configuration["Jwt:Audience"].ToString(),
                signingCredentials,
                expiration: TimeSpan.FromDays(Convert.ToInt32(_configuration["Jwt:Expiration"]))
                );
            var claims = new Claim[] {
                new Claim(ClaimTypes.PrimarySid, user.F_UserId.ToString()),//用户id
                //new Claim(ClaimTypes.GroupSid,channel.ToString()),//渠道来源
                new Claim(ClaimTypes.Sid, user.F_UserCode),//用户账号
                new Claim(ClaimTypes.Name, user.F_UserName),//用户名字
                new Claim(ClaimTypes.Role, user.F_RoleId.ToString()),//角色id
                new Claim("RoleCode", roleinfo.F_RoleCode),//角色code
                new Claim(ClaimTypes.DenyOnlySid, user.F_WxOpenId!=null?user.F_WxOpenId:""),//微信id
                new Claim(ClaimTypes.Expiration,DateTime.Now.AddSeconds(permissionRequirement.Expiration.TotalSeconds).ToString())
            };
            //用户标识
            var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
            identity.AddClaims(claims);

            var jwt_token = JwtToken.BuildJwtToken(claims, permissionRequirement);
            #endregion

            await AddLogAsync(usercode, "登录成功", ip, user.F_UserId, channel);
            user.F_LastActiveTime = DateTime.Now;
            var res = await _sys_useraccountRepository.Update(user);
            var result = new
            {
                username = user.F_UserName,
                usercode = user.F_UserCode,
                token = jwt_token,
                seat_flag = user.F_SeatFlag,
                group = seatgroupcode,
                role_name = roleinfo.F_RoleName,
                role_id = roleinfo.F_RoleId,
                role_code = roleinfo.F_RoleCode,
                dept_id = user.F_DeptId,
                mobile = user.F_Mobile,
                
            };
            return Success("成功", result);
        }

        [HttpPost("update_token")]
        public async Task<IActionResult> Update_Token(int channel = 1)
        {
            #region 获取ip地址
            var ip = IPHelper.GetIp(this.HttpContext);
            #endregion

            #region 用户信息判断及查找
            string usercode = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Sid).Value;

            var user = await _sys_useraccountRepository.GetSingle(x => x.F_UserCode == usercode && x.F_DeleteFlag == (int)EnumUserCountState.Enabled);
            if (user.F_DeleteFlag == (int)EnumUserCountState.Delete)
            {
                await AddLogAsync(usercode, "当前账户被禁止登录访问", ip, user.F_UserId, channel);
                return Error("当前账户被禁止登录访问！");
            }
            #endregion
            #region 角色判断
            var roleinfo = await _sys_roleinfoRepository.GetSingle(x => x.F_RoleId == user.F_RoleId && x.F_State == (int)EnumDelState.Enabled);

            //查询角色 如若查询不到，反馈  不要直接反馈明显信息
            if (roleinfo == null)
            {
                await AddLogAsync(usercode, "无相关角色信息", ip, user.F_UserId, channel);
                return Error("当前用户涉嫌非法访问！");
            }
            #endregion
            #region 坐席组
            var seatgroupcode = "";
            var seatgroupinfo = await _sys_seatgroupRepository.GetSingle(x => x.F_ZXZID == user.F_SeartGroupID && x.F_State == (int)EnumDelState.Enabled);
            if (seatgroupinfo != null)
                seatgroupcode = seatgroupinfo.F_ZXZCode;
            #endregion

            #region JWT token生成
            var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"].ToString()));
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
            var permissionRequirement = new PermissionRequirement(
                "/api/denied",
                ClaimTypes.Role,
                _configuration["Jwt:Issuer"].ToString(),
                _configuration["Jwt:Audience"].ToString(),
                signingCredentials,
                expiration: TimeSpan.FromDays(Convert.ToInt32(_configuration["Jwt:Expiration"]))
                );
            var claims = new Claim[] {
                new Claim(ClaimTypes.PrimarySid, user.F_UserId.ToString()),//用户id
                //new Claim(ClaimTypes.GroupSid,channel.ToString()),//渠道来源
                new Claim(ClaimTypes.Sid, user.F_UserCode),//用户账号
                new Claim(ClaimTypes.Name, user.F_UserName),//用户名字
                new Claim(ClaimTypes.Role, user.F_RoleId.ToString()),//角色id
                new Claim("RoleCode", roleinfo.F_RoleCode),//角色code
                new Claim(ClaimTypes.DenyOnlySid, user.F_WxOpenId),//微信id
                new Claim(ClaimTypes.Expiration,DateTime.Now.AddSeconds(permissionRequirement.Expiration.TotalSeconds).ToString())
            };
            //用户标识
            var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
            identity.AddClaims(claims);

            var jwt_token = JwtToken.BuildJwtToken(claims, permissionRequirement);
            #endregion

            await AddLogAsync(usercode, "token更新成功", ip, user.F_UserId, channel);
             
            var result = new
            {
                username = user.F_UserName,
                usercode = user.F_UserCode,
                token = jwt_token,
                seat_flag = user.F_SeatFlag,
                group = seatgroupcode,
                role_name = roleinfo.F_RoleName,
                role_id = roleinfo.F_RoleId,
                role_code = roleinfo.F_RoleCode,
                dept_id = user.F_DeptId,
                mobile = user.F_Mobile,
            };

            return Success("token更新成功！", result);

        }

        [HttpPost("/api/logout")]
        public IActionResult LogoutAsync()
        {
            return Ok();
        }

        [AllowAnonymous]
        [HttpGet("/api/denied")]
        public IActionResult Denied()
        {
            return new JsonResult(new
            {
                Status = false,
                Message = "无权限访问"
            });
        }


        #region 私有方法
        /// <summary>
        /// 存储登录日志
        /// </summary>
        /// <param name="code"></param>
        /// <param name="log"></param>
        /// <param name="ip"></param>
        /// <param name="userid"></param>
        /// <returns></returns>
        private async Task AddLogAsync(string code, string log, string ip,int userid, int channel)
        {
            var login_log = new T_Sys_LoginLogs()
            {
                F_LoginCode = code,
                F_LoginIP = ip,
                F_LoginId=userid,
                F_State=0,
                F_Result= log,
                F_LoginDate = DateTime.Now,
                F_Channel=channel
            };

            if (await _sys_login_logsRepository.Add(login_log)<=0)
            {
                LogDefault.Error($"{code}登录日志存储异常，登录IP地址为{ip}");
            }
           
        }

        #endregion
    }
}