package com.crunii.micro.service.sysmgr.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.crunii.micro.common.constants.CommonConstants;
import com.crunii.micro.common.dto.PageReq;
import com.crunii.micro.common.dto.PageRsp;
import com.crunii.micro.common.dto.Result;
import com.crunii.micro.common.exception.BusinessException;
import com.crunii.micro.domain.dto.Worker;
import com.crunii.micro.domain.entity.main.TsmPost;
import com.crunii.micro.domain.entity.main.TsmPostRole;
import com.crunii.micro.domain.entity.main.TsmPostWorker;
import com.crunii.micro.domain.entity.main.TsmWorkerRole;
import com.crunii.micro.domain.repo.main.TsmPostRepo;
import com.crunii.micro.domain.repo.main.TsmPostRoleRepo;
import com.crunii.micro.domain.repo.main.TsmPostWorkerRepo;
import com.crunii.micro.domain.repo.main.TsmWorkerRoleRepo;
import com.crunii.micro.domain.util.CurrWorkerUtil;
import com.crunii.micro.service.sysmgr.constants.SysmgrConstants;
import com.crunii.micro.service.sysmgr.dto.post.*;
import com.crunii.micro.service.sysmgr.jdbc.PostJdbcDao;
import com.crunii.micro.service.sysmgr.service.PostService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

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

import static com.crunii.micro.service.sysmgr.constants.ErrorMsgConstants.*;

/**
 * 职务 Service 实现类
 */
@Service
@Validated
@Slf4j
public class PostServiceImpl implements PostService {

    @Resource
    private TsmPostRepo tsmPostRepo;
    @Resource
    private TsmPostRoleRepo tsmPostRoleRepo;
    @Resource
    private TsmPostWorkerRepo tsmPostWorkerRepo;
    @Resource
    private PostJdbcDao postJdbcDao;
    @Resource
    private TsmWorkerRoleRepo tsmWorkerRoleRepo;

    /**
     * 创建职务
     *
     * @param reqVO 职务信息
     * @return 职务编号
     */
    @Override
    public Long createPost(PostCreateReqVO reqVO) {
        // 校验正确性
        validatePostForCreateOrUpdate(null, reqVO.getName(), null);
        //校验请求参数
        validatePostParameter(reqVO.getSort());
        // 插入职务
        TsmPost post=new TsmPost();
        BeanUtils.copyProperties(reqVO,post);
        post.setState(CommonConstants.STATE_VALID);
        post.setCode("zw" + System.currentTimeMillis());
        saveCreate(post);
        tsmPostRepo.save(post);
        return post.getId();
    }

    /**
     * 更新职务
     *
     * @param reqVO 职务信息
     */
    @Override
    public void updatePost(PostUpdateReqVO reqVO) {
        // 校验正确性
        validatePostForCreateOrUpdate(reqVO.getId(), reqVO.getName(), null);
        //校验请求参数
        validatePostParameter(reqVO.getSort());
        //校验当前职务下是否有用户,已关联用户的职务不可置无效
        List<TsmPostWorker> postWorkers = tsmPostWorkerRepo.findByPostId(reqVO.getId());
        if (postWorkers.size()>0 && reqVO.getState().equals(0)){
            throw new BusinessException(POST_WORKER_EXIST_TOO);
        }
        // 更新职务
        TsmPost updateObj = tsmPostRepo.getOnePost(reqVO.getId());
        //职务编码不可更新
        BeanUtils.copyProperties(reqVO,updateObj,"code");
        if (StrUtil.isEmpty(updateObj.getCode())) {
            updateObj.setCode("zw" + System.currentTimeMillis());
        }
        saveUpdate(updateObj);
        tsmPostRepo.save(updateObj);
    }

    /**
     * 删除职务信息
     *
     * @param id 职务编号
     */
    @Override
    public void deletePost(Long id) {
        // 校验是否存在
        validatePostExists(id);
        //校验当前职务下是否有用户
        List<TsmPostWorker> postWorkers = tsmPostWorkerRepo.findByPostId(id);
        if (postWorkers.size()>0){
            throw new BusinessException(POST_WORKER_EXIST);
        }
        // 删除职务
        tsmPostRepo.deletePost(id);
    }

