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

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
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.DateRange;
import com.xunmei.common.core.domain.R;
import com.xunmei.common.core.domain.edu.domain.*;
import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskEditDto;
import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskPageDto;
import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskReportDto;
import com.xunmei.common.core.domain.edu.dto.CoreEduTrainingTaskSignDto;
import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingPlanDataVo;
import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingTaskDetailVo;
import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingTaskPageVo;
import com.xunmei.common.core.domain.edu.vo.CoreEduTrainingTaskReportVo;
import com.xunmei.common.core.enums.ExportPdfType;
import com.xunmei.common.core.enums.edu.EduTrainingDoStatus;
import com.xunmei.common.core.enums.edu.EduTrainingType;
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.CoreEduTrainingTaskMapper;
import com.xunmei.core.edu.mapper.CoreEduTrainingTaskToRoleMapper;
import com.xunmei.core.edu.mapper.CoreEduTrainingTaskToUserMapper;
import com.xunmei.core.edu.service.ICoreEduTrainingTaskService;
import com.xunmei.core.edu.service.ICoreEduTrainingTaskToRoleService;
import com.xunmei.core.edu.service.ICoreEduTrainingTaskToUserService;
import com.xunmei.system.api.RemoteFileService;
import com.xunmei.system.api.RemoteOrgService;
import com.xunmei.system.api.domain.SysOrg;
import com.xunmei.system.api.domain.SysUser;
import com.xunmei.system.api.function.RemoteCallHandlerExecutor;
import io.netty.util.internal.StringUtil;
import org.apache.commons.lang3.StringUtils;
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 java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 教育任务Service业务层处理
 *
 * @author xunmei
 * @date 2023-08-27
 */
@Service
public class CoreEduTrainingTaskServiceImpl extends ServiceImpl<CoreEduTrainingTaskMapper, CoreEduTrainingTask> implements ICoreEduTrainingTaskService {
    @Autowired
    private CoreEduTrainingTaskMapper coreEduTrainingTaskMapper;
    @Autowired
    private RemoteOrgService orgService;
    @Autowired
    private RemoteFileService fileService;
    @Autowired
    private ICoreEduTrainingTaskToRoleService coreEduTrainingTaskToRoleService;
    @Autowired
    private CoreEduTrainingTaskToRoleMapper taskToRoleMapper;
    @Autowired
    private CoreEduTrainingTaskToUserMapper taskToUserMapper;
    @Autowired
    private ICoreEduTrainingTaskToUserService coreEduTrainingTaskToUserService;

