package cn.com.ty.lift.system.user.service.impl;

import cn.com.ty.lift.common.constants.ApiConstants;
import cn.com.ty.lift.common.constants.CommonEnum;
import cn.com.ty.lift.common.constants.WebSocketConstants;
import cn.com.ty.lift.common.model.PushMessage;
import cn.com.ty.lift.common.model.PushUserInfo;
import cn.com.ty.lift.common.utils.ProjectUtils;
import cn.com.ty.lift.common.utils.SendMessageUtil;
import cn.com.ty.lift.system.constants.CommonConstants;
import cn.com.ty.lift.system.settings.dao.entity.MaintenanceCompany;
import cn.com.ty.lift.system.settings.service.IMaintenanceCompanyService;
import cn.com.ty.lift.system.user.dao.entity.*;
import cn.com.ty.lift.system.user.dao.entity.model.*;
import cn.com.ty.lift.system.user.dao.mapper.UserApplicationMapper;
import cn.com.ty.lift.system.user.service.*;
import cn.com.ty.lift.system.utils.CommonUtil;
import cn.com.xwy.boot.web.dto.RestResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户申请表 服务实现类
 * </p>
 *
 * @author huangyuan
 * @since 2019-12-13
 */
@Service
public class UserApplicationService extends ServiceImpl<UserApplicationMapper, UserApplication> implements IUserApplicationService {

    @Resource
    private IMtCompanyUserService mtCompanyUserService;

    @Resource
    private IMaintenanceCompanyService maintenanceCompanyService;

    @Resource
    private IUserRoleService userRoleService;

    @Resource
    private IRoleService roleService;

    @Resource
    private IUserService userService;

    @Resource
    private IUserInfoService userInfoService;

    @Resource
    private IProjectService projectService;

    @Resource
    private PushUserService pushUserService;

    @Resource
    private JmsMessagingTemplate jmsMessagingTemplate;

    private static final Map<Integer, String> permission = new HashMap<>();

    static {
        permission.put(21, "查看权限");
        permission.put(22, "评价权限");
    }

    @Override
    public RestResponse apply(UserApplyRequest userApplyRequest, int applyTypeTeam) {
        //申请公司id
        long companyId = userApplyRequest.getCompanyId();
        //申请人id
        long applyUserId = userApplyRequest.getUserId();
        //获取用户原有的申请信息
        UserApplication userApplication = this.getOne(new QueryWrapper<UserApplication>()
                .eq("mt_company_id", companyId)
                .eq("user_id", applyUserId)
                //去掉申请未通过的判断
                .ne("status", ApiConstants.ApplicationConstants.APPLY_FAIL)
        );
        //设置前校验
        RestResponse restResponse = applyCheck(userApplyRequest, userApplication, applyTypeTeam);
        if (restResponse != null) {
            //校验不通过返回校验信息
            return restResponse;
        }
        //校验通过设置审核信息
        if (userApplication == null) {
            userApplication = new UserApplication();
            userApplication.setUserId(applyUserId);
            userApplication.setMtCompanyId(companyId);
            userApplication.setType(applyTypeTeam);
            //设置审核描述信息
            userApplication.setDescription(userApplyRequest.getDescription());
            //申请加入项目时需要设置的信息
            userApplication.setProjectId(userApplyRequest.getProjectId());
        }
        //审核状态变为待审核
        userApplication.setStatus(ApiConstants.ApplicationConstants.APPLY_WAIT);
        //申请加入项目时需要设置的信息
        userApplication.setPowerType(userApplyRequest.getPowerType());
        boolean result = this.saveOrUpdate(userApplication);
        //组合消息内容
        UserInfo userInfo = userInfoService.getByUserId(applyUserId);
        String applyName = userInfo.getName();
        if (result) {
            //申请操作成功，推送消息
            if (ApiConstants.ApplicationConstants.APPLY_TYPE_TEAM == applyTypeTeam) {
                applyTeamPushMessage(companyId, applyName);
            } else {
                applyProjectPushMessage(userApplyRequest, companyId, applyName);
            }
        } else {
            return RestResponse.fail(ApiConstants.RESULT_ERROR, "申请失败");
        }
        return RestResponse.success(null, ApiConstants.RESULT_SUCCESS, "申请成功");
    }

