using Dapper;
using Ewide.Core;
using Ewide.Core.Extension;
using Ewide.Core.Service;
using Furion.DatabaseAccessor;
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System;

namespace Ewide.Application.Service
{
    [ApiDescriptionSettings(Name = "HouseMember")]
    public class HouseMemberService : IHouseMemberService, IDynamicApiController, ITransient
    {
        private readonly IDapperRepository _dapperRepository;

        private readonly IRepository<SysUser> _sysUserRep;  // 用户表仓储 
        private readonly IUserManager _userManager;
        private readonly ISysUserService _sysUserService;
        private readonly ISysEmpService _sysEmpService;

        public HouseMemberService(
            IDapperRepository dapperRepository,
            IRepository<SysUser> sysUserRep,
            IUserManager userManager,
            ISysUserService sysUserService,
            ISysEmpService sysEmpService
        )
        {
            _dapperRepository = dapperRepository;
            _sysUserRep = sysUserRep;
            _userManager = userManager;
            _sysUserService = sysUserService;
            _sysEmpService = sysEmpService;
        }

        /// <summary>
        /// 分页查询用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/houseMember/page")]
        public async Task<dynamic> QueryMemberPageList([FromBody] UserInput input)
        {
            var dataScopes = await _userManager.GetUserAllDataScopeList();

            var sql = @"SELECT
SU.*,
SO.Name OrgName,
SUR.RoleName,
SUR.RoleCode
FROM sys_user SU
LEFT JOIN sys_emp SE ON SU.Id = SE.Id
LEFT JOIN sys_org SO ON SE.OrgId = SO.Id
LEFT JOIN (
	SELECT
		SUR.SysUserId,
		GROUP_CONCAT(SR.Name) RoleName,
		GROUP_CONCAT(SR.Code) RoleCode
	FROM sys_user_role SUR
	LEFT JOIN sys_role SR ON SUR.SysRoleId = SR.Id
	GROUP BY SUR.SysUserId
) SUR ON SU.Id = SUR.SysUserId
WHERE 1=1";
            var param = new DynamicParameters();

            if (!string.IsNullOrEmpty(input.SearchValue))
            {
                sql += @" AND (SU.Account Like @SearchValue
                OR SU.Name Like @SearchValue
                OR SU.Phone Like @SearchValue)";
                param.Add("SearchValue", "%" + input.SearchValue + "%");
            }

            if (!string.IsNullOrEmpty(input.SysEmpParam.OrgId))
            {
                var filter = " AND (SO.Id = @OrgId {0}) ";
                filter = String.Format(filter, input.TreeNodeDataScope.GetValueOrDefault(1) == 2 ? " OR SO.Pids Like CONCAT('%[', @OrgId, ']%') " : "");
                sql += filter;
                param.Add("OrgId", input.SysEmpParam.OrgId);
            }

            if (input.SearchStatus >= 0)
            {
                sql += " AND SU.Status = @Status";
                param.Add("Status", input.SearchStatus);
            }

            if (!_userManager.SuperAdmin)
            {
                sql += " AND SU.AdminType <> @AdminType";
                param.Add("AdminType", AdminType.SuperAdmin);

                sql += " AND SU.Id <> @UserId";
                param.Add("UserId", _userManager.UserId);

                if (dataScopes.Count > 0)
                {
                    sql += " AND SO.Id IN @OrgIds";
                    param.Add("OrgIds", dataScopes.ToArray());
                }
            }

            var users = await _dapperRepository.QueryPageData<UserOutput>(sql, input, param);

            //foreach (var user in users.Items)
            //{
            //    user.SysEmpInfo = await _sysEmpService.GetEmpInfo(user.Id);
            //}
            return PageDataResult<UserOutput>.PageResult(users);
        }

        /// <summary>
        /// 增加用户       
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/houseMember/add")]
        [UnitOfWork]
        public async Task AddUser(AddHouseMemberInput input)
        {
            var id = await _sysUserService.AddUser(input);
            var grantRoleInput = input.Adapt<UpdateUserInput>();
            grantRoleInput.Id = id;

            // 添加角色
            grantRoleInput.GrantRoleIdList.Add(input.RoleId);
            await _sysUserService.GrantUserRole(grantRoleInput);
        }

        /// <summary>
        /// 获取角色
        /// </summary>
        /// <param name="orgId"></param>
        /// <returns></returns>
        [HttpGet("/houseMember/defaultRole")]
        public async Task<dynamic> DefaultRole([FromQuery] string orgId)
        {
            return (await GetDefaultRole(orgId)).Adapt<RoleOutput>();
        }

        /// <summary>
        /// 获取用户拥有角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/houseMember/ownRole")]
        public async Task<dynamic> GetUserOwnRole([FromQuery] QueryUserInput input)
        {
            return await _sysUserService.GetUserOwnRole(input);
        }

        [HttpGet("/houseMember/defaultRoleRange")]
        public async Task<dynamic> DefaultRoleRange()
        {
            return (await GetRoleRange()).Select(p => p.Adapt<RoleOutput>()).ToList();
        }

        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/houseMember/delete")]
        [UnitOfWork]
        public async Task DeleteUser(DeleteUserInput input)
        {
            /*
             * 未处理逻辑
             * 片区监管员在本片区已有安全员的情况下无法删除
             */

            await _sysUserService.DeleteUser(input);
        }