    @Override
    public TableDataInfo<CoreEduTrainingTaskPageVo> selectPage(CoreEduTrainingTaskPageDto request) {
        if (Boolean.TRUE.equals(request.getCheckSub())) {
            SysOrg org = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgById(request.getOrgId(), SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
            request.setOrgPath(org.getPath());
        }
        IPage<CoreEduTrainingTaskPageVo> pageData = coreEduTrainingTaskMapper.selectPageData(request.getPageRequest(), request);
        if (ObjectUtil.isNotEmpty(pageData.getRecords())) {
            List<Long> idList = pageData.getRecords().stream().map(CoreEduTrainingTaskPageVo::getId).collect(Collectors.toList());
            List<CoreEduTrainingTaskToRole> roleList = taskToRoleMapper.selectList(new LambdaQueryWrapper<CoreEduTrainingTaskToRole>()
                    .in(CoreEduTrainingTaskToRole::getEduTrainingTaskId, idList));
            Map<Long, List<CoreEduTrainingTaskToRole>> listMap = roleList.stream().collect(Collectors.groupingBy(CoreEduTrainingTaskToRole::getEduTrainingTaskId));
            for (CoreEduTrainingTaskPageVo record : pageData.getRecords()) {
                record.setNo(pageData.getRecords().indexOf(record) + 1);
                record.setTypeText(EduTrainingType.getName(record.getType()));
                record.setStatusText(EduTrainingDoStatus.getName(record.getStatus()));
                List<CoreEduTrainingTaskToRole> coreEduTrainingTaskToRoles = listMap.get(record.getId());
                if (ObjectUtil.isEmpty(coreEduTrainingTaskToRoles)) {
                    continue;
                }
                record.setTaskRoleNameList(coreEduTrainingTaskToRoles.stream().map(CoreEduTrainingTaskToRole::getRoleName).collect(Collectors.joining(",")));
            }
        }

        //抓换为TableDataInfo适配前端
        return TableDataInfo.build(pageData);
    }


    /**
     * 查询教育任务
     *
     * @param id 教育任务主键
     * @return 教育任务
     */
    @Override
    public CoreEduTrainingTaskDetailVo selectCoreEduTrainingTaskById(Long id) {
        CoreEduTrainingTaskDetailVo detailVo = coreEduTrainingTaskMapper.selectEduTrainingTaskDetail(id);
        List<CoreEduTrainingTaskToUser> userList = taskToUserMapper.selectByMap(MapUtil.of("edu_training_task_id", id));
        if (ObjectUtil.isNotEmpty(userList)) {
            detailVo.setTaskUserList(userList);
        }
        return detailVo;
    }

    /**
     * 查询教育任务列表
     *
     * @param coreEduTrainingTask 教育任务
     * @return 教育任务
     */
    @Override
    public List<CoreEduTrainingTask> selectCoreEduTrainingTaskList(CoreEduTrainingTask coreEduTrainingTask) {
        return coreEduTrainingTaskMapper.selectList(new QueryWrapper<>(coreEduTrainingTask));
    }

    /**
     * 新增教育任务
     *
     * @param coreEduTrainingTask 教育任务
     * @return 结果
     */
    @Override
    public int insertCoreEduTrainingTask(CoreEduTrainingTask coreEduTrainingTask) {
        coreEduTrainingTask.setCreateTime(DateUtils.getNowDate());
        return coreEduTrainingTaskMapper.insert(coreEduTrainingTask);
    }

    /**
     * 修改教育任务
     *
     * @param request 教育任务
     * @return 结果
     */
    @Override
    public int updateCoreEduTrainingTask(CoreEduTrainingTaskEditDto request) {
        CoreEduTrainingTask coreEduTrainingTask = coreEduTrainingTaskMapper.selectById(request.getId());
        BeanUtils.copyProperties(request, coreEduTrainingTask);

        List<CoreEduTrainingTaskToUser> taskUserList = request.getTaskUserList();
        if (taskUserList != null && taskUserList.size() > 0) {
            for (CoreEduTrainingTaskToUser taskToUser : taskUserList) {
                taskToUser.setEduTrainingTaskId(request.getId());
                taskToUser.setSign(0);
            }
            coreEduTrainingTaskToUserService.saveBatch(taskUserList);
        }
        if (ObjectUtil.equal(request.getSubmitType(), 2)) {
            coreEduTrainingTask.setStatus(EduTrainingDoStatus.WAIT_SIGN.getCode());
        }

        coreEduTrainingTask.setUpdateBy(SecurityUtils.getLoginUser().getSysUser().getId().toString());
        coreEduTrainingTask.setUpdateTime(DateUtils.getNowDate());
        return coreEduTrainingTaskMapper.updateById(coreEduTrainingTask);
    }

    /**
     * 批量删除教育任务
     *
     * @param ids 需要删除的教育任务主键
     * @return 结果
     */
    @Override
    public int deleteCoreEduTrainingTaskByIds(Long[] ids) {
        return coreEduTrainingTaskMapper.deleteBatchIds(Arrays.asList((ids)));
    }

    /**
     * 删除教育任务信息
     *
     * @param id 教育任务主键
     * @return 结果
     */
    @Override
    public int deleteCoreEduTrainingTaskById(Long id) {
        return coreEduTrainingTaskMapper.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void createTaskForNow(CoreEduTrainingPlanDataVo plan, Date start, Date end) {

        //如果不是无周期的计划，那么需要查询出他的时间范围
        if (plan.getPlanCycle() != 0) {
            DateRange dateRange = DateUtils.getStartAndEnd(new Date(), plan.getPlanCycle());
            start = dateRange.getStartTime();
            end = dateRange.getEndTime();
        }
        List<CoreEduTrainingPlanToExecOrg> planExecOrgList = plan.getPlanExecOrgList();
        List<SysOrg> orgList;
        if (ObjectUtil.isEmpty(planExecOrgList)) {
            Integer orgType = plan.getExecOrgType();
            orgList = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectByOrgType(orgType, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
        } else {
            List<Long> list = planExecOrgList.stream().map(CoreEduTrainingPlanToExecOrg::getOrgId).collect(Collectors.toList());
            orgList = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgByIdList(list, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
        }
        Integer execTimes = plan.getExecTimes();
        Map<Integer, DateRange> dateMap = DateUtils.splitDateRange(start, end, execTimes);
        saveTaskAndRoleData(plan, start, end, orgList, dateMap);
    }

    private void saveTaskAndRoleData(CoreEduTrainingPlanDataVo plan, Date start, Date end, List<SysOrg> orgList, Map<Integer, DateRange> dateMap) {
        List<CoreEduTrainingPlanToRole> planRoleList = plan.getPlanRoleList();
        List<CoreEduTrainingTask> taskList = new ArrayList<>();
        List<CoreEduTrainingTaskToRole> taskRoleList = new ArrayList<>();
        for (SysOrg org : orgList) {
            for (Map.Entry<Integer, DateRange> entry : dateMap.entrySet()) {
                Date startTime = entry.getValue().getStartTime();
                Date endTime = entry.getValue().getEndTime();
                CoreEduTrainingTask trainingTask = new CoreEduTrainingTask();
                trainingTask.setId(IdWorker.getId());
                trainingTask.setPlanId(plan.getId());
                trainingTask.setPlanCycle(plan.getPlanCycle());
                trainingTask.setStartDate(startTime);
                trainingTask.setEndDate(endTime);
                trainingTask.setContent(null);
                trainingTask.setTitle(plan.getPlanName());
                trainingTask.setNote(null);
                trainingTask.setTrainingStartDateTime(null);
                trainingTask.setTrainingEndDateTime(null);
                trainingTask.setFileList(ObjectUtil.isEmpty(plan.getFileList()) ? null : JSON.toJSONString(plan.getFileList()));
                trainingTask.setImageList(null);
                trainingTask.setOrgId(org.getId());
                trainingTask.setType(null);
                trainingTask.setOrgName(org.getName());
                trainingTask.setOrgPath(org.getPath());
                trainingTask.setStatus(EduTrainingDoStatus.WAIT_RECORDED.getCode());
                trainingTask.setPdfUrl(null);
                trainingTask.setCreateTime(new Date());
                trainingTask.setUpdateTime(new Date());
                taskList.add(trainingTask);
                for (CoreEduTrainingPlanToRole planToRole : planRoleList) {
                    CoreEduTrainingTaskToRole coreEduTrainingTaskToRole = new CoreEduTrainingTaskToRole();
                    coreEduTrainingTaskToRole.setEduTrainingTaskId(trainingTask.getId());
                    coreEduTrainingTaskToRole.setRoleId(planToRole.getRoleId());
                    coreEduTrainingTaskToRole.setRoleName(planToRole.getRoleName());
                    taskRoleList.add(coreEduTrainingTaskToRole);
                }
            }


        }
        if (ObjectUtil.isNotEmpty(taskList)) {
            this.saveBatch(taskList);
        }
        if (ObjectUtil.isNotEmpty(taskRoleList)) {
            coreEduTrainingTaskToRoleService.saveBatch(taskRoleList);
        }
    }


    @Override
    public List<CoreEduTrainingTaskReportVo> selectCoreEduTrainingTaskReport(CoreEduTrainingTaskReportDto request) {
        request.setStartDate(DateUtil.beginOfMonth(request.getDate()));
        request.setEndDate(DateUtil.endOfMonth(request.getDate()));
        Long orgId = request.getOrgId();

        List<SysOrg> sysOrgList = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectSysOrgByParentId(orgId, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
        if (ObjectUtil.isEmpty(sysOrgList)) {

            return new ArrayList<>();
        }
        List<CoreEduTrainingTaskReportVo> list = coreEduTrainingTaskMapper.selectReport(request);
        list.forEach(item -> {
            item.setFinishRate(calculatePercent(item.getShouldFinish(), item.getFinish()));
        });


        return list;
    }

    private String calculatePercent(Integer num1, Integer num2) {
        if (num1 == 0 || num2 == 0) {
            return "0%";
        }
        BigDecimal a1 = new BigDecimal(num1);
        BigDecimal a2 = new BigDecimal(num2);
        BigDecimal r = a1.divide(a2, 4, RoundingMode.HALF_UP);
        NumberFormat percent = NumberFormat.getPercentInstance();
        percent.setMaximumFractionDigits(4);
        return percent.format(r.doubleValue());
    }

    @Override
    public Integer selectCoreEduTrainingTaskSign(CoreEduTrainingTaskSignDto request) {
        SysUser sysUser = SecurityUtils.getLoginUser().getSysUser();
        CoreEduTrainingTaskToUser taskToUser = taskToUserMapper.selectOne(new LambdaQueryWrapper<CoreEduTrainingTaskToUser>()
                .eq(CoreEduTrainingTaskToUser::getEduTrainingTaskId, request.getId())
                .eq(CoreEduTrainingTaskToUser::getType, 1)
                .eq(CoreEduTrainingTaskToUser::getUserId, sysUser.getId()));
        if (taskToUser == null) {
            throw new SystemException("未获取到当前用户于该教育培训的详细信息");
        }
        taskToUser.setSign(1);
        taskToUser.setSignImage(request.getSignImage());
        return taskToUserMapper.updateSign(taskToUser);
    }

    @Override
    public String buildEduPdf(Long id) {
        CoreEduTrainingTaskDetailVo task = this.selectCoreEduTrainingTaskById(id);
        SysOrg sysOrg = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgById(task.getOrgId(), SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
        String[] strings = sysOrg.getPath().split("-");
        List<Long> list = Arrays.stream(strings).map(Long::valueOf).collect(Collectors.toList());
        List<SysOrg> sysOrgList = RemoteCallHandlerExecutor.executeRemoteCall(() -> orgService.selectOrgByIdList(list, SecurityConstants.INNER), ErrorMsgConstants.QUERY_ORG_DATA_ERROR);
        String orgName = sysOrgList.stream().map(SysOrg::getName).collect(Collectors.joining("_"));

        String fileName = orgName + "_" + ExportPdfType.EDUCATION_TRAINING.getText() + "_" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + ".pdf";
        Map<String, Object> data = this.getFtlEdu(task);

        R<String> r = RemoteCallHandlerExecutor.executeRemoteCall(() -> fileService.generateEduTrainingPdf(data, fileName), ErrorMsgConstants.GENERATE_PDF_ERROR);
        if (ObjectUtil.hasEmpty(r, r.getData())) {
            throw new SystemException(ErrorMsgConstants.GENERATE_PDF_ERROR);
        }

       /* //新方式生成pdf
        try {
            String url = createEduPdfByNewType(data, dest);
            //此处set以后 jpa框架自动保存入库
            edu.setPdfUrl(url);

            final RegisterBookPdf bookPdf = new RegisterBookPdf();
            bookPdf.setId(IDHelper.id());
            bookPdf.setRegisterBookType(ExportPdfType.EDUCATION_TRAINING);
            bookPdf.setDate(new Date());
            bookPdf.setOrgId(edu.getOrgId());
            bookPdf.setPdfUrl(url);
            registerBookPdfMapper.insert(bookPdf);
            return url;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }*/
        return r.getData();
    }

    private Map<String, Object> getFtlEdu(CoreEduTrainingTaskDetailVo task) {
        Map<String, Object> data = new HashMap<>();
        String time = DateUtil.format(task.getTrainingStartDateTime(), "yyyy年MM月dd日");
        String address = task.getOrgName();
        String hostName = task.getHostName() == null ? StringUtil.EMPTY_STRING : task.getHostName();
        String recorderName = task.getRecorderName() == null ? StringUtil.EMPTY_STRING : task.getRecorderName();
        String content = task.getContent();
        String note = task.getNote();
        data.put("time", StringUtils.isNotEmpty(time) ? time : StringUtil.EMPTY_STRING);
        data.put("address", StringUtils.isNotEmpty(address) ? time : StringUtil.EMPTY_STRING);
        data.put("hostName", StringUtils.isNotEmpty(hostName) ? hostName : StringUtil.EMPTY_STRING);
        data.put("recorderName", StringUtils.isNotEmpty(recorderName) ? recorderName : StringUtil.EMPTY_STRING);
        data.put("content", StringUtils.isNotEmpty(content) ? "内容: " + content : StringUtil.EMPTY_STRING);
        data.put("note", StringUtils.isNotEmpty(note) ? "总结: " + note : StringUtil.EMPTY_STRING);
        data.put("image", ObjectUtil.isNotEmpty(task.getTaskUserList()) ? task.getTaskUserList() : StringUtil.EMPTY_STRING);
        return data;
    }

    private String generateFilePath(String fileName) {
        String resource = "cache";
        File file = new File(resource);
        if (!file.exists()) {
            file.mkdirs();
        }
        return resource + File.separator + fileName;
    }
}