    @Override
    public RestResponse applyFail(UserApplyRequest userApplyRequest) {
        UserApplication userApplication = this.getById(userApplyRequest.getId());
        //设置申请状态为审核不通过
        userApplication.setStatus(ApiConstants.ApplicationConstants.APPLY_FAIL);
        //设置处理时间
        userApplication.setDealDate(LocalDateTime.now());
        //处理人id
        userApplication.setDealUserId(userApplication.getUserId());
        this.updateById(userApplication);
        return RestResponse.success(null, ApiConstants.RESULT_SUCCESS, "操作成功");
    }

    @Override
    public RestResponse applyList(UserApplyRequest userApplyRequest) {
        Long companyId = userApplyRequest.getCompanyId();
        List<Long> userQueryIdList = null;
        //通过用户名或手机号查找用户id
        if (StringUtils.isNotBlank(userApplyRequest.getQueryCondition())) {
            userQueryIdList = userService.getIdListByQueryCondition(userApplyRequest.getQueryCondition());
        }
        //获取所有状态的申请信息集合
        List<UserApplication> userApplicationListResult = this.list(new QueryWrapper<UserApplication>()
                .select("status")
                .eq("mt_company_id", companyId)
        );
        //封装不同状态的条数信息
        ApplyPageResponse applyPageResponse = new ApplyPageResponse();
        packUserApplicationStatusCount(userApplicationListResult, applyPageResponse, userApplyRequest.getStatus());

        //封装具体信息
        List<UserApplyResponse> userApplyResponseList = new ArrayList<>();
        IPage userApplicationPage = new Page(userApplyRequest.getPageNum(), userApplyRequest.getPageSize());
        userApplicationPage = this.page(userApplicationPage, new QueryWrapper<UserApplication>()
                .in(userQueryIdList != null && userQueryIdList.size() > 0, "user_id", userQueryIdList)
                .eq("mt_company_id", companyId)
                .eq("status", userApplyRequest.getStatus())
        );
        List<UserApplication> userApplicationList = userApplicationPage.getRecords();
        if (userApplicationList != null && userApplicationList.size() > 0) {
            //获取用id集合
            List<Long> userIdList = ProjectUtils.getAttrList(userApplicationList, "userId", null);
            //获取用户id -> 角色关系
            Map<Long, Role> userIdToRole = roleService.getUserIdToRoleByUserIdsAndCompanyId(userIdList, companyId);
            //用户id对应的用户基本信息
            Map<Long, UserResponse> userIdToUserResponse = userService.getUserResponseByUserIdList(userIdList);
            for (UserApplication userApplication : userApplicationList) {
                UserApplyResponse userApplyResponse = new UserApplyResponse();
                UserResponse userResponse = userIdToUserResponse.get(userApplication.getUserId());
                //设置申请人用户信息
                if (userResponse != null) {
                    userApplyResponse.setUserAvatarUrl(userResponse.getAvatarUrl());
                    userApplyResponse.setUserName(userResponse.getName());
                    userApplyResponse.setUserMobile(userResponse.getMobile());
                }
                //设置申请人角色信息
                if (userIdToRole != null) {
                    Role role = userIdToRole.get(userApplication.getUserId());
                    if (role != null) {
                        userApplyResponse.setRoleName(role.getName());
                    }
                }
                //设置申请基础信息
                userApplyResponse.setApplyDate(userApplication.getApplyDate());
                userApplyResponse.setApplyType(userApplication.getType());
                userApplyResponse.setPowerType(userApplication.getPowerType());
                userApplyResponse.setDealDate(userApplication.getDealDate());
                userApplyResponse.setId(userApplication.getId());
                userApplyResponse.setUserId(userApplication.getUserId());

                userApplyResponseList.add(userApplyResponse);
            }
        }
        userApplicationPage.setRecords(userApplyResponseList);
        //设置分页数据
        applyPageResponse.setPage(userApplicationPage);
        return RestResponse.success(applyPageResponse, ApiConstants.RESULT_SUCCESS, "获取申请信息成功");
    }