    /**
     * 获得职务分页列表
     *
     * @param reqVO 分页条件
     * @return 部门分页列表
     */
    @Override
    public PageRsp<PostRespVO> getPostPage(PageReq<PostPageReqVO> reqVO) {
        PageRsp<PostRespVO> postRespVOPageRsp = postJdbcDao.pagePost(reqVO);
        for (PostRespVO postRespVO : postRespVOPageRsp.getResult()) {
            List<TsmPostWorker> workers = tsmPostWorkerRepo.findByPostId(postRespVO.getId());
            postRespVO.setPeopleNum(workers.size());
            List<Long> roles = tsmPostRoleRepo.findByPostId(postRespVO.getId()).stream().map(s->(long)s.getRoleId()).collect(Collectors.toList());
            postRespVO.setRoleList(roles);
        }
        return postRespVOPageRsp;
    }

    /**
     * 获得职务列表
     *
     */
    @Override
    public List<PostListRspVo> getPostList() {
        List<PostListRspVo> posts=new ArrayList<>();
        for (TsmPost tsmPost : tsmPostRepo.findAllPost()) {
            PostListRspVo vo=new PostListRspVo();
            vo.setId(tsmPost.getId());
            vo.setName(tsmPost.getName());
            //查询职务关联的角色
            List<Integer> roles = tsmPostRoleRepo.findByPostId(tsmPost.getId()).stream().map(TsmPostRole::getRoleId).collect(Collectors.toList());
            vo.setRoleList(roles);
            posts.add(vo);
        }
        return posts;
    }

    /**
     * 获得职务信息
     *
     * @param id 岗位编号
     * @return 岗位信息
     */
    @Override
    public PostRespVO getPost(Long id) {
        PostRespVO postRespVO=new PostRespVO();
        TsmPost tsmPost = tsmPostRepo.getOnePost(id);
        BeanUtils.copyProperties(tsmPost,postRespVO);
        return postRespVO;
    }


    /**
     * 判断职务名称是否已存在
     *
     * @param reqVO
     * @return
     */
    @Override
    public Result<Boolean> getByName(PostReqVO reqVO) {
        return new Result<>(tsmPostRepo.findByName(reqVO.getName()) == null);
    }

    /**
     * 职务关联角色
     * @param reqVO
     * @return
     */
    @Override
    public Result<Boolean> doCorrelateRole(CorrelatePostReq reqVO) {
        if (ObjectUtil.isEmpty(reqVO) || reqVO.getPostId()==null){
            throw new BusinessException(REQUEST_ERROR);
        }
        if (reqVO.getRoleList().size()==0){
            throw  new BusinessException(POST_CREATE_ROLE_NOT_NULL);
        }
        //当前选中的角色
        List<Integer> roleList = reqVO.getRoleList();
        if (roleList.contains(SysmgrConstants.DEPARTMENT_AUDIT_PERSON) && roleList.contains(SysmgrConstants.SYS_AUDIT_PERSON)) {
            throw new BusinessException(WORKER_TWO_ROLE_EXIST);
        }
        tsmPostRoleRepo.deletePostId(reqVO.getPostId());
        roleList.forEach(s->{
            TsmPostRole tsmPostRole=new TsmPostRole();
            tsmPostRole.setPostId(reqVO.getPostId());
            tsmPostRole.setRoleId(s);
            tsmPostRoleRepo.save(tsmPostRole);
        });
        //处理已关联当前职务的用户的关联角色
        List<TsmPostWorker> workers = tsmPostWorkerRepo.findByPostId(reqVO.getPostId());
        for (TsmPostWorker worker : workers) {
            //查询用户本该拥有的所有角色
            List<Integer> roleIds= tsmPostRoleRepo.findPostAndRoleByWorker(worker.getWorkerId(), reqVO.getPostId()).stream().map(TsmPostRole::getRoleId).collect(Collectors.toList());
            List<TsmWorkerRole> allRoles = tsmWorkerRoleRepo.findByLoginId(worker.getWorkerId());
            List<Integer> allRoleIds = allRoles.stream().map(TsmWorkerRole::getRoleId).collect(Collectors.toList());
            //删除角色与用户的关联关系
            for (TsmWorkerRole role : allRoles) {
                if (role.getSource()==2 && !roleList.contains(role.getRoleId()) && !roleIds.contains(role.getRoleId())){
                    tsmWorkerRoleRepo.delete(role);
                    tsmWorkerRoleRepo.flush();
                }
            }
            //新增角色与用户的关联关系
            for (Integer roleId : reqVO.getRoleList()) {
                if (roleList.contains(roleId) && !allRoleIds.contains(roleId)){
                    TsmWorkerRole tsmWorkerRole=new TsmWorkerRole();
                    tsmWorkerRole.setRoleId(roleId);
                    tsmWorkerRole.setLoginId(Math.toIntExact(worker.getWorkerId()));
                    tsmWorkerRole.setSource(2);
                    tsmWorkerRoleRepo.saveAndFlush(tsmWorkerRole);
                }
            }
        }
        return Result.ofSuccessMsg(OPERATION_SUCCESS);
    }

