package com.hz.pm.api.user.manage;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hz.pm.api.common.helper.UserInfoHelper;
import com.hz.pm.api.common.util.BizUtils;
import com.hz.pm.api.common.util.StrUtils;
import com.hz.pm.api.organization.model.entity.DingEmployeeInfo;
import com.hz.pm.api.organization.service.IDingEmployeeInfoService;
import com.hz.pm.api.sys.model.entity.Role;
import com.hz.pm.api.sys.model.entity.UserRole;
import com.hz.pm.api.sys.service.IRoleService;
import com.hz.pm.api.sys.service.IUserRoleService;
import com.hz.pm.api.user.model.entity.UserInfo;
import com.hz.pm.api.user.model.enumeration.UserAvailableEnum;
import com.hz.pm.api.user.model.po.ReqUserDetailEditPO;
import com.hz.pm.api.user.model.po.ReqUserDisableOrEnablePO;
import com.hz.pm.api.user.model.po.UserDetailReq;
import com.hz.pm.api.user.model.po.UserInfoListReq;
import com.hz.pm.api.user.model.vo.ResUserDetailVO;
import com.hz.pm.api.user.model.vo.UserInfoListVO;
import com.hz.pm.api.user.model.vo.UserRoleVO;
import com.hz.pm.api.user.security.model.UserFullInfoDTO;
import com.hz.pm.api.user.service.IUserInfoService;
import com.hz.pm.api.user.util.LoginUserUtil;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.wflow.workflow.bean.dto.ProcessInstanceUserDto;
import lombok.RequiredArgsConstructor;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liuxinxin
 * @since 2023/2/13 上午9:09
 */
@Component
@RequiredArgsConstructor
public class UserInfoManage {

    private final UserAuthManage userAuthManage;
    private final IUserInfoService userInfoService;
    private final IRoleService roleService;
    private final IDingEmployeeInfoService dingEmployeeInfoService;
    private final IUserRoleService userRoleService;
    private final UserInfoHelper userInfoHelper;

    public PageVo<UserInfoListVO> list(UserInfoListReq req) {
        List<Long> userIdList = getRoleCompliantUserIdList(req.getUserRoleList());
        if (userIdList != null && userIdList.isEmpty()) {
            return PageVo.empty();
        }
        LambdaQueryWrapper<UserInfo> wrapper = Wrappers.lambdaQuery(UserInfo.class)
                .eq(StrUtils.isNotBlank(req.getPhoneNo()), UserInfo::getMobile, req.getPhoneNo())
                .like(StrUtils.isNotBlank(req.getName()), UserInfo::getRealName, req.getName())
                .in(Objects.nonNull(userIdList), UserInfo::getId, userIdList)
                .like(StrUtils.isNotBlank(req.getMhUnitName()), UserInfo::getMhUnitName, req.getMhUnitName())
                .eq(Objects.nonNull(req.getMhUnitId()), UserInfo::getMhUnitId, req.getMhUnitId())
                .orderByDesc(UserInfo::getUpdateOn);

        Page<UserInfo> page = userInfoService.page(req.page(), wrapper);
        if (page.getTotal() == 0) {
            return PageVo.empty();
        }
        List<UserInfoListVO> result = new ArrayList<>();
        page.getRecords().forEach(r -> {
            UserInfoListVO item = new UserInfoListVO();
            item.setName(r.getRealName());
            userStatusBuilder(item, r);
            item.setUpdateTime(r.getUpdateOn());
            item.setEmployeeCode(r.getEmployeeCode());
            item.setUserRoleList(getUserRole(item.getUserId()));
            item.setUserId(r.getId());
            item.setPhoneNo(r.getMobile());
            item.setMhUnitId(r.getMhUnitId());
            item.setMhUnitName(r.getMhUnitName());
            result.add(item);
        });
        return PageVo.of(result, page.getTotal());
    }

    /**
     * 获取符合查询条件的 用户 userId
     *
     * @param user
     */
    @SuppressWarnings("all")
    private List<Long> getRoleCompliantUserIdList(List<UserRoleVO> userRoles) {
        if (CollUtil.isNotEmpty(userRoles)) {
            userRoles.removeIf(r -> Objects.isNull(r.getId()));
        }
        if (CollUtil.isEmpty(userRoles)) {
            return null;
        }
        List<Long> roleIds = CollUtils.fieldList(userRoles, UserRoleVO::getId);
        LambdaQueryWrapper<UserRole> urQuery = Wrappers.lambdaQuery(UserRole.class)
                .select(UserRole::getUserId).in(UserRole::getRoleId,roleIds);
        return userRoleService.listUserIdByRoleIds(roleIds);
    }