        /// <summary>
        /// 更新用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/houseMember/edit")]
        [UnitOfWork]
        public async Task UpdateUser(UpdateUserInput input)
        {
            /*
             * 未处理逻辑
             * 如果移动组织架构,会产生以下几种逻辑
             * 片区1监管员(无安全员或有其他监管员)=>片区2,直接成功
             * 片区1监管员(有安全员并且无其他监管员)=>片区2,无法移动
             * 片区1安全员=>片区2(有监管员),直接成功
             * 片区1安全员=>片区2(无监管员),无法移动,需要创建监管员
             */

            await _sysUserService.UpdateUser(input);
        }

        /// <summary>
        /// 查看用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/houseMember/detail")]
        public async Task<dynamic> GetUser([FromQuery] QueryUserInput input)
        {
            var sql = @"SELECT
SU.*,
SO.Name OrgName,
SUR.RoleName,
SUR.RoleCode
FROM sys_user SU
LEFT JOIN sys_emp SE ON SU.Id = SE.Id
LEFT JOIN sys_org SO ON SE.OrgId = SO.Id
LEFT JOIN (
	SELECT
		SUR.SysUserId,
		GROUP_CONCAT(SR.Name) RoleName,
		GROUP_CONCAT(SR.Code) RoleCode
	FROM sys_user_role SUR
	LEFT JOIN sys_role SR ON SUR.SysRoleId = SR.Id
	GROUP BY SUR.SysUserId
) SUR ON SU.Id = SUR.SysUserId
WHERE SU.Id=@Id";
            var user = (await _dapperRepository.QueryAsync<UserOutput>(sql, new { input.Id })).SingleOrDefault();
            if (user != null)
            {
                user.SysEmpInfo = await _sysEmpService.GetEmpInfo(user.Id);
            }
            return user;
        }

        /// <summary>
        /// 修改用户状态
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/houseMember/changeStatus")]
        public async Task ChangeUserStatus(UpdateUserInput input)
        {
            await _sysUserService.ChangeUserStatus(input);
        }

        /// <summary>
        /// 授权用户数据范围
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/houseMember/grantData")]
        public async Task GrantUserData(UpdateUserInput input)
        {
            await _sysUserService.GrantUserData(input);
        }

        /// <summary>
        /// 获取用户拥有数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/houseMember/ownData")]
        public async Task<dynamic> GetUserOwnData([FromQuery] QueryUserInput input)
        {
            return await _sysUserService.GetUserOwnData(input);
        }

        /// <summary>
        /// 获取当前机构中所创建的默认角色
        ///     片区中的第一个帐号必定为片区监管员
        /// </summary>
        /// <param name="orgId"></param>
        /// <returns></returns>
        [NonAction]
        private async Task<SysRole> GetDefaultRole(string orgId)
        {
            var roles = await GetRoleRange();
            if (roles.Count < 2) throw Oops.Oh("未配置正确的角色");

            var _sysOrgRep = Db.GetRepository<SysOrg>();
            var org = await _sysOrgRep.DetachedEntities.FirstOrDefaultAsync(p => p.Id == orgId);
            // 如果当前组织为街道, 则直接返回安全员
            if (org == null || org.Type <= (int)OrgType.乡镇街道办事处)
            {
                return roles.LastOrDefault();
            }

            var _sysEmpRep = Db.GetRepository<SysEmp>();
            var _sysUserRoleRep = Db.GetRepository<SysUserRole>();
            var userIds = await _sysEmpRep.DetachedEntities.Where(p => p.OrgId == orgId).Select(p => p.Id).ToListAsync();
            var roleIds = await _sysUserRoleRep.DetachedEntities.Where(p => userIds.Contains(p.SysUserId)).Select(p => p.SysRoleId).ToListAsync();

            var _sysRoleRep = Db.GetRepository<SysRole>();
            var isExistZoneManager = await _sysRoleRep.DetachedEntities.AnyAsync(p => roleIds.Contains(p.Id) && p.Code == Enum.GetName(HouseManagerRole.ZoneManager).ToUnderScoreCase());
            // 存在片区监管员，返回安全员, 否则返回监管员
            if (isExistZoneManager)
            {
                return roles.LastOrDefault();
            }

            return roles.FirstOrDefault();
        }

        /// <summary>
        /// 获取可创建的角色列表
        /// </summary>
        /// <returns></returns>
        [NonAction]
        private async Task<List<SysRole>> GetRoleRange()
        {
            var codes = (new[] {
                Enum.GetName(HouseManagerRole.ZoneManager),
                Enum.GetName(HouseManagerRole.HouseSecurityManager),
            }).Select(p => p.ToUnderScoreCase());

            var _sysRoleRep = Db.GetRepository<SysRole>();
            var roles = await _sysRoleRep.DetachedEntities.Where(p => codes.Contains(p.Code)).ToListAsync();

            return roles;
        }
    }
}
