package com.xunmei.core.edu.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xunmei.common.core.constant.ErrorMsgConstants;
import com.xunmei.common.core.constant.SecurityConstants;
import com.xunmei.common.core.domain.edu.domain.CoreEduTrainingPlan;
import com.xunmei.common.core.domain.edu.domain.CoreEduTrainingPlanToExecOrg;
import com.xunmei.common.core.domain.edu.domain.CoreEduTrainingPlanToRole;
import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingPlanEditDto;
import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingPlanInsertDto;
import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingPlanPageDto;
import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingPlanDataVo;
import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingPlanDetailVo;
import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingPlanPageVo;
import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingPlanRoleVo;
import com.xunmei.common.core.exception.SystemException;
import com.xunmei.common.core.utils.DateUtils;
import com.xunmei.common.core.web.page.TableDataInfo;
import com.xunmei.common.security.utils.SecurityUtils;
import com.xunmei.core.edu.mapper.CoreEduTrainingPlanMapper;
import com.xunmei.core.edu.mapper.CoreEduTrainingPlanToExecOrgMapper;
import com.xunmei.core.edu.mapper.CoreEduTrainingPlanToRoleMapper;
import com.xunmei.core.edu.mapper.CoreEduTrainingTaskMapper;
import com.xunmei.core.edu.service.ICoreEduTrainingPlanService;
import com.xunmei.core.edu.service.ICoreEduTrainingPlanToExecOrgService;
import com.xunmei.core.edu.service.ICoreEduTrainingPlanToRoleService;
import com.xunmei.core.edu.service.ICoreEduTrainingTaskService;
import com.xunmei.system.api.RemoteOrgService;
import com.xunmei.system.api.domain.SysOrg;
import com.xunmei.system.api.function.RemoteCallHandlerExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 教育培训计划Service业务层处理
 *
 * @author xunmei
 * @date 2023-08-24
 */
@Slf4j
@Service
public class CoreEduTrainingPlanServiceImpl extends ServiceImpl<CoreEduTrainingPlanMapper, CoreEduTrainingPlan> implements ICoreEduTrainingPlanService {
    @Autowired
    private CoreEduTrainingPlanMapper coreEduTrainingPlanMapper;
    @Autowired
    private ICoreEduTrainingPlanToRoleService coreEduTrainingPlanToRoleService;
    @Autowired
    private CoreEduTrainingPlanToRoleMapper coreEduTrainingPlanToRoleMapper;
    @Autowired
    private ICoreEduTrainingPlanToExecOrgService coreEduTrainingPlanToExecOrgService;
    @Autowired
    private CoreEduTrainingPlanToExecOrgMapper coreEduTrainingPlanToExecOrgMapper;
    @Autowired
    private ICoreEduTrainingTaskService coreEduTrainingTaskService;
    @Autowired
    private CoreEduTrainingTaskMapper coreEduTrainingTaskMapper;
    @Autowired
    private RemoteOrgService orgService;