    /**
     * 装配用户状态 及 userId
     *
     * @param resUser  \
     * @param userInfo \
     */
    private static void userStatusBuilder(UserInfoListVO resUser, UserInfo userInfo) {
        if (Objects.nonNull(userInfo)) {
            resUser.setPhoneNo(userInfo.getMobile());
            if (StringUtils.isNotBlank(userInfo.getAvailable())
                    && UserAvailableEnum.ENABLE.name().equals(userInfo.getAvailable())) {
                resUser.setStatus(UserAvailableEnum.ENABLE.name());
            } else {
                resUser.setStatus(UserAvailableEnum.DISABLE.name());
            }
            resUser.setUserId(userInfo.getId());
        } else {
            resUser.setStatus(UserAvailableEnum.DISABLE.name());
        }
    }


    private List<UserRoleVO> getUserRole(Long userId) {
        List<UserRoleVO> userRoleInfoList = new ArrayList<>();
        if (Objects.isNull(userId)) {
            return userRoleInfoList;
        }
        List<UserRole> userRoleList = userRoleService.list(Wrappers.lambdaQuery(UserRole.class)
                .eq(UserRole::getUserId, userId).orderByAsc(UserRole::getCreateOn));
        if (CollUtil.isNotEmpty(userRoleList)) {
            List<Long> roleIdList = userRoleList.stream().map(UserRole::getRoleId).collect(Collectors.toList());
            List<Role> roleList = roleService.listByIds(roleIdList);
            roleList.forEach(r -> {
                UserRoleVO userRoleVO = new UserRoleVO();
                userRoleVO.setId(r.getId());
                userRoleVO.setName(r.getName());
                userRoleVO.setCreateOn(r.getCreateOn());
                userRoleInfoList.add(userRoleVO);
            });
        }
        return userRoleInfoList;
    }

    @Transactional(rollbackFor = Exception.class)
    public void disableOrEnable(ReqUserDisableOrEnablePO req) {
        Long userId;
        if (req.getUserId() != null) {
            userId = req.getUserId();
        } else if (StrUtils.isNotBlank(req.getEmployeeCode())) {
            UserInfoManage proxy = (UserInfoManage) AopContext.currentProxy();
            userId = proxy.generateUserId(req.getEmployeeCode());
        } else {
            throw BizException.wrap("用户参数缺失");
        }
        UserInfo userInfo = userInfoService.getById(userId);
        userInfo.setAvailable(req.getOperation());
        userInfoService.updateById(userInfo);
        if ("DISABLE".equals(userInfo.getAvailable())) {
            userAuthManage.kickOff(userId);
        }

    }

    public ResUserDetailVO userInfoDetail(UserDetailReq req) {
        Long userId = req.getUserId();
        String employeeCode = req.getEmployeeCode();
        if (StrUtils.isBlank(employeeCode) && Objects.isNull(userId)) {
            throw new IllegalArgumentException("参数缺失");
        }
        UserInfo userInfo = userInfoService.getById(userId);
        if (Objects.isNull(userInfo)) {
            return null;
        }
        ResUserDetailVO resUserDetail = new ResUserDetailVO();
        resUserDetail.setRealName(userInfo.getRealName());
        resUserDetail.setUserId(userInfo.getId());
        resUserDetail.setPhoneNo(userInfo.getMobile());
        resUserDetail.setStatus(userInfo.getAvailable());

        // 装配用户角色信息列表
        List<UserRole> userRoleList = userRoleService.listByUserId(userId);
        if (CollUtil.isNotEmpty(userRoleList)) {
            List<Long> roleIdList = CollUtils.fieldList(userRoleList, UserRole::getRoleId);
            List<Role> roleList = roleService.listByIds(roleIdList);
            List<UserRoleVO> userRoles = roleList.stream().map(r -> {
                UserRoleVO userRoleVO = new UserRoleVO();
                userRoleVO.setId(r.getId());
                userRoleVO.setName(r.getName());
                return userRoleVO;
            }).collect(Collectors.toList());
            resUserDetail.setUserRoleInfoList(userRoles);
        }
        return resUserDetail;
    }

