package com.chushang.inspection.project.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.shaded.com.google.common.collect.Maps;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chushang.common.core.constant.SecurityConstants;
import com.chushang.common.core.util.DateUtils;
import com.chushang.common.core.util.SpringUtils;
import com.chushang.common.core.util.StringUtils;
import com.chushang.common.core.util.TreeUtils;
import com.chushang.common.core.web.Result;
import com.chushang.common.excel.utils.ExcelUtils;
import com.chushang.common.mybatis.enums.Operator;
import com.chushang.common.mybatis.page.CommonParam;
import com.chushang.common.mybatis.utils.WrapperUtils;
import com.chushang.datascope.annotation.DataScope;
import com.chushang.inspection.project.dto.TaskDTO;
import com.chushang.inspection.project.dto.TaskExcelDTO;
import com.chushang.inspection.project.dto.TaskQuery;
import com.chushang.inspection.project.po.Template;
import com.chushang.inspection.project.service.TbTemplateService;
import com.chushang.inspection.project.vo.ConfigVO;
import com.chushang.inspection.project.vo.TaskVO;
import com.chushang.inspection.project.service.PollingTaskService;
import com.chushang.security.utils.SecurityUtils;
import com.chushang.task.entity.dto.CreateTaskDTO;
import com.chushang.task.enums.ServiceEnum;
import com.chushang.task.enums.TaskTypeEnum;
import com.chushang.task.feign.RemoteTaskService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chushang.inspection.project.mapper.PollingTaskMapper;
import com.chushang.inspection.project.po.PollingTask;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

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

/**
  * @auther: zhao
  * @date: 2024/6/18 15:39
  */
@Slf4j
@Service
@CacheConfig(cacheNames = "task")
public class PollingTaskServiceImpl extends ServiceImpl<PollingTaskMapper, PollingTask> implements PollingTaskService {
    /**
     * 通过远程调用的方式进行入库
     */
    @Resource
    RemoteTaskService remoteTaskService;

    @Override
    @DataScope
    public List<TaskVO> findList(TaskQuery taskQuery)
    {
        LambdaQueryWrapper<PollingTask> taskSql = WrapperUtils.builder(taskQuery, CommonParam.buildPageRequest());
        Long pid = taskQuery.getPid();
        String searchNum = null;
        if (null != pid){
            PollingTask topTask = getOne(new LambdaQueryWrapper<PollingTask>().eq(PollingTask::getId, pid));
            if (ObjectUtil.isNotEmpty(topTask)){
                searchNum = topTask.getSearchNum();
            }
        }
        taskSql.likeRight(StringUtils.isNotBlank(searchNum), PollingTask::getSearchNum, searchNum);
        List<PollingTask> list = list(taskSql);
        if (CollectionUtil.isNotEmpty(list)){
            List<TaskVO> collect = list.stream().map(this::convert).collect(Collectors.toList());
            return TreeUtils.build(collect);
        }
        return new ArrayList<>();
    }

    @Override
    @DataScope
    public List<TaskVO> findTopList(CommonParam commonParam) {
        LambdaQueryWrapper<PollingTask> searchNumSql = WrapperUtils.builder(commonParam, commonParam);
        searchNumSql
                .eq(PollingTask::getParentId, 0)
                .eq(PollingTask::getEnabled, 1)
                .and(w -> w.isNull(PollingTask::getEndTime)
                        .or().ge(PollingTask::getEndTime, DateUtils.format(LocalDateTime.now())));

        List<PollingTask> list = list(searchNumSql);
        if (CollectionUtil.isNotEmpty(list)){
            return list.stream().map(this::convert).collect(Collectors.toList());
        }else {
            return new ArrayList<>();
        }
    }

    @Override
    public ConfigVO findTaskConfig(Long taskId)
    {
        PollingTask task = getById(taskId);
        Assert.notNull(task, "此任务不存在");
        if (task.getParentId() == 0) {
            return BeanUtil.copyProperties(task, ConfigVO.class);
        }
        String searchNum = task.getSearchNum().split("-")[0] + "-";
        CommonParam commonParam = CommonParam.buildPageRequest();
        LambdaQueryWrapper<PollingTask> taskSql = WrapperUtils.builder(commonParam, commonParam);
        taskSql.eq(PollingTask::getSearchNum, searchNum).last(Operator.LIMIT_ONE.getCharacter());
        task = getOne(taskSql);
        Assert.notNull(task, "此任务不存在");
        return BeanUtil.copyProperties(task, ConfigVO.class);
    }

