using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using Performance.DtoModels;
using Performance.DtoModels.AppSettings;
using Performance.EntityModels;
using Performance.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;

namespace Performance.Api.Controllers
{
    [Route("api/[controller]")]
    public class AccountController : Controller
    {
        private UserService _userService;
        private RoleService _roleService;
        private IMemoryCache _memoryCache;
        private Application _options;
        private ClaimService _claim;
        private HospitalService _hospitalService;

        public AccountController(UserService userService,
            HospitalService hospitalService,
            RoleService roleService,
            IMemoryCache memoryCache,
            IOptions<Application> options,
            ClaimService claim)
        {
            _userService = userService;
            _roleService = roleService;
            _memoryCache = memoryCache;
            _hospitalService = hospitalService;
            _options = options.Value;
            _claim = claim;
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <remarks>
        /// Sample request:
        ///
        ///     POST /Todo
        ///     {
        ///       "logintype": 2,
        ///       "account": "admin",
        ///       "password": "1111",
        ///       "appname": "string",
        ///       "device": "web"
        ///     }
        ///
        /// </remarks>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("login")]
        [AllowAnonymous]
        public ApiResponse<JwtToken> Login([FromBody] LoginRequest request)
        {
            var user = _userService.Login(request);
            if (user == null)
                return new ApiResponse<JwtToken>(ResponseType.Fail, "用户不存在");

            var claims = new Claim[]
            {
                new Claim(JwtClaimTypes.Id, user.UserID.ToString()),
                new Claim(JwtClaimTypes.Login, user.Login),
                new Claim(JwtClaimTypes.RealName,  user.RealName),
                new Claim(JwtClaimTypes.Mail, user.Mail??""),
                new Claim(JwtClaimTypes.AppName, request.AppName ?? ""),
                new Claim(JwtClaimTypes.Device, request.Device ?? ""),
                new Claim(JwtClaimTypes.Department, user.Department ?? ""),
            };

            var jwtToken = JwtTokenHelper.GenerateToken(claims, _options.ExpirationMinutes);
            return new ApiResponse<JwtToken>(ResponseType.OK, jwtToken);
        }

        /// <summary>
        /// 刷新登录JWT TOKEN
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("refresh")]
        public ApiResponse<JwtToken> Refresh()
        {
            var userClaim = _claim.GetUserClaim();
            var claims = new Claim[]
            {
                new Claim(JwtClaimTypes.Id, userClaim.FirstOrDefault(t => t.Type == JwtClaimTypes.Id)?.Value??""),
                new Claim(JwtClaimTypes.Login, userClaim.FirstOrDefault(t => t.Type == JwtClaimTypes.Login)?.Value??""),
                new Claim(JwtClaimTypes.RealName,  userClaim.FirstOrDefault(t => t.Type == JwtClaimTypes.RealName)?.Value??""),
                new Claim(JwtClaimTypes.Mail, userClaim.FirstOrDefault(t => t.Type == JwtClaimTypes.Mail)?.Value??""),
                new Claim(JwtClaimTypes.AppName, userClaim.FirstOrDefault(t => t.Type == JwtClaimTypes.AppName)?.Value??""),
                new Claim(JwtClaimTypes.Device, userClaim.FirstOrDefault(t => t.Type == JwtClaimTypes.Device)?.Value??""),
                new Claim(JwtClaimTypes.Department, userClaim.FirstOrDefault(t => t.Type == JwtClaimTypes.Department)?.Value??""),
            };

            var jwtToken = JwtTokenHelper.GenerateToken(claims, _options.ExpirationMinutes);
            // 设置当前请求Jwt失效
            var jwt = _claim.GetJwtToken();
            //claimService.SetJwtBlacklist(jwt);

            return new ApiResponse<JwtToken>(ResponseType.OK, jwtToken);
        }

        /// <summary>
        /// 查询个人信息
        /// </summary>
        /// <returns></returns>
        [Route("selfinfo")]
        [HttpPost]
        public ApiResponse SelfInfo()
        {
            var userid = _claim.GetUserId();
            var user = _userService.GetUser(userid);
            user.Role = _roleService.GetUserRole(user.UserID);
            user.Hospital = _hospitalService.GetUserHopital(user.UserID);

            int[] roleArray = new int[] { _options.NurseRole, _options.DirectorRole, _options.SpecialRole, _options.OfficeRole };
            user.IsAgainAdmin = user.Role != null ? roleArray.Contains(user.Role.First().Type ?? 0) : false;
            return new ApiResponse(ResponseType.OK, user);
        }