    /**
     * 校验职务请求参数
     */
    private void validatePostParameter(Integer sort) {
        if (sort == null) {
            throw new BusinessException(POST_CREATE_SORT_NOT_NULL);
        }
    }

    /**
     * 数据校验
     */
    private void validatePostForCreateOrUpdate(Long id, String name, String code) {
        // 校验自己存在
        validatePostExists(id);
        // 校验岗位名的唯一性
        validatePostNameUnique(id, name);
        // 校验岗位编码的唯一性
        validatePostCodeUnique(id, code);
    }

    /**
     * 校验职务名的唯一性
     */
    private void validatePostNameUnique(Long id, String name) {
        List<Long> ids = tsmPostRepo.findByName(name).stream().map(TsmPost::getId).filter(s -> !s.equals(id)).collect(Collectors.toList());
        if (ids.size()==0) {
            return;
        }
        // 如果 id 为空，说明是新增
        if (id == null) {
            throw new BusinessException(POST_NAME_DUPLICATE);
        }
        if (ids.size()>0) {
            throw new BusinessException(POST_NAME_DUPLICATE);
        }
    }

    /**
     * 校验职务编码的唯一性
     */
    private void validatePostCodeUnique(Long id, String code) {
        List<TsmPost> post = tsmPostRepo.findByCode(code);
        List<Long> codsList = post.stream().map(TsmPost::getId).collect(Collectors.toList());
        if (post.size()==0) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的职务
        if (id == null) {
            throw new BusinessException(POST_CODE_DUPLICATE);
        }
        if (codsList.contains(id)) {
            throw new BusinessException(POST_CODE_DUPLICATE);
        }
    }

    /**
     * 校验自己存在
     */
    private void validatePostExists(Long id) {
        if (id == null) {
            return;
        }
        if (tsmPostRepo.getOnePost(id) == null) {
            throw new BusinessException(POST_NOT_FOUND);
        }
    }

    /**
     * 保存新建信息
     *
     * @param tsmPost
     */
    private void saveCreate(TsmPost tsmPost) {
        Worker worker = getWorker();
        if (ObjectUtil.isNotEmpty(worker)) {
            tsmPost.setCreateId((long) worker.getLoginId());
            tsmPost.setCreateBy(worker.getWorkerName());
            tsmPost.setCreateTime(new Date());
        }
    }

    /**
     * 保存修改信息
     *
     * @param tsmPost
     */
    private void saveUpdate(TsmPost tsmPost) {
        Worker worker = getWorker();
        if (ObjectUtil.isNotEmpty(worker)) {
            tsmPost.setUpdateId((long) worker.getLoginId());
            tsmPost.setUpdateBy(worker.getWorkerName());
            tsmPost.setUpdateTime(new Date());
        }
    }

    /**
     * 获取登录用户
     *
     * @return
     */
    private Worker getWorker() {
        Worker worker = CurrWorkerUtil.getCurrWorker();
        if (ObjectUtil.isEmpty(worker)) {
            throw new BusinessException("获取登录用户失败");
        }
        return worker;
    }

}