    @Override
    public TaskVO getTaskById(Long taskId) {
        PollingTask task = getById(taskId);
        Assert.notNull(task, "此任务不存在");
        return convert(task);
    }

    @Override
    @Transactional
    public Long saveTask(TaskDTO task) {
        PollingTask pollingTask = BeanUtil.copyProperties(task, PollingTask.class);
        processIndexes(pollingTask);
        // 填充 部门id
//        pollingTask.setDeptId(SecurityUtils.getDeptId());
        save(pollingTask);
        return pollingTask.getId();
    }

    @Override
    @Transactional
    public Long updateTask(TaskDTO task, Long taskId) {
        PollingTask currentTask = getById(taskId);
        Assert.notNull(currentTask, "修改的任务不存在");
        PollingTask pollingTask = BeanUtil.copyProperties(task, PollingTask.class);
        if (!Objects.equals(pollingTask.getParentId(), currentTask.getParentId())) {
            processIndexes(pollingTask);

            LambdaQueryWrapper<PollingTask> taskSql = WrapperUtils.builder();
            taskSql.likeLeft(PollingTask::getSearchNum, currentTask.getSearchNum());
            // 修改下级机构
            List<PollingTask> tasks = list(taskSql);

            if (CollUtil.isNotEmpty(tasks)) {
                for (PollingTask updateTask : tasks) {
                    String replace = StrUtil.replace(updateTask.getSearchNum(), currentTask.getSearchNum(), pollingTask.getSearchNum());
                    updateTask.setSearchNum(replace);
                    updateTask.setLevel(replace.split("-").length);
                    updateById(updateTask);
                }
            }
        }
        if (pollingTask.getParentId() != 0) {
            // 只有顶级可以修改设置
            pollingTask.setIsInspection(null);
            pollingTask.setDispatchMethod(null);
            pollingTask.setReviewMethod(null);
            pollingTask.setIsRepeat(null);
        }
        else {
            Assert.notNull(pollingTask.getIsInspection(), "必须指定是否开通巡检单");
            Assert.notNull(pollingTask.getDispatchMethod(), "必须指定巡检方式");
            Assert.notNull(pollingTask.getReviewMethod(), "必须指定审核方式");
            Assert.notNull(pollingTask.getIsRepeat(), "必须指定是否重复派单");
        }
        if (task.getEnabled() != null && !task.getEnabled().equals(1)) {
            // 同时禁用下级
            String searchNum = pollingTask.getSearchNum();
            LambdaUpdateWrapper<PollingTask> updateSql = new LambdaUpdateWrapper<>();
            updateSql.eq(PollingTask::getSearchNum, searchNum)
                    .set(PollingTask::getEnabled, false);
            update(updateSql);
        }
        pollingTask.setId(currentTask.getId());

        updateById(pollingTask);

        return currentTask.getId();
    }

    @SneakyThrows
    @Override
    public List<TaskExcelDTO> importRead(MultipartFile file) {
//        try (InputStream inputStream = file.getInputStream()) {
        return ExcelUtils.read(file, TaskExcelDTO.class);


//            ExcelUtil.importExcel(inputStream, TaskExcelDTO.class, bulkShipping(pid));
//        } catch (IOException e) {
//            log.error("导入失败", e);
//            Assert.isTrue(false, "导入失败");
//        }
    }

    /**
     * 读取保存
     */
    @Override
    public void importSave(List<TaskExcelDTO> taskExcel, Long parentId)
    {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("data", taskExcel);
        paramMap.put("parentId", parentId);
        Long deptId = SecurityUtils.getDeptId();
        String username = SecurityUtils.getUsername();
        // 交给后台任务
        remoteTaskService.createTask(
                CreateTaskDTO.builder()
                        .params(JSON.toJSONString(paramMap))
                        .taskName("任务导入")
                        .applicationName(ServiceEnum.INSPECTION)
                        .methodName("importTask")
                        .className(this.getClass().getName())
                        .deptId(deptId)
                        .taskType(TaskTypeEnum.UPLOAD)
                        .createBy(username)
                        .build(), SecurityConstants.INNER
        );
    }