    @Override
    public TableDataInfo selectPage(CoreEduTrainingPlanPageDto request) {

        //下穿
        if (request.getCheckSub()) {
            SysOrg r = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgById(request.getBelongOrgId(), SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
            request.setBelongOrgPath(r.getPath());
        }
        //获取数据
        Page<CoreEduTrainingPlanPageVo> page = coreEduTrainingPlanMapper.selectPageData(request.getPage(), request);
        SysOrg sysOrg = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectTopOrg(SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
        for (CoreEduTrainingPlanPageVo record : page.getRecords()) {
            record.setNo(page.getRecords().indexOf(record) + 1);
            if (ObjectUtil.equal(record.getCreateOrgId(), sysOrg.getId())) {
                record.setCreateByTopOrg(1);
            }
            String roleNameList = coreEduTrainingPlanToRoleMapper.selectRoleNameByPlanId(record.getId()).stream().map(CoreEduTrainingPlanRoleVo::getRoleName).collect(Collectors.joining(","));
            record.setPlanRoleNameList(roleNameList);

        }
        //抓换为TableDataInfo适配前端
        TableDataInfo tableDataInfo = new TableDataInfo();
        tableDataInfo.setMsg("操作成功");
        tableDataInfo.setCode(200);
        tableDataInfo.setTotal(page.getTotal());
        tableDataInfo.setRows(page.getRecords());
        return tableDataInfo;


    }


    /**
     * 查询教育培训计划
     *
     * @param id 教育培训计划主键
     * @return 教育培训计划
     */
    @Override
    public CoreEduTrainingPlanDetailVo selectCoreEduTrainingPlanById(Long id) {
        final CoreEduTrainingPlan plan = coreEduTrainingPlanMapper.selectById(id);
        CoreEduTrainingPlanDetailVo vo = new CoreEduTrainingPlanDetailVo();
        BeanUtils.copyProperties(plan, vo);
        final List<CoreEduTrainingPlanToExecOrg> execOrgList = coreEduTrainingPlanToExecOrgMapper.selectByMap(MapUtil.of("plan_id", id));
        final List<Long> execOrgIdList = execOrgList.stream().map(CoreEduTrainingPlanToExecOrg::getOrgId).collect(Collectors.toList());
        vo.setPlanExecOrgIdList(ObjectUtil.isEmpty(execOrgIdList) ? null : execOrgIdList);
        final List<CoreEduTrainingPlanToRole> planToRoles = coreEduTrainingPlanToRoleMapper.selectByMap(MapUtil.of("plan_id", id));
        final List<Long> execRoleIdList = planToRoles.stream().map(CoreEduTrainingPlanToRole::getRoleId).collect(Collectors.toList());
        vo.setPlanRoleId(ObjectUtil.isEmpty(execRoleIdList) ? null : execRoleIdList);
        return vo;
    }

    /**
     * 查询教育培训计划列表
     *
     * @param coreEduTrainingPlan 教育培训计划
     * @return 教育培训计划
     */
    @Override
    public List<CoreEduTrainingPlan> selectCoreEduTrainingPlanList(CoreEduTrainingPlan coreEduTrainingPlan) {
        return coreEduTrainingPlanMapper.selectList(new QueryWrapper<>(coreEduTrainingPlan));
    }

    /**
     * 新增教育培训计划
     *
     * @param request 教育培训计划
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertCoreEduTrainingPlan(CoreEduTrainingPlanInsertDto request) {
        if (ObjectUtil.isAllEmpty(request.getExecOrgType(), request.getPlanExecOrgIdList())) {
            throw new RuntimeException("培训机构类型和执行机构不能同时为空!");
        }
        CoreEduTrainingPlan plan = new CoreEduTrainingPlan();
        BeanUtils.copyProperties(request, plan);
        plan.setId(IdWorker.getId());
        plan.setCreateTime(new Date());
        plan.setUpdateTime(new Date());
        plan.setCreateBy(SecurityUtils.getUserId().toString());
        plan.setUpdateBy(SecurityUtils.getUserId().toString());
        plan.setBuildTaskNow(Boolean.TRUE.equals(request.getBuildTaskNow()) ? 1 : 0);
        final Long orgId = SecurityUtils.getLoginUser().getSysUser().getOrgId();
        SysOrg r = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgById(orgId, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
        SysOrg org = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.getSysOrgByUserId(SecurityUtils.getUserId(), SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
        plan.setCreateOrgId(orgId);
        plan.setCreateOrgName(r.getName());
        plan.setCreateOrgPath(r.getPath());
        plan.setBelongOrgId(orgId);
        plan.setBelongOrgName(r.getName());
        plan.setBelongOrgPath(r.getPath());
        batchSavePlanToRole(request.getPlanRoleId(), plan.getId());
        batchSavePlanToExecOrg(request.getPlanExecOrgIdList(), plan.getId());
        //省联社或者办事处创建的计划才存在下发
        if (checkOrgType(org.getType())) {
            plan.setStandard(1);
            plan.setIssue(0);
        }
        int insert = coreEduTrainingPlanMapper.insert(plan);

        //如果不是省联社或者办事处，并且是无周期或者立即生效
        if ((!checkOrgType(plan.getExecOrgType())) && (ObjectUtil.equal(0, plan.getPlanCycle()) || ObjectUtil.equal(0, plan.getBuildTaskNow()))) {
            CoreEduTrainingPlanDataVo detailPlanData = coreEduTrainingPlanMapper.getDetailPlanData(plan.getId());
            coreEduTrainingTaskService.createTaskForNow(detailPlanData, plan.getStartDate(), plan.getEndDate());
        }

        return insert;
    }


    private Boolean checkOrgType(Integer orgType) {
        if (ObjectUtil.isEmpty(orgType)) {
            throw new RuntimeException("当前用户所在机构类型无法确认!");
        }
        //如果是省联社或者办事处则返回1，其他机构类型返回0
        return ObjectUtil.equal(orgType, 1) || ObjectUtil.equal(orgType, 11);
    }

    /**
     * 修改教育培训计划
     *
     * @param request 教育培训计划
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateCoreEduTrainingPlan(CoreEduTrainingPlanEditDto request) {

        if (ObjectUtil.isAllEmpty(request.getExecOrgType(), request.getPlanExecOrgIdList())) {
            throw new RuntimeException("培训机构类型和执行机构不能同时为空!");
        }

        final CoreEduTrainingPlan plan = getById(request.getId());
        BeanUtils.copyProperties(request, plan);
        plan.setUpdateTime(DateUtils.getNowDate());
        plan.setUpdateBy(SecurityUtils.getLoginUser().getSysUser().getId().toString());

        coreEduTrainingPlanToRoleMapper.deleteByMap(MapUtil.of("plan_id", plan.getId()));
        coreEduTrainingPlanToExecOrgMapper.deleteByMap(MapUtil.of("plan_id", plan.getId()));
        batchSavePlanToRole(request.getPlanRoleId(), plan.getId());
        batchSavePlanToExecOrg(request.getPlanExecOrgIdList(), plan.getId());
        return coreEduTrainingPlanMapper.updateById(plan);
    }

    public void batchSavePlanToRole(List<Long> roleIdList, Long planId) {
        if (ObjectUtil.isEmpty(roleIdList)) {
            return;
        }
        List<CoreEduTrainingPlanToRole> planRoleList = new ArrayList<>();
        for (Long roleId : roleIdList) {
            CoreEduTrainingPlanToRole role = new CoreEduTrainingPlanToRole();
            role.setRoleId(roleId);
            role.setPlanId(planId);
            planRoleList.add(role);
        }
        if (CollectionUtil.isNotEmpty(planRoleList)) {
            coreEduTrainingPlanToRoleService.saveBatch(planRoleList);
        }
    }

    public void batchSavePlanToExecOrg(List<Long> orgIdList, Long planId) {
        if (ObjectUtil.isEmpty(orgIdList)) {
            return;
        }
        List<CoreEduTrainingPlanToExecOrg> planOrgList = new ArrayList<CoreEduTrainingPlanToExecOrg>();
        for (Long orgId : orgIdList) {
            CoreEduTrainingPlanToExecOrg org = new CoreEduTrainingPlanToExecOrg();
            org.setOrgId(orgId);
            org.setPlanId(planId);
            planOrgList.add(org);
        }
        coreEduTrainingPlanToExecOrgService.saveBatch(planOrgList);
    }

    /**
     * 批量删除教育培训计划
     *
     * @param ids 需要删除的教育培训计划主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteCoreEduTrainingPlanByIds(Long[] ids) {
        Integer count = coreEduTrainingTaskMapper.checkHasTaskIsDone(Arrays.asList(ids));
        if (count != null && count > 0) {
            throw new RuntimeException("已有任务完成，无法删除");
        }
        return coreEduTrainingPlanMapper.deleteBatchIds(Arrays.asList((ids)));
    }

    /**
     * 删除教育培训计划信息
     *
     * @param id 教育培训计划主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteCoreEduTrainingPlanById(Long id) {
        return coreEduTrainingPlanMapper.deleteById(id);
    }

    @Override
    public List<CoreEduTrainingPlanRoleVo> listPlanRole(Long orgId) {
        if (orgId == null) {
            SysOrg r = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectTopOrg(SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
            orgId = r.getId();
        }
        return coreEduTrainingPlanMapper.selectPlanRole(orgId);
    }

    @Override
    public List<SysOrg> getExecuteOrg(CoreEduTrainingPlan plan) {
        Integer execOrgType = plan.getExecOrgType();
        List<SysOrg> orgList;
        //优先判断是否存在具体的执行机构，如果存在则直接返回，否则根据机构类型进行查询
        QueryWrapper<CoreEduTrainingPlanToExecOrg> eos = new QueryWrapper<>();
        eos.lambda().eq(CoreEduTrainingPlanToExecOrg::getPlanId, plan.getId());
        List<CoreEduTrainingPlanToExecOrg> execOrg = coreEduTrainingPlanToExecOrgMapper.selectList(eos);
        if (ObjectUtil.isNotEmpty(execOrg)) {
            final List<Long> list = execOrg.stream().map(CoreEduTrainingPlanToExecOrg::getOrgId).collect(Collectors.toList());
            orgList = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgByIdList(list, SecurityConstants.INNER), "未能查找到具体的培训机构,请联系管理员!");
            return orgList;
        }
        Assert.notNull(execOrgType, "未能查找到具体的培训机构,请联系管理员!");
        orgList = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectByOrgType(execOrgType, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
        Assert.notEmpty(orgList, "无法根据培训机构类型找到具体机构,请修改计划内容!");
        return orgList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void publishPlan(Long planId) {
        final CoreEduTrainingPlan plan = coreEduTrainingPlanMapper.selectById(planId);
        if (plan == null) {
            throw new SystemException("计划不存在!");
        }
        if (ObjectUtil.equal(plan.getIssue(), 1)) {
            throw new SystemException("计划已完成发布!");
        }
        Assert.isTrue(ObjectUtil.equal(plan.getIssue(), 1), "计划已完成发布!");
        // 下发 按钮显示逻辑:仅省联社安全保卫管理人员进入且由省联社管理安全保卫人员创建的计划才显示
        //todo 判断当前人的角色信息


        //获取执行角色
        LambdaQueryWrapper<CoreEduTrainingPlanToRole> ros = new LambdaQueryWrapper<>();
        ros.eq(CoreEduTrainingPlanToRole::getPlanId, plan.getId());
        List<CoreEduTrainingPlanToRole> planRoleList = coreEduTrainingPlanToRoleMapper.selectList(ros);

        //获取执行机构
        List<SysOrg> executeOrg = this.getExecuteOrg(plan);

        List<CoreEduTrainingPlan> list = new ArrayList<>();
        for (SysOrg sysOrg : executeOrg) {
            CoreEduTrainingPlan coreEduTrainingPlan = new CoreEduTrainingPlan();
            BeanUtils.copyProperties(plan, coreEduTrainingPlan);
            coreEduTrainingPlan.setId(IdWorker.getId());
            coreEduTrainingPlan.setBuildTaskNow(0);
            coreEduTrainingPlan.setBelongOrgId(sysOrg.getId());
            coreEduTrainingPlan.setBelongOrgName(sysOrg.getName());
            coreEduTrainingPlan.setBelongOrgPath(sysOrg.getPath());
            coreEduTrainingPlan.setStandard(0);
            coreEduTrainingPlan.setIssue(0);
            coreEduTrainingPlan.setParentId(planId);
            coreEduTrainingPlan.setCreateTime(new Date());
            coreEduTrainingPlan.setUpdateTime(new Date());
            list.add(coreEduTrainingPlan);
        }
        List<CoreEduTrainingPlanToRole> insertPlanRoleList = new ArrayList<>();
        for (CoreEduTrainingPlan coreEduTrainingPlan : list) {
            //保存执行角色
            for (CoreEduTrainingPlanToRole planRole : planRoleList) {
                CoreEduTrainingPlanToRole role = new CoreEduTrainingPlanToRole();
                role.setPlanId(coreEduTrainingPlan.getId());
                role.setRoleId(planRole.getRoleId());
                insertPlanRoleList.add(role);
            }
        }
        if (list.size() > 0) {
            this.saveBatch(list);
        }
        if (insertPlanRoleList.size() > 0) {
            coreEduTrainingPlanToRoleService.saveBatch(insertPlanRoleList);
        }
        plan.setIssue(1);
        this.updateById(plan);

    }

    @Override
    public CoreEduTrainingPlanDataVo getDetailPlanData(Long id) {
        return coreEduTrainingPlanMapper.getDetailPlanData(id);
    }
}