    @Transactional(rollbackFor = Exception.class)
    public void userInfoDetailEdit(ReqUserDetailEditPO reqUserDetailEditPO) {
        Long userId = reqUserDetailEditPO.getUserId();
        if (Objects.isNull(userId)) {
            String employeeCode = reqUserDetailEditPO.getEmployeeCode();
            if (StringUtils.isBlank(employeeCode)) {
                throw new IllegalArgumentException("employeeCode can't be null");
            }
            userId = generateUserId(employeeCode);
        }
        UserInfo userInfo = userInfoService.getById(userId);
        String oldUserStatus = userInfo.getAvailable();
        // 绑定用户手机号
        bandUserMobile(userInfo, reqUserDetailEditPO);

        userInfo.setAvailable(reqUserDetailEditPO.getStatus());
        userInfo.setUpdateOn(LocalDateTime.now());
        userInfo.setUpdateBy(LoginUserUtil.getUserId());
        userInfoService.updateById(userInfo);

        List<UserRoleVO> userRoleInfoList = reqUserDetailEditPO.getUserRoleInfoList();
        userRoleService.remove(Wrappers.lambdaQuery(UserRole.class).eq(UserRole::getUserId, userId));
        if (CollUtil.isNotEmpty(userRoleInfoList)) {
            Long finalUserId = userId;
            List<UserRole> userRoleList = userRoleInfoList.stream().map(r -> {
                UserRole saveRecord = new UserRole();
                saveRecord.setRoleId(r.getId());
                saveRecord.setUserId(finalUserId);
                return saveRecord;
            }).collect(Collectors.toList());
            userRoleService.saveBatch(userRoleList);
        }
        // 刷新用户权限 仅原状态为正常才需要刷新session
        if ("ENABLE".equals(oldUserStatus)) {
            if (oldUserStatus.equals(userInfo.getAvailable())) {
                userAuthManage.refreshSession(userId);
            } else {
                userAuthManage.kickOff(userId);
            }
        }
    }

    /**
     * 绑定用户手机号
     *
     * @param userInfo
     * @param reqUserDetailEditPO
     */
    @Transactional(rollbackFor = Exception.class)
    public void bandUserMobile(UserInfo userInfo, ReqUserDetailEditPO reqUserDetailEditPO) {
        String employeeCode = reqUserDetailEditPO.getEmployeeCode();
        Long userId = userInfo.getId();
        // 校验手机号是否重复
        UserInfo repeatMobileUserInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getMobile, reqUserDetailEditPO.getPhoneNo()).ne(UserInfo::getId, userId));
        if (Objects.nonNull(repeatMobileUserInfo)) {
            throw new BizException("该手机号码已被绑定，请问重复绑定");
        }

        String phoneNo = reqUserDetailEditPO.getPhoneNo();
        userInfo.setMobile(phoneNo);
        // 更新浙政钉相关数据
        if (StringUtils.isNotBlank(phoneNo)) {
            dingEmployeeInfoService
                    .update(Wrappers.lambdaUpdate(DingEmployeeInfo.class)
                            .eq(DingEmployeeInfo::getMainJob, "true")
                            .eq(DingEmployeeInfo::getEmployeeCode, employeeCode)
                            .set(DingEmployeeInfo::getBindUserMobile, phoneNo));
            userInfoService.updateById(userInfo);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Long generateUserId(String employeeCode) {
        UserInfo userInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getEmployeeCode, employeeCode));
        if (Objects.isNull(userInfo)) {
            List<DingEmployeeInfo> dingEmployeeInfoList = dingEmployeeInfoService
                    .list(Wrappers.lambdaQuery(DingEmployeeInfo.class)
                            .eq(DingEmployeeInfo::getEmployeeCode, employeeCode)
                            .eq(DingEmployeeInfo::getMainJob, "true"));
            if (CollUtil.isEmpty(dingEmployeeInfoList)) {
                throw new BizException("员工账号不存在");
            }
            DingEmployeeInfo dingEmployeeInfo = dingEmployeeInfoList.get(0);
            userInfo = UserInfo.builder()
                    .accountId(dingEmployeeInfo.getAccountId())
                    .username(dingEmployeeInfo.getEmployeeName())
                    .realName(dingEmployeeInfo.getEmployeeName())
                    .employeeCode(dingEmployeeInfo.getEmployeeCode())
                    .available(UserAvailableEnum.DISABLE.name())
                    .createBy(-1L)
                    .updateBy(-1L)
                    .createOn(LocalDateTime.now())
                    .updateOn(LocalDateTime.now())
                    .build();
            userInfoService.save(userInfo);
        }
        return userInfo.getId();
    }


    public ResUserDetailVO currentUserInfo() {
        Long userId = LoginUserUtil.getUserId();
        UserInfo userInfo = userInfoService.getById(userId);
        if (Objects.isNull(userInfo)) {
            return null;
        }
        ResUserDetailVO resUserDetail = new ResUserDetailVO();
        resUserDetail.setRealName(userInfo.getRealName());
        resUserDetail.setUserId(userInfo.getId());
        resUserDetail.setPhoneNo(userInfo.getMobile());
        resUserDetail.setStatus(userInfo.getAvailable());
        resUserDetail.setEmployeeCode(userInfo.getEmployeeCode());
        resUserDetail.setMhUnitId(userInfo.getMhUnitId());
        resUserDetail.setMhUnitName(userInfo.getMhUnitName());

        // 装配用户角色信息列表
        List<UserRole> userRoleList = userRoleService.listByUserId(userId);
        if (CollUtil.isNotEmpty(userRoleList)) {
            List<Long> roleIdList = CollUtils.fieldList(userRoleList, UserRole::getRoleId);
            List<Role> roleList = roleService.listByIds(roleIdList);
            List<UserRoleVO> userRoles = roleList.stream().map(r -> {
                UserRoleVO userRole = new UserRoleVO();
                userRole.setId(r.getId());
                userRole.setName(r.getName());
                userRole.setCode(r.getCode());
                return userRole;
            }).collect(Collectors.toList());
            resUserDetail.setUserRoleInfoList(userRoles);
        }
        return resUserDetail;
    }

    public Map<String, ProcessInstanceUserDto> getUserMapByUserIds(Collection<Long> staterUsers) {
        if (CollUtil.isEmpty(staterUsers)) {
            return Collections.emptyMap();
        }
        List<UserInfo> userInfos = userInfoService.listByIds(staterUsers);
        if (CollUtil.isEmpty(userInfos)) {
            return Collections.emptyMap();
        }
        return userInfos.stream().map(u -> {
            ProcessInstanceUserDto userInfo = new ProcessInstanceUserDto();
            userInfo.setUserId(String.valueOf(u.getId()));
            userInfo.setUserName(u.getRealName());
            userInfo.setOrgCode(String.valueOf(u.getMhUnitId()));
            userInfo.setOrgName(u.getMhUnitName());
            return userInfo;
        }).collect(Collectors.toMap((ProcessInstanceUserDto::getUserId), v -> v));
    }

    /**
     * 获取当前用户可控角色列表
     *
     * @return
     */
    public List<UserRoleVO> getControlledRoleList() {
        Long userId = LoginUserUtil.getUserId();
        // 装配用户角色信息列表
        List<UserRole> userRoleList = userRoleService.list(Wrappers.lambdaQuery(UserRole.class)
                .eq(UserRole::getUserId, userId));

        List<UserRoleVO> controlledRoleVOList = new ArrayList<>();
        List<Long> controlledRoleIdList = new ArrayList<>();
        if (CollUtil.isNotEmpty(userRoleList)) {
            List<Long> roleIdList = userRoleList.stream().map(UserRole::getRoleId).distinct().collect(Collectors.toList());

            List<Role> roleList = roleService.list(Wrappers.lambdaQuery(Role.class).in(Role::getId, roleIdList));

            for (Role role : roleList) {
                List<Long> manageRoleIdList = BizUtils.splitToLong(role.getManageRoleIds());
                if (CollUtil.isNotEmpty(manageRoleIdList)) {
                    controlledRoleIdList.addAll(manageRoleIdList);
                }
            }
            controlledRoleIdList = controlledRoleIdList.stream().distinct().collect(Collectors.toList());
            List<Role> controlledRoleList = roleService.list(Wrappers.lambdaQuery(Role.class).in(Role::getId, controlledRoleIdList));

            controlledRoleVOList = controlledRoleList.stream().map(r -> {
                UserRoleVO userRoleVO = new UserRoleVO();
                userRoleVO.setId(r.getId());
                userRoleVO.setName(r.getName());
                userRoleVO.setCode(r.getCode());
                return userRoleVO;
            }).collect(Collectors.toList());
        }
        return controlledRoleVOList;
    }

    /**
     * 根据用户名获取
     *
     * @param username /
     * @return /
     */
    public UserFullInfoDTO queryUserInfoInPasswordAuth(String username) {
        // TODO 目前账号密码登陆测试使用 强制用户登录 userId 1L
        UserInfo userInfo = userInfoService.getById(username);
        if (Objects.isNull(userInfo)) {
            return null;
        }
        // 返回用户全量信息
        return userInfoHelper.getUserFullInfo(userInfo);
    }

    /**
     * 根据手机号获取
     *
     * @param phoneNo /
     * @return /
     */
    public UserFullInfoDTO queryUserInfoInPhoneNoAuth(String phoneNo) {
        UserInfo userInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getMobile, phoneNo));
        if (Objects.isNull(userInfo)) {
            return null;
        }
        // 返回用户全量信息
        return userInfoHelper.getUserFullInfo(userInfo);
    }

    /**
     * 根据accountId(浙政钉扫码登陆)
     *
     * @param accountId /
     * @return /
     */
    public UserFullInfoDTO queryUserInfoInAccountIdAuth(String accountId) {

        // 获取用户信息
        UserInfo userInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getAccountId, accountId));
        if (Objects.isNull(userInfo)) {
            return null;
        }
        // 返回用户全量信息
        return userInfoHelper.getUserFullInfo(userInfo);
    }

    public UserFullInfoDTO getUserFullInfoByEmployeeCode(String employeeCode) {
        UserInfo userInfo = userInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getEmployeeCode, employeeCode).last("limit 1"));
        if (Objects.isNull(userInfo)) {
            return null;
        }
        // 返回用户全量信息
        return userInfoHelper.getUserFullInfo(userInfo);
    }

}