    @Override
    @Cacheable(key = "'top-one:' + #taskId")
    public PollingTask getTopTask(Long taskId) {
        PollingTask task = baseMapper.selectById(taskId);
        Assert.notNull(task, "此任务不存在");
        if (task.getParentId() == 0) {
            return task;
        }
        String searchNum = task.getSearchNum().split("-")[0] + "-";
        LambdaQueryWrapper<PollingTask> taskSql = WrapperUtils.builder();
        taskSql.eq(PollingTask::getSearchNum, searchNum)
                .last(Operator.LIMIT_ONE.getCharacter());
        return  baseMapper.selectOne(taskSql);
    }
    @Transactional
    public Result<Boolean> importTask(String params)
    {
        JSONObject jsonObject = JSON.parseObject(params);
        // 数据导入
        JSONArray data = jsonObject.getJSONArray("data");
        if (CollectionUtil.isEmpty(data)) return Result.failed("内容为空");
        List<TaskExcelDTO> tasks = data.toList(TaskExcelDTO.class);
        // 数据集合
        // 父类任务ID
        Long parentId = jsonObject.getLong("parentId");
        Map<String, Long> map = Maps.newHashMap();
        // 一分
        create(parentId == null ? 0 : parentId, tasks.stream().map(TaskExcelDTO::getFirstBank).distinct().collect(Collectors.toList()), map);
        // 二分
        extracted(tasks, map, TaskExcelDTO::getFirstBank, TaskExcelDTO::getSecondBank);
        // 一支
        extracted(tasks, map, TaskExcelDTO::getSecondBank, TaskExcelDTO::getFirstSubBank);
        // 二支
        extracted(tasks, map, TaskExcelDTO::getFirstSubBank, TaskExcelDTO::getSecondSubBank);

        return Result.ok();
    }

    private void extracted(List<TaskExcelDTO> tasks, Map<String, Long> map, Function<TaskExcelDTO, String> groupingBy, Function<TaskExcelDTO, String> mapping) {
        Map<String, Set<String>> secondBanks;
        secondBanks = tasks.stream().filter(f -> StrUtil.isNotEmpty(groupingBy.apply(f)) && StrUtil.isNotEmpty(mapping.apply(f)))
                .distinct().collect(Collectors.groupingBy(groupingBy,
                        Collectors.mapping(mapping, Collectors.toSet())));
        if (CollUtil.isEmpty(secondBanks)) {
            return;
        }
        secondBanks.forEach((k, v) -> create(map.get(k), new ArrayList<>(v), map));
    }

    private void create(Long pid, List<String> names, Map<String, Long> map) {
        Assert.notNull(pid, "【{}】还未指定上级id", names);
        names.forEach(name -> {
            LambdaQueryWrapper<PollingTask> taskSql = WrapperUtils.builder();
            taskSql.eq(PollingTask::getName, name).eq(PollingTask::getParentId, pid);
            List<PollingTask> queryList = list(taskSql);
            // 先通过名称和pid查询是否存在 存在直接返回id 不存在新增
                    if(CollUtil.isEmpty(queryList)){
                        map.put(name,
                                SpringUtils.getBean(this.getClass()).saveTask(TaskDTO.builder().name(name).parentId(pid)
                                        .enabled(1).build())
                        );
                    }else{
                        map.put(name,queryList.get(0).getId());
                    }
                }
        );
    }
    private void processIndexes(PollingTask task) {
        if (task.getParentId() != 0)
        {
            LambdaQueryWrapper<PollingTask> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(PollingTask::getId, task.getParentId()).last(Operator.LIMIT_ONE.getCharacter());
            PollingTask superiorTask = getOne(queryWrapper);
            // 获取上级
            Assert.notNull(superiorTask, "上级任务不存在");
            // 如果上级id存在
            String index = superiorTask.getSearchNum();
            int level = superiorTask.getLevel() + 1;

            Integer max = getBaseMapper().childMaxIndex(index, level);
            max = max != null ? max + 1 : 1;
            task.setSearchNum(index + max + "-");
            task.setSearchIndex(max);
            task.setLevel(level);
            // 只有顶级可以修改设置
            task.setIsInspection(null);
            task.setDispatchMethod(null);
            task.setReviewMethod(null);
            task.setIsRepeat(null);
        }
        else
        {
            // 顶级
            Integer max = getBaseMapper().childMaxIndex(null, 1);
            max = max == null ? 1 : max + 1;
            task.setSearchNum(max + "-");
            task.setSearchIndex(max);
            task.setLevel(max);
        }
    }

    private TaskVO convert(PollingTask task){
        TaskVO taskVO = new TaskVO();
        BeanUtil.copyProperties(task,taskVO);
        taskVO.setTaskId(task.getId());
        taskVO.setTaskName(task.getName());
        return taskVO;
    }

}