    @Override
    public Map<Integer, Long> getApplyStatusToCountMap(List userApplicationResult, int[] applyStatusArray, String statusField) {
        Map<Integer, Long> statusToCount = new HashMap<>();
        Map<Integer, List<UserApplication>> statusToUserApplication = ProjectUtils.attrToListMap(userApplicationResult,
                statusField, null);
        //获取不同状态对应数量
        for (int status : applyStatusArray) {
            List<UserApplication> userApplicationList = statusToUserApplication.get(status);
            Long count = 0L;
            if (userApplicationList != null) {
                count = Long.valueOf(userApplicationList.size());
            }
            statusToCount.put(status, count);
        }
        return statusToCount;
    }

    /**
     * @param
     * @return
     * @description 封装用户申请信息状态条数
     * @date 2020-01-06 23:12
     */
    private void packUserApplicationStatusCount(List<UserApplication> userApplicationListResult, ApplyPageResponse applyPageResponse, int currentStatus) {
        //获取状态对应的数量
        Map<Integer, Long> statusToApplyCount = this.getApplyStatusToCountMap(userApplicationListResult,
                CommonConstants.USER_APPLICATION_STATUS, "status");
        //待审核
        applyPageResponse.setApplyWaitCount(statusToApplyCount.get(ApiConstants.ApplicationConstants.APPLY_WAIT));
        //审核通过
        applyPageResponse.setApplyPassCount(statusToApplyCount.get(ApiConstants.ApplicationConstants.APPLY_PASS));
        //审核未通过
        applyPageResponse.setApplyFailCount(statusToApplyCount.get(ApiConstants.ApplicationConstants.APPLY_FAIL));
        //设置未查询的总记录条数
        Long count = statusToApplyCount.get(currentStatus) == null ? 0L : statusToApplyCount.get(currentStatus);
        applyPageResponse.setCount(count);
    }

    /**
     * @param userApplyRequest 申请参数
     * @param applyTypeTeam    申请类型
     * @return
     * @description 校验项目
     * @date 2020-01-05 14:14
     */
    private RestResponse applyCheck(UserApplyRequest userApplyRequest, UserApplication userApplication, int applyTypeTeam) {
        //校验用户是否已在团队或者项目中
        if (ApiConstants.ApplicationConstants.APPLY_TYPE_TEAM == applyTypeTeam) {
            //获取用户团队信息
            MtCompanyUser mtCompanyUser = mtCompanyUserService.getOne(new QueryWrapper<MtCompanyUser>()
                    .eq("mt_company_id", userApplyRequest.getCompanyId())
                    .eq("user_id", userApplyRequest.getUserId())
                    .ne("status", ApiConstants.ApplicationConstants.APPLY_FAIL)
            );
            if (mtCompanyUser != null) {
                return RestResponse.fail(ApiConstants.RESULT_ERROR, "用户已经在团队中了");
            }
        } else {
            //获取项目用户信息
            ProjectUser projectUser = projectService.getProjectUserByUserIdAndProjectId(new ProjectUser(
                    userApplyRequest.getUserId(), userApplyRequest.getCompanyId(), userApplyRequest.getProjectId()));
            if (projectUser != null) {
                return RestResponse.fail(ApiConstants.RESULT_ERROR, "用户已经在项目中了");
            }
        }
        //校验两次申请的时间
        if (userApplication != null) {
            LocalDateTime oldApplyTime = userApplication.getApplyDate();
            //当前申请时间
            LocalDateTime nowApplyTime = LocalDateTime.now();
            //差值判断
            if (CommonUtil.durationJudge(oldApplyTime, nowApplyTime, 1L)) {
                return RestResponse.success(null, ApiConstants.RESULT_ERROR, "今天已经申请过了");
            }
        }
        return null;
    }