        /// <summary>
        /// 修改个人信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("updateself")]
        [HttpPost]
        public ApiResponse<UserResponse> UpdateSelf([CustomizeValidator(RuleSet = "Self"), FromBody] UserRequest request)
        {
            request.ID = _claim.GetUserId();
            var user = _userService.UpdateSelf(request);
            return new ApiResponse<UserResponse>(ResponseType.OK, user);
        }

        /// <summary>
        /// 用户列表
        /// </summary>
        /// <returns></returns>
        [Route("list")]
        [HttpPost]
        public ApiResponse<List<UserResponse>> List()
        {
            var userList = _userService.GetUserList(_claim.GetUserId());
            return new ApiResponse<List<UserResponse>>(ResponseType.OK, "ok", userList);
        }

        /// <summary>
        /// 新增用户
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("insert")]
        [HttpPost]
        public ApiResponse<UserResponse> Insert([CustomizeValidator(RuleSet = "Insert"), FromBody] UserRequest request)
        {
            var userId = _claim.GetUserId();
            var user = _userService.Insert(request, userId);
            user.Role = request.Role;
            return new ApiResponse<UserResponse>(ResponseType.OK, user);
        }

        /// <summary>
        /// 新增用户
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("delete")]
        [HttpPost]
        public ApiResponse Delete([CustomizeValidator(RuleSet = "Delete"), FromBody] UserRequest request)
        {
            return _userService.Delete(request.ID);
        }

        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("update")]
        [HttpPost]
        public ApiResponse<UserResponse> Update([CustomizeValidator(RuleSet = "Update"), FromBody] UserRequest request)
        {
            var userId = _claim.GetUserId();

            int[] roleArray = new int[] { _options.NurseRole, _options.DirectorRole, _options.SpecialRole, _options.OfficeRole };
            var roles = _roleService.GetUserRole(userId);
            var isAgainAdmin = roles != null ? roleArray.Contains(roles.First().Type ?? 0) : false;

            var user = _userService.Update(request, isAgainAdmin);
            user.Role = request.Role;
            return new ApiResponse<UserResponse>(ResponseType.OK, user);
        }

        /// <summary>
        /// 修改用户密码
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("password")]
        [HttpPost]
        public ApiResponse<UserResponse> Password([FromBody] PasswordRequest request)
        {
            var userid = _claim.GetUserId();
            var user = _userService.UpdatePwd(request, userid);
            return new ApiResponse<UserResponse>(ResponseType.OK, user);
        }

        /// <summary>
        /// 角色列表
        /// </summary>
        /// <returns></returns>
        [Route("rolelist")]
        [HttpPost]
        public ApiResponse<List<sys_role>> RoleList()
        {
            var userid = _claim.GetUserId();
            var roleList = _userService.RoleList(userid);
            return new ApiResponse<List<sys_role>>(ResponseType.OK, "ok", roleList);
        }

        /// <summary>
        /// 科室列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("department")]
        [HttpPost]
        public ApiResponse<List<TitleValue>> Department([FromBody] SetDepartmentRequest request)
        {
            var department = _userService.Department(request.HospitalID);
            return new ApiResponse<List<TitleValue>>(ResponseType.OK, "ok", department);
        }

        /// <summary>
        /// 演示用户
        /// </summary>
        /// <returns></returns>
        [Route("demo/users")]
        [HttpPost]
        public ApiResponse<List<TitleValue<int>>> DemoUsers()
        {
            var users = _userService.GetDemoUsers();
            return new ApiResponse<List<TitleValue<int>>>(ResponseType.OK, users);
        }

        /// <summary>
        /// 更换角色获取Token
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        [Route("demo/token/{userId}")]
        [HttpPost]
        public ApiResponse<JwtToken> DemoUsers(int userId)
        {
            if (userId < 1)
                return new ApiResponse<JwtToken>(ResponseType.ParameterError, "用户不存在,请先创建!");

            var user = _userService.GetDemoUserIdentity(userId);
            var userClaim = _claim.GetUserClaim();
            var claims = new Claim[]
            {
                new Claim(JwtClaimTypes.Id, user.UserID.ToString()),
                new Claim(JwtClaimTypes.Login, user.Login),
                new Claim(JwtClaimTypes.RealName,  user.RealName),
                new Claim(JwtClaimTypes.Mail, user.Mail??""),
                new Claim(JwtClaimTypes.AppName, userClaim.FirstOrDefault(t => t.Type == JwtClaimTypes.AppName)?.Value??""),
                new Claim(JwtClaimTypes.Device,userClaim.FirstOrDefault(t => t.Type == JwtClaimTypes.Device)?.Value??""),
                new Claim(JwtClaimTypes.Department, user.Department ?? ""),
            };

            var jwtToken = JwtTokenHelper.GenerateToken(claims, _options.ExpirationMinutes);
            return new ApiResponse<JwtToken>(ResponseType.OK, jwtToken);
        }

        /// <summary>
        /// 修改用户密码
        /// </summary>
        /// <param name="userId">用户id</param>
        /// <returns></returns>
        [Route("reset/{userId}")]
        [HttpPost]
        public ApiResponse<UserResponse> Password(int userId)
        {
            var loginUserId = _claim.GetUserId();
            var user = _userService.ResetPwd(userId, loginUserId);
            return new ApiResponse<UserResponse>(ResponseType.OK, user);
        }


        #region 多角色

        /// <summary>
        /// 查询用户信息
        /// </summary>
        /// <returns></returns>
        [Route("selfInfos")]
        [HttpPost]
        public ApiResponse SelfInfos([FromBody] UserRequest request)
        {
            var userid = _claim.GetUserId();
            var user = _userService.GetUser(userid);
            user.Role = _roleService.GetUsersRole(user.UserID);
            user.Hospital = _hospitalService.GetUserHopital(user.UserID);

            int[] roleArray = new int[] { _options.NurseRole, _options.DirectorRole, _options.SpecialRole, _options.OfficeRole };
            if (request.Role <= 0)
                user.IsAgainAdmin = user.Role != null ? roleArray.Contains(user.Role.First().Type ?? 0) : false;
            else
                user.IsAgainAdmin = user.Role != null ? roleArray.Contains(user.Role.First(t=>t.RoleID==request.Role).Type ?? 0) : false;
            return new ApiResponse(ResponseType.OK, user);
        }

        /// <summary>
        /// 新增用户
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("InsertUser")]
        [HttpPost]
        public ApiResponse<UserResponse> InsertUser([CustomizeValidator(RuleSet = "Insert"), FromBody] UserRequest request)
        {
            var userId = _claim.GetUserId();
            var user = _userService.InsertUser(request, userId);
            user.RoleArr = request.RoleArr;
            return new ApiResponse<UserResponse>(ResponseType.OK, user);
        }

        /// <summary>
        /// 编辑用户
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("UpdateUser")]
        [HttpPost]
        public ApiResponse<UserResponse> UpdateUser([CustomizeValidator(RuleSet = "Update"), FromBody] UserRequest request)
        {
            var userId = _claim.GetUserId();

            int[] roleArray = new int[] { _options.NurseRole, _options.DirectorRole, _options.SpecialRole, _options.OfficeRole };
            var roles = _roleService.GetUsersRole(userId);
            //var roleType = roles.Select(c => c.Type).ToArray();
            var intersect = roleArray.Intersect(roles.Select(c => (int)c.Type).ToArray());
            var isAgainAdmin = roles != null ? intersect.Any() : false;

            var user = _userService.UpdateUser(request, isAgainAdmin);
            user.RoleArr = request.RoleArr;
            return new ApiResponse<UserResponse>(ResponseType.OK, user);
        }

        /// <summary>
        /// 新增用户
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("DeleteUser")]
        [HttpPost]
        public ApiResponse DeleteUser([CustomizeValidator(RuleSet = "Delete"), FromBody] UserRequest request)
        {
            return _userService.DeleteUser(request.ID);
        }

        #endregion

        /// <summary>
        /// 批量新增用户
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [Route("BatchSaveUser")]
        [HttpPost]
        public ApiResponse BatchSaveUser()
        {

            return new ApiResponse(ResponseType.OK);
        }
    }
}