package com.ningdatech.carapi.sys.manage;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.NdJsonUtil;
import com.ningdatech.carapi.common.constant.UserRoleTypeEnum;
import com.ningdatech.carapi.datascope.aop.LambdaDataScope;
import com.ningdatech.carapi.datascope.contants.LambdaDataScopeTypeEnum;
import com.ningdatech.carapi.driver.constant.DriverRegistrationStatusEnum;
import com.ningdatech.carapi.driver.constant.DriverStatusEnum;
import com.ningdatech.carapi.driver.constant.TrainingRegistrationTypeEnum;
import com.ningdatech.carapi.driver.constant.UserCanLoginEnum;
import com.ningdatech.carapi.driver.entity.DriverInfo;
import com.ningdatech.carapi.driver.entity.TrainingRegistrationReview;
import com.ningdatech.carapi.driver.service.IDriverInfoService;
import com.ningdatech.carapi.driver.service.ITrainingRegistrationReviewService;
import com.ningdatech.carapi.sys.convert.UserAuthConverter;
import com.ningdatech.carapi.sys.convert.UserRoleConverter;
import com.ningdatech.carapi.sys.entity.MetaApply;
import com.ningdatech.carapi.sys.entity.Role;
import com.ningdatech.carapi.sys.entity.UserRole;
import com.ningdatech.carapi.sys.entity.dto.CompanyDTO;
import com.ningdatech.carapi.sys.entity.dto.UserPageQuery;
import com.ningdatech.carapi.sys.entity.dto.UserSaveDTO;
import com.ningdatech.carapi.sys.entity.dto.UserUpdateDTO;
import com.ningdatech.carapi.sys.entity.enumeration.BooleanDisplayEnum;
import com.ningdatech.carapi.sys.entity.enumeration.MetaApplyStatusEnum;
import com.ningdatech.carapi.sys.entity.enumeration.MetaApplyTypeEnum;
import com.ningdatech.carapi.sys.entity.vo.UserInfoVO;
import com.ningdatech.carapi.sys.helper.CompaniesCacheHelper;
import com.ningdatech.carapi.sys.service.IMetaApplyService;
import com.ningdatech.carapi.sys.service.RoleService;
import com.ningdatech.carapi.sys.service.UserRoleService;
import com.ningdatech.carapi.user.entity.NdUserAuth;
import com.ningdatech.carapi.user.entity.NdUserInfo;
import com.ningdatech.carapi.user.entity.NdUserInfoJoin;
import com.ningdatech.carapi.user.security.auth.model.UserInfoDetails;
import com.ningdatech.carapi.user.service.INdUserAuthService;
import com.ningdatech.carapi.user.service.INdUserInfoJoinService;
import com.ningdatech.carapi.user.service.INdUserInfoService;
import com.ningdatech.carapi.user.util.LoginUserUtil;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.DesensitizedUtil;
import lombok.RequiredArgsConstructor;

/**
 * @Classname UserRepository
 * @Description
 * @Date 2022/10/12 11:26
 * @Created by PoffyZhang
 */
@Component
@RequiredArgsConstructor
public class UserManage {
    private final INdUserInfoService userInfoService;
    private final INdUserInfoJoinService userInfoJoinService;
    private final INdUserAuthService userAuthService;
    private final UserRoleService userRoleService;
    private final RoleService roleService;
    private final INdUserInfoService userService;
    private final CompaniesCacheHelper companiesCacheHelper;
    private final IDriverInfoService driverInfoService;
    private final IMetaApplyService iMetaApplyService;
    private final ITrainingRegistrationReviewService iTrainingRegistrationReviewService;
    private final INdUserInfoService ndUserInfoService;

    public PageVo<UserInfoVO> queryUserList(UserPageQuery userPageQuery){
        Page<NdUserInfoJoin> page = userPageQuery.page();
        LambdaQueryWrapper<NdUserInfoJoin> wrapper = Wrappers.lambdaQuery(NdUserInfoJoin.class);
        wrapper.like(StringUtils.isNotBlank(userPageQuery.getUsername()),NdUserInfoJoin::getUsername, userPageQuery.getUsername())
                .like(StringUtils.isNotBlank(userPageQuery.getAccount()),NdUserInfoJoin::getAccount, userPageQuery.getAccount())
                .in(Objects.nonNull(userPageQuery.getRoleId()),NdUserInfoJoin::getRoleId, userPageQuery.getRoleId())
                .eq(Boolean.TRUE,NdUserInfoJoin::getCanLogin,UserCanLoginEnum.CAN_LOGIN.getCode())
                .like(StringUtils.isNotBlank(userPageQuery.getCompanyName()),NdUserInfoJoin::getCompanyName, userPageQuery.getCompanyName())
                .orderBy(Boolean.TRUE,Boolean.FALSE,NdUserInfoJoin::getUpdateOn);
        userInfoJoinService.pageJoin(page, wrapper);
        List<UserInfoVO> data = CollUtils.convert(page.getRecords(), w -> BeanUtil.copyProperties(w, UserInfoVO.class));
        // 查出可登录的帐号
        List<UserInfoVO> resVos = searchAuth(data);
        // 查出角色名
        searchRoleName(resVos);
        return PageVo.of(resVos, page.getTotal());
    }

    public UserInfoVO queryDetails(Long id) {

        LambdaQueryWrapper<NdUserInfo> wrapper = Wrappers.lambdaQuery(NdUserInfo.class);
        UserManage context = (UserManage) AopContext.currentProxy();
        context.buildQuery(wrapper, id);
        NdUserInfo user = userInfoService.getOne(wrapper);
        if (Objects.isNull(user)) {
            return null;
        }

        UserInfoVO query = BeanUtil.toBean(user, UserInfoVO.class);
        //查出帐号
        searchAuth(query);
        //查出角色
        searchRoleName(query);
        return query;
    }

    @LambdaDataScope(type = LambdaDataScopeTypeEnum.ONLY_COMPANY)
    public void buildQuery(LambdaQueryWrapper<NdUserInfo> wrapper, Long id) {
        wrapper.eq(NdUserInfo::getId,id);
    }

    private List<UserInfoVO> searchAuth(List<UserInfoVO> userInfos) {
        List<UserInfoVO> results = null;
        if(CollUtil.isEmpty(userInfos)){
            return Collections.emptyList();
        }
        //查出帐号
        List<Long> userIds = userInfos.stream().map(UserInfoVO::getId).collect(Collectors.toList());
        Map<Long, UserRole> userRoleMap = userRoleService.list(Wrappers.lambdaQuery(UserRole.class).in(UserRole::getUserId, userIds))
                .stream().collect(Collectors.toMap(UserRole::getUserId, r -> r));
        LambdaQueryWrapper<NdUserAuth> wrapper = Wrappers.lambdaQuery(NdUserAuth.class);
        wrapper.in(NdUserAuth::getUserId, userIds);
        List<NdUserAuth> auths = userAuthService.list(wrapper);
        if(CollUtil.isNotEmpty(auths)){
            results = userInfos.stream()
                    .map(user -> {
                        UserInfoVO vo = UserAuthConverter.convert(user, auths);
                        // 如果用户角色不为企业和运营商，需对账号(手机号)进行脱敏
                        Long userId = user.getId();
                        UserRole userRole = userRoleMap.get(userId);
                        if (Objects.nonNull(userRole)) {
                            Long roleId = userRole.getRoleId();
                            if (!UserRoleTypeEnum.COMPANY_INFO_OFFICER_ROLE_ID.getId().equals(roleId) &&
                                    !UserRoleTypeEnum.OPERATOR_ROLE_ID.getId().equals(roleId)) {
                                String account = user.getAccount();
                                String encryptPhone = DesensitizedUtil.mobilePhone(account);
                                vo.setAccount(encryptPhone);
                            }
                        }
                        return vo;
                    })
                    .collect(Collectors.toList());
        }
        return results;
    }

    private void searchRoleName(List<UserInfoVO> userInfos) {
        if(CollUtil.isEmpty(userInfos)){
            return;
        }
        //查出角色名
        List<Long> userIds = userInfos.stream().map(UserInfoVO::getId).collect(Collectors.toList());
        LambdaQueryWrapper<UserRole> wrapper = Wrappers.lambdaQuery(UserRole.class);
        wrapper.in(UserRole::getUserId, userIds);
        List<UserRole> userRoles = userRoleService.list(wrapper);
        if(CollUtil.isEmpty(userRoles)){
            return;
        }
        List<Long> roleIds = userRoles.stream()
                .map(UserRole::getRoleId)
                .distinct()
                .collect(Collectors.toList());
        List<Role> roles = roleService.listByIds(roleIds);
        if(CollUtil.isNotEmpty(roles)){
            userInfos.stream()
                    .map(user -> UserRoleConverter.convert(user,userRoles,roles))
                    .collect(Collectors.toList());
        }
    }

    private void searchAuth(UserInfoVO user) {
        if(Objects.isNull(user)){
            return;
        }
        //查出帐号
        LambdaQueryWrapper<NdUserAuth> wrapper = Wrappers.lambdaQuery(NdUserAuth.class);
        wrapper.in(NdUserAuth::getUserId, user.getId());
        List<NdUserAuth> auths = userAuthService.list(wrapper);
        if(CollUtil.isNotEmpty(auths)){
            UserAuthConverter.convert(user,auths);
        }
    }

    private void searchRoleName(UserInfoVO user) {
        if(Objects.isNull(user)){
            return;
        }
        //查出角色名
        LambdaQueryWrapper<UserRole> wrapper = Wrappers.lambdaQuery(UserRole.class);
        wrapper.in(UserRole::getUserId, user.getId());
        List<UserRole> userRoles = userRoleService.list(wrapper);
        if(CollUtil.isEmpty(userRoles)){
            return;
        }
        List<Long> roleIds = userRoles.stream().map(UserRole::getRoleId).distinct().collect(Collectors.toList());
        List<Role> roles = roleService.listByIds(roleIds);
        if(CollUtil.isNotEmpty(roles)){
            UserRoleConverter.convert(user,userRoles,roles);
        }
    }

    public void save(UserSaveDTO data, Long userId) {
        // 创建系统用户信息
        userService.save(data, LoginUserUtil.getUserId());
        // 当新增用户角色为驾驶员时,新增驾驶员档案信息,并默认驾驶员材料复审通过(该驾驶员可参加培训考试)
        Long roleId = data.getRole();
        if (UserRoleTypeEnum.DRIVER_ROLE_ID.getId().equals(roleId)){
            // 获取对应的驾驶员用户信息
            NdUserInfo ndUserInfo = userInfoService.getOne(Wrappers.lambdaQuery(NdUserInfo.class)
                    .eq(NdUserInfo::getMobile, data.getMobile()));
            // 将该驾驶员用户设置为不可登录状态
            ndUserInfo.setCanLogin(UserCanLoginEnum.CAN_NOT_LOGIN.getCode());
            // 更新信息
            ndUserInfoService.updateById(ndUserInfo);
            DriverInfo driverInfo = new DriverInfo();
            driverInfo.setDriverName(data.getUsername());
            driverInfo.setCompanyId(data.getCompanyId());
            CompanyDTO companyDTO = companiesCacheHelper.getById(data.getCompanyId());
            driverInfo.setCompanyName(companyDTO.getName());
            driverInfo.setPhoneNo(data.getMobile());
            driverInfo.setUserId(ndUserInfo.getId());
            driverInfo.setDriverStatus(DriverStatusEnum.induction.name());
            driverInfo.setDriverRegistrationStatus(DriverRegistrationStatusEnum.exam_training_stage.name());
            driverInfo.setInductionTime(LocalDateTime.now());
            driverInfo.setCreateOn(LocalDateTime.now());
            driverInfo.setUpdateOn(LocalDateTime.now());
            driverInfoService.save(driverInfo);

            // 创建空的取证培训初审、复审审核记录
            Long driverId = driverInfo.getId();
            // 获取录入用户信息
            UserInfoDetails loginUser = LoginUserUtil.loginUserDetail();
            // 补充初审审核信息
            MetaApply metaApply = new MetaApply();
            assemblyMetaApplyInfo(ndUserInfo, driverId, loginUser, metaApply);
            metaApply.setApplyType(MetaApplyTypeEnum.PRELIMINARY_REVIEW.name());
            metaApply.setApplyStatus(MetaApplyStatusEnum.FIRST_TRIAL_APPROVED.name());
            iMetaApplyService.save(metaApply);

            // 补充驾驶员报名初审审核表信息
            TrainingRegistrationReview trainingRegistrationReviewSaveRecord = new TrainingRegistrationReview();
            assemblyTrainingRegistrationReviewInfo(data, ndUserInfo, companyDTO, driverId, loginUser, metaApply, trainingRegistrationReviewSaveRecord);
            trainingRegistrationReviewSaveRecord.setMetaApplyType(MetaApplyTypeEnum.PRELIMINARY_REVIEW.name());
            trainingRegistrationReviewSaveRecord.setRegistrationType(TrainingRegistrationTypeEnum.FORENSIC_REGISTRATION.name());
            trainingRegistrationReviewSaveRecord.setApprovalStatus(MetaApplyStatusEnum.FIRST_TRIAL_APPROVED.name());
            iTrainingRegistrationReviewService.save(trainingRegistrationReviewSaveRecord);

            // 补充复审审核信息
            MetaApply inReviewMetaApply = new MetaApply();
            assemblyMetaApplyInfo(ndUserInfo, driverId, loginUser, inReviewMetaApply);
            inReviewMetaApply.setApplyType(MetaApplyTypeEnum.IN_REVIEW.name());
            inReviewMetaApply.setApplyStatus(MetaApplyStatusEnum.REEXAMINATION_APPROVED.name());
            iMetaApplyService.save(inReviewMetaApply);

            // 补充驾驶员报名复审审核表信息
            TrainingRegistrationReview trainingRegistrationReviewSaveRecord2 = new TrainingRegistrationReview();
            assemblyTrainingRegistrationReviewInfo(data, ndUserInfo, companyDTO, driverId, loginUser, inReviewMetaApply, trainingRegistrationReviewSaveRecord2);
            trainingRegistrationReviewSaveRecord2.setPreliminaryReviewAssociatedId(trainingRegistrationReviewSaveRecord.getId());
            trainingRegistrationReviewSaveRecord2.setMetaApplyType(MetaApplyTypeEnum.IN_REVIEW.name());
            trainingRegistrationReviewSaveRecord2.setRegistrationType(TrainingRegistrationTypeEnum.FORENSIC_REGISTRATION.name());
            trainingRegistrationReviewSaveRecord2.setApprovalStatus(MetaApplyStatusEnum.REEXAMINATION_APPROVED.name());
            iTrainingRegistrationReviewService.save(trainingRegistrationReviewSaveRecord2);

        }
    }

    private void assemblyTrainingRegistrationReviewInfo(UserSaveDTO data, NdUserInfo ndUserInfo, CompanyDTO companyDTO, Long driverId, UserInfoDetails loginUser, MetaApply inReviewMetaApply, TrainingRegistrationReview trainingRegistrationReviewSaveRecord2) {
        trainingRegistrationReviewSaveRecord2.setMetaApplyId(inReviewMetaApply.getId());
        trainingRegistrationReviewSaveRecord2.setCompanyId(data.getCompanyId());
        trainingRegistrationReviewSaveRecord2.setCompanyName(companyDTO.getName());
        trainingRegistrationReviewSaveRecord2.setRegionId(companyDTO.getRegionId());
        trainingRegistrationReviewSaveRecord2.setDriverUserId(ndUserInfo.getId());
        trainingRegistrationReviewSaveRecord2.setDriverId(driverId);
        trainingRegistrationReviewSaveRecord2.setDriverName(data.getUsername());
        trainingRegistrationReviewSaveRecord2.setDriverPhoneNo(data.getMobile());
        trainingRegistrationReviewSaveRecord2.setCreateBy(loginUser.getUserId());
        trainingRegistrationReviewSaveRecord2.setCreateOn(LocalDateTime.now());
        trainingRegistrationReviewSaveRecord2.setUpdateOn(LocalDateTime.now());
    }

    private void assemblyMetaApplyInfo(NdUserInfo ndUserInfo, Long driverId, UserInfoDetails loginUser, MetaApply metaApply) {
        metaApply.setCreateOn(LocalDateTime.now());
        metaApply.setUpdateOn(LocalDateTime.now());
        metaApply.setUserId(ndUserInfo.getId());
        metaApply.setApplyTime(LocalDateTime.now());
        metaApply.setApplicantId(loginUser.getUserId());
        metaApply.setApplicant(loginUser.getNickName());
        metaApply.setRegionId(loginUser.getRegionId());
        metaApply.setCompanyId(loginUser.getCompanyId());
        JSONObject extraMaterial = new JSONObject();
        extraMaterial.put("driverInfoId", driverId);
        metaApply.setExtraMaterial(NdJsonUtil.toJson(extraMaterial));
        metaApply.setDisplayEnable(BooleanDisplayEnum.Y.name());
    }

    public void update(UserUpdateDTO data, Long userId) {
        Long roleId = data.getRole();
        // 当编辑用户角色为驾驶员时,更新驾驶员档案信息
        if (UserRoleTypeEnum.DRIVER_ROLE_ID.getId().equals(roleId)){
            Long userInfoId = data.getId();
            DriverInfo driverInfo = driverInfoService.getOne(Wrappers.lambdaQuery(DriverInfo.class).eq(DriverInfo::getUserId, userInfoId));
            if(Objects.nonNull(driverInfo)){
                driverInfo.setDriverName(data.getUsername());
                CompanyDTO companyDTO = companiesCacheHelper.getById(data.getCompanyId());
                driverInfo.setCompanyName(companyDTO.getName());
                driverInfo.setCompanyId(data.getCompanyId());
                driverInfo.setPhoneNo(data.getMobile());
                driverInfoService.updateById(driverInfo);
            }
        }
        userService.update(data, LoginUserUtil.getUserId());
    }

    public Boolean remove(List<Long> ids) {

        ids.forEach(userId ->{
            UserRole userRole = userRoleService.getOne(Wrappers.lambdaQuery(UserRole.class)
                    .eq(UserRole::getUserId, userId));
            Long roleId = userRole.getRoleId();
            // 当删除用户角色为驾驶员时,删除驾驶员档案信息
            if (UserRoleTypeEnum.DRIVER_ROLE_ID.getId().equals(roleId)){
                driverInfoService.remove(Wrappers.lambdaQuery(DriverInfo.class)
                        .eq(DriverInfo::getUserId,userId));
            }
        });

        UserManage context = (UserManage) AopContext.currentProxy();
        List<Long> list = Lists.newArrayList();
        for (Long id : ids) {
            LambdaQueryWrapper<NdUserInfo> wrapper = Wrappers.lambdaQuery(NdUserInfo.class);
            context.buildQuery(wrapper, id);
            NdUserInfo userInfo = userService.getOne(wrapper);
            if (Objects.nonNull(userInfo)) {
                list.add(userInfo.getId());
            }
        }

        return userService.removeByIdWithCache(list);
    }
}