    /**
     * @param
     * @return
     * @description 团队审核通过
     * @date 2020-01-05 15:00
     */
    private RestResponse teamPass(UserApplyRequest userApplyRequest, UserApplication userApplication) {
        //更新公司用户信息
        Long companyId = userApplication.getMtCompanyId();
        Long userId = userApplication.getUserId();
        //给用户分配角色
        UserRole userRole = new UserRole();
        userRole.setCompanyId(companyId);
        userRole.setUserId(userId);
        userRole.setRoleId(userApplyRequest.getRoleId());
        if (!userRoleService.save(userRole)) {
            return RestResponse.fail(ApiConstants.RESULT_ERROR, "给用户分配角色失败");
        }
        //获取公司用户信息
        MtCompanyUser mtCompanyUser = mtCompanyUserService.getOne(new QueryWrapper<MtCompanyUser>()
                .eq("mt_company_id", companyId)
                .eq("user_id", userId)
        );
        //如果公司用户信息不存在，新建信息
        if (mtCompanyUser == null) {
            mtCompanyUser = new MtCompanyUser();
            mtCompanyUser.setMtCompanyId(companyId);
            mtCompanyUser.setUserId(userId);
            mtCompanyUser.setCreateUserId(userId);
            mtCompanyUser.setCreateTime(new Date());
        }
        mtCompanyUser.setUpdateTime(new Date());
        mtCompanyUser.setUpdateUserId(userId);
        //设置用户状态在团队中
        mtCompanyUser.setStatus(ApiConstants.ApplicationConstants.APPLY_PASS);
        if (!mtCompanyUserService.saveOrUpdate(mtCompanyUser)) {
            return RestResponse.fail(ApiConstants.RESULT_ERROR, "关联团队失败");
        }
        //加入团队审核通过后进行消息推送
        teamPassPushMessage(companyId, userId);
        return null;
    }

    /**
     * @param
     * @return
     * @description 团队审核通过
     * @date 2020-01-05 15:17
     */
    private void projectPass(UserApplication userApplication) {
        ProjectUser projectUser = new ProjectUser();
        projectUser.setUserId(userApplication.getUserId());
        projectUser.setCompanyId(userApplication.getMtCompanyId());
        projectUser.setProjectId(userApplication.getProjectId());
        projectUser.setUserRole(userApplication.getPowerType() + "");
        projectUser.setIsMonitor("0");
        //保存项目信息
        projectService.saveProjectUser(projectUser);
        //加入项目审核通过后消息推送
        projectPassPushMessage(userApplication, projectUser);
    }

    /**
     * @param companyId 公司id
     * @param applyName 申请人名称
     * @return 推送信息
     * @description 申请加入团队将消息推送给pc端文员
     * @date 2020/5/2 4:18 下午
     */
    private boolean applyTeamPushMessage(long companyId, String applyName) {
        MaintenanceCompany maintenanceCompany = maintenanceCompanyService.getById(companyId);
        String teamName = maintenanceCompany.getName();
        String content = applyName + "申请加入" + teamName;
        //申请加入团队成功，给公司所有文员推送信息
        List<Long> clerkIds = userService.getUserIdByCompanyIdAndRoleCode(companyId,
                CommonEnum.DefaultRole.CLERK.getCode());
        return SendMessageUtil.sendMessageToPC(jmsMessagingTemplate, clerkIds, content,
                WebSocketConstants.MessageType.TEAM_MSG);
    }

    /**
     * @param userApplyRequest 申请信息
     * @param companyId        申请的项目所在的公司
     * @param applyName        申请名称
     * @return false 失败 true 成功
     * @description 申请加入项目成功后推送消息
     * @date 2020/5/2 11:50 下午
     */
    private boolean applyProjectPushMessage(UserApplyRequest userApplyRequest, long companyId, String applyName) {
        //申请加入项目，推送消息
        //项目所在区域的区域主管，以及所有文员
        List<PushUserInfo> pushUserInfoList = pushUserService.getCompanyUserInfoByRoleCode(companyId,
                CommonEnum.DefaultRole.CLERK.getCode());
        //获取项目所在的区域主管的信息
        ProjectInfo projectInfo = projectService.getProjectById(userApplyRequest.getProjectId());
        if (projectInfo != null) {
            //将消息推送到app端
            PushMessage pushMessage = PushMessage.workApplyPermission(applyName, projectInfo.getProjectName(),
                    permission.get(userApplyRequest.getPowerType()));
            if (projectInfo.getRegionDirectorId() != null) {
                PushUserInfo regionDirector = pushUserService.getCompanyUserInfoByUserId(companyId,
                        projectInfo.getRegionDirectorId());
                if (regionDirector != null) {
                    pushUserInfoList.add(regionDirector);
                }
            }
            if (pushUserInfoList != null && pushUserInfoList.size() > 0) {
                //消息内容
                String content = pushMessage.getContent();
                pushMessage.sendTokenOnPlatform(jmsMessagingTemplate, pushUserInfoList);
                //将消息推送到pc端
                List<Long> userIdList = pushUserInfoList.stream().map(PushUserInfo::getUserId)
                        .collect(Collectors.toList());
                SendMessageUtil.sendMessageToPC(jmsMessagingTemplate, userIdList, content,
                        WebSocketConstants.MessageType.TEAM_MSG);
                return true;
            }
        }
        return false;
    }

    @Override
    @Transactional
    public RestResponse applyPass(UserApplyRequest userApplyRequest) {
        //加入团队审核通过
        UserApplication userApplication = this.getById(userApplyRequest.getId());
        //设置申请信息
        userApplication.setStatus(ApiConstants.ApplicationConstants.APPLY_PASS);
        userApplication.setDealDate(LocalDateTime.now());
        userApplication.setDealUserId(userApplyRequest.getUserId());
        if (ApiConstants.ApplicationConstants.APPLY_TYPE_TEAM == userApplication.getType()) {
            //团队审核通过
            RestResponse restResponse = teamPass(userApplyRequest, userApplication);
            if (restResponse != null) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return restResponse;
            }
        } else {
            //项目审核通过
            projectPass(userApplication);
        }
        if (!this.updateById(userApplication)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return RestResponse.fail(ApiConstants.RESULT_ERROR, "更新用户申请信息失败");
        }
        return RestResponse.success(null, ApiConstants.RESULT_SUCCESS, "操作成功");
    }

    /**
     * @param
     * @return
     * @description 加入团队审核通过后进行消息推送
     * @date 2020/5/3 11:05 上午
     */
    private void teamPassPushMessage(Long companyId, Long userId) {
        //获取区域主管信息
        List<PushUserInfo> pushUserInfoList = pushUserService.getCompanyUserInfoByRoleCode(companyId,
                CommonEnum.DefaultRole.REGION_DIRECTOR.getCode());
        if (pushUserInfoList != null && pushUserInfoList.size() > 0) {
            //申请人
            PushUserInfo applyUserInfo = pushUserService.getUserInfoByUserId(userId);
            if (applyUserInfo != null) {
                MaintenanceCompany maintenanceCompany = maintenanceCompanyService.getById(companyId);
                pushUserInfoList.add(applyUserInfo);
                if (maintenanceCompany != null) {
                    PushMessage.teamJoin(applyUserInfo.getUserName(), maintenanceCompany.getName())
                            .sendTokenOnPlatform(jmsMessagingTemplate, pushUserInfoList);
                }
            }
        }
    }

    /**
     * @param
     * @return
     * @description 加入项目审核通过后消息推送
     * @date 2020/5/3 11:44 上午
     */
    private void projectPassPushMessage(UserApplication userApplication, ProjectUser projectUser) {
        //加入项目审核通过，消息推送
        ProjectInfo projectInfo = projectService.getProjectById(userApplication.getProjectId());
        if (projectInfo != null) {
            UserInfo applyUserInfo = userInfoService.getByUserId(userApplication.getUserId());
            if (applyUserInfo != null) {
                PushUserInfo regionDirector = pushUserService.getCompanyUserInfoByUserId(userApplication.getMtCompanyId(),
                        projectUser.getUserId());
                PushMessage.workObtainPermission(applyUserInfo.getName(), projectInfo.getProjectName(),
                        permission.get(userApplication.getPowerType())).sendTokenOnPlatform(jmsMessagingTemplate, regionDirector);
            }
        }
    }

}
