/*
 * Author: wangjian
 * 生成ServiceImpl
 */
package com.tofly.xrtymis.custom.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tofly.common.core.entity.ResultRespone;
import com.tofly.common.core.util.Date8Util;
import com.tofly.common.core.util.StringUtil;
import com.tofly.common.oauth.exception.ToflyDeniedException;
import com.tofly.common.oauth.util.SecurityUtils;
import com.tofly.xrtymis.custom.commons.Constate;
import com.tofly.xrtymis.custom.dto.ForeignOrderDto;
import com.tofly.xrtymis.custom.dto.other.GdConfigDto;
import com.tofly.xrtymis.custom.entity.OrderTypeByIdResult;
import com.tofly.xrtymis.custom.entity.TypeTree;
import com.tofly.xrtymis.custom.service.GdflowconfigService;
import com.tofly.xrtymis.custom.service.GdgltypebmService;
import com.tofly.xrtymis.custom.vo.ConfingTypeVo;
import com.tofly.xrtymis.entity.Gddepartment;
import com.tofly.xrtymis.entity.Gdflowconfig;
import com.tofly.xrtymis.entity.Gdgltypebm;
import com.tofly.xrtymis.entity.Gdperson;
import com.tofly.xrtymis.mapper.GddepartmentMapper;
import com.tofly.xrtymis.mapper.GdflowconfigMapper;
import com.tofly.xrtymis.mapper.GdpersonMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * ${comments}
 *
 * @author fcl
 * @date Mon May 31 00:00:00 CST 2021
 */
@Service("gdflowconfigService")
public class GdflowconfigServiceImpl extends ServiceImpl<GdflowconfigMapper, Gdflowconfig> implements GdflowconfigService {

    @Autowired
    private GddepartmentMapper gddepartmentMapper;
    @Autowired
    private GdpersonMapper gdpersonMapper;
    @Autowired
    private GdgltypebmService gdgltypebmService;

    @Override
    public Gdflowconfig getByOrderType(Long gdlx) {
        QueryWrapper<Gdflowconfig> wrapper = new QueryWrapper<>();
        wrapper.eq("GDLX", gdlx);
        return baseMapper.selectOne(wrapper);
    }

    /**
     * 根据类型id获取工单流程配置
     *
     * @param id    工单类型
     * @param xf1id 工单类型细分1
     * @param xf2id 工单类型细分2
     * @return
     */
    @Override
    public Gdflowconfig loadGdFlowConfig(Long id, Long xf1id, Long xf2id) {
        if (xf2id != null) {
            return getOne(new QueryWrapper<Gdflowconfig>().lambda()
                    .eq(Gdflowconfig::getGdlx, id).eq(Gdflowconfig::getGdxf1, xf1id).eq(Gdflowconfig::getGdxf2, xf2id).eq(Gdflowconfig::getSfDelete, 1));
        }

        if (xf1id != null) {
            return getOne(new QueryWrapper<Gdflowconfig>().lambda()
                    .eq(Gdflowconfig::getGdlx, id).eq(Gdflowconfig::getGdxf1, xf1id).eq(Gdflowconfig::getSfDelete, 1).isNull(Gdflowconfig::getGdxf2));

        }
        return getOne(new QueryWrapper<Gdflowconfig>().lambda()
                .eq(Gdflowconfig::getGdlx, id).eq(Gdflowconfig::getSfDelete, 1).isNull(Gdflowconfig::getGdxf1));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultRespone saveConfig(GdConfigDto gdConfigDto) {
        if (gdConfigDto.getTransferOutType() != null && gdConfigDto.getTabType() != null) {
            return ResultRespone.failed(false, "转入其它流程与接入其它流程不能同时存在");
        }
        //工单类型、细分集合
        List<Gdflowconfig> gdflowconfigList = gdConfigDto.getGdflowconfigList();
        if (StringUtil.isNotNull(gdflowconfigList) && gdflowconfigList.size() > 0) {
            //对传入的工单类型配置中验证是否有重复的，因为这里多变量（工单类型、细分1、细分2），所以直接将三个变量组合判断
            Map<String, List<Gdflowconfig>> groupBylx = gdflowconfigList.stream()
                    //这里添加中文区分，是由于可能存在工单类型11，细分111和工单类型111，细分11的情况，导致最后的比较错误
                    .collect(Collectors.groupingBy(v -> "工单类型" + v.getGdlx() + "细分一" + v.getGdxf1() + "细分二" + v.getGdxf2()));
            //键集合；用于查询数据库时，使用三个变量组合查询数据库，判断是否已经有配置好的流程
            List<String> keyList = new ArrayList<>();
            groupBylx.forEach((k, v) -> {
                if (v.size() > 1) {
                    throw new ToflyDeniedException("请仔细检查工单类型和细分中是否存在重复数据上传");
                }
                //去null字段
                keyList.add(k.replace("null", ""));
            });
            //需要查询已配置好的流程；流程配置中是否已经添加了相同的工单类型、细分1和细分2
            List<Gdflowconfig> isExistConfig = baseMapper.selectExist(keyList);
            if (StringUtil.isNotNull(isExistConfig) && isExistConfig.size() > 0) {
                StringBuilder stringBuilder = new StringBuilder();
                for (Gdflowconfig existConfig : isExistConfig) {
                    String error = "工单类型：" + existConfig.getGdlxName() + ",";
                    String xf1 = existConfig.getGdxf1Name();
                    if (StringUtil.isNotEmpty(xf1)) {
                        error = error + "细分1：" + xf1 + ",";
                        String xf2 = existConfig.getGdxf2Name();
                        if (StringUtil.isNotEmpty(xf2)) {
                            error = error + "细分2：" + xf2 + ",";
                        }
                    }
                    stringBuilder.append(error);
                }
                throw new ToflyDeniedException("以下配置：" + stringBuilder + "已存在，不能重复添加");
            }
            //得到配置中最后一级的工单类型
            List<Long> gdlxList = new ArrayList<>();
            for (Gdflowconfig gdflowconfig : gdflowconfigList) {
                if (StringUtil.isNotNull(gdflowconfig.getGdxf2())){
                    gdlxList.add(gdflowconfig.getGdxf2());
                }else if (StringUtil.isNotNull(gdflowconfig.getGdxf1())){
                    gdlxList.add(gdflowconfig.getGdxf1());
                }else if (StringUtil.isNotNull(gdflowconfig.getGdlx())){
                    gdlxList.add(gdflowconfig.getGdlx());
                }
            }
            //查询工单类型
            List<Gdgltypebm> gdgltypebmList = gdgltypebmService.list(Wrappers.<Gdgltypebm>lambdaQuery().in(gdlxList.size() > 0,Gdgltypebm::getId , gdlxList)
                    .select(Gdgltypebm::getId , Gdgltypebm::getViewType));
            Map<Long , Gdgltypebm> gdgltypebmMap = gdgltypebmList.stream().collect(Collectors.toMap(Gdgltypebm::getId , v -> v));

            //节点人员配置集合
            List<Gdperson> gdpersonList = gdConfigDto.getGdpersonList();
            //节点部门配置集合
            List<Gddepartment> gddepartmentList = gdConfigDto.getGddepartmentList();
            //gdConfigDto中的其他均为流程配置公共参数
            Gdflowconfig gdflowconfig = new Gdflowconfig();
            //公共参数转变
            BeanUtils.copyProperties(gdConfigDto, gdflowconfig);
            //流程配置最大ID
            Long configMaxId = baseMapper.getMaxId();
            //流程部门最大ID
            Long departMaxId = gddepartmentMapper.departMaxId();
            List<Gddepartment> departList = new ArrayList<>();
            //节点人员最大ID
            Long personMaxId = gdpersonMapper.personMaxId();
            List<Gdperson> personList = new ArrayList<>();
            for (int i = 0; i < gdflowconfigList.size(); i++) {
                //设置流程配置主键ID
                gdflowconfigList.get(i).setId(configMaxId + i);
                Gdflowconfig gdflowconfigViewType = gdflowconfigList.get(i);
                //设置流程配置的viewType
                if (StringUtil.isNotNull(gdflowconfigViewType.getGdxf2())){
                    gdflowconfigList.get(i).setViewType(gdgltypebmMap.get(gdflowconfigViewType.getGdxf2()).getViewType());
                }else if (StringUtil.isNotNull(gdflowconfigViewType.getGdxf1())){
                    gdflowconfigList.get(i).setViewType(gdgltypebmMap.get(gdflowconfigViewType.getGdxf1()).getViewType());
                }else if (StringUtil.isNotNull(gdflowconfigViewType.getGdlx())){
                    gdflowconfigList.get(i).setViewType(gdgltypebmMap.get(gdflowconfigViewType.getGdlx()).getViewType());
                }

                //设置部门流程ID
                for (Gddepartment depart : gddepartmentList) {
                    Gddepartment gddepartment = new Gddepartment();
                    gddepartment.setDepartId(depart.getDepartId());
                    gddepartment.setConfigId(configMaxId + i);
                    gddepartment.setDepartName(depart.getDepartName());
                    gddepartment.setId(departMaxId++);
                    departList.add(gddepartment);
                }
                //设置人员流程
                for (Gdperson person : gdpersonList) {
                    Gdperson gdperson = new Gdperson();
                    BeanUtils.copyProperties(person, gdperson);
                    gdperson.setConfigId(configMaxId + i);
                    gdperson.setId(personMaxId++);
                    personList.add(gdperson);
                }
            }
            Date currentDate = Date8Util.getCurrentDate();
            Long userId = SecurityUtils.getUserId();
            //保存工单流程配置
            boolean flag = baseMapper.insertBatchConfig(gdflowconfigList, gdflowconfig, currentDate , userId);
            //保存部门
            gddepartmentMapper.insertBatchDepart(departList);

            if (StringUtil.isNotNull(personList) && personList.size() >0){
                //如果长度超过了1000，那么使用数据库的IN查询会报错，IN查询最大只能包含1000个数据，所以需要根据1000分段查询
                int size = personList.size();
                //向上取整 , 获得次数，但是次数不多，只有几次，所以可以使用for循环分段查询
                int count = (int) Math.ceil(Double.valueOf(size) / 1000d);
                for (int i = 0; i < count; i++) {
                    int startIndex = i * 1000;
                    int endIndex = 1000 + i * 1000;
                    List<Gdperson> subList = null;
                    //判断是否截取的最后一次数据，如果是最后一次数据，则不能使用endIndex这个参数去截取了，有可能会存在endIndex参数值超过索引最大值的情况
                    if (i < count - 1) {
                        subList = personList.subList(startIndex, endIndex);
                    } else {
                        //分段采取最后的数据
                        subList = personList.subList(startIndex, personList.size());
                    }
                    //保存人员
                    gdpersonMapper.insertBatchPerson(subList);
                }
            }

        } else {
            throw new ToflyDeniedException("请正确添加工单类型配置");
        }
        return ResultRespone.success(true);
    }

    @Override
    public IPage<OrderTypeByIdResult> getConfig(Page page, String type, String departId, String sfDelete , Long gdlx , String viewType) {
        List<String> typeList = null;
        List<String> departList = null;
        if (StringUtil.isNotEmpty(type)) {
            typeList = Arrays.asList(type.split(","));
        }
        if (StringUtil.isNotEmpty(departId)) {
            departList = Arrays.asList(departId.split(","));
        }

        return baseMapper.getConfig(page, typeList, departList, sfDelete , gdlx, viewType);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultRespone updateConfig(GdConfigDto gdConfigDto) {
        if (gdConfigDto.getTransferOutType() != null && gdConfigDto.getTabType() != null) {
            return ResultRespone.failed(false, "转入其它流程与接入其它流程不能同时存在");
        }
        Gdflowconfig selGdf = new Gdflowconfig();
        selGdf.setGdlx(gdConfigDto.getGdflowconfigList().get(0).getGdlx());
        selGdf.setGdxf1(gdConfigDto.getGdflowconfigList().get(0).getGdxf1());
        selGdf.setGdxf2(gdConfigDto.getGdflowconfigList().get(0).getGdxf2());
        selGdf.setSfDelete("1");
        Gdflowconfig gf = this.getOne(Wrappers.query(selGdf).lambda().isNull(selGdf.getGdxf1() == null, Gdflowconfig::getGdxf1).isNull(selGdf.getGdxf2() == null, Gdflowconfig::getGdxf2));
        if (gf != null && !gf.getId().equals(gdConfigDto.getId())) {
            return ResultRespone.failed(false, "名称重复");
        }
        //逻辑删除之前被修改的流程配置
        boolean isupdate = this.update(new UpdateWrapper<Gdflowconfig>().lambda().set(Gdflowconfig::getSfDelete, 0).eq(Gdflowconfig::getId, gdConfigDto.getId()));
        if (isupdate) {
            //实体转化
            Gdflowconfig gdflowconfig = new Gdflowconfig();
            BeanUtils.copyProperties(gdConfigDto, gdflowconfig);
            gdflowconfig.setId(null);
            gdflowconfig.setGdlx(gdConfigDto.getGdflowconfigList().get(0).getGdlx());
            gdflowconfig.setGdxf1(gdConfigDto.getGdflowconfigList().get(0).getGdxf1());
            gdflowconfig.setGdxf2(gdConfigDto.getGdflowconfigList().get(0).getGdxf2());
            //设置流程配置的viewType
            if (StringUtil.isNotNull(gdflowconfig.getGdxf2())){
                Gdgltypebm gdgltypebm = gdgltypebmService.getOne(Wrappers.<Gdgltypebm>lambdaQuery().eq(Gdgltypebm::getId , gdflowconfig.getGdxf2())
                        .select(Gdgltypebm::getId , Gdgltypebm::getViewType));
                gdflowconfig.setViewType(gdgltypebm.getViewType());
            }else if (StringUtil.isNotNull(gdflowconfig.getGdxf1())){
                Gdgltypebm gdgltypebm = gdgltypebmService.getOne(Wrappers.<Gdgltypebm>lambdaQuery().eq(Gdgltypebm::getId , gdflowconfig.getGdxf1())
                        .select(Gdgltypebm::getId , Gdgltypebm::getViewType));
                gdflowconfig.setViewType(gdgltypebm.getViewType());
            }else if (StringUtil.isNotNull(gdflowconfig.getGdlx())){
                Gdgltypebm gdgltypebm = gdgltypebmService.getOne(Wrappers.<Gdgltypebm>lambdaQuery().eq(Gdgltypebm::getId , gdflowconfig.getGdlx())
                        .select(Gdgltypebm::getId , Gdgltypebm::getViewType));
                gdflowconfig.setViewType(gdgltypebm.getViewType());
            }
            //保存一条修改后的最新流程配置
            this.save(gdflowconfig);
            //刚插入的流程ID
            Long configId = gdflowconfig.getId();
            //流程部门最大ID
            Long departMaxId = gddepartmentMapper.departMaxId();
            List<Gddepartment> departList = new ArrayList<>();
            //节点人员最大ID
            Long personMaxId = gdpersonMapper.personMaxId();
            List<Gdperson> personList = new ArrayList<>();
            //节点人员配置集合
            List<Gdperson> gdpersonList = gdConfigDto.getGdpersonList();
            //节点部门配置集合
            List<Gddepartment> gddepartmentList = gdConfigDto.getGddepartmentList();
            //设置部门流程ID
            for (Gddepartment depart : gddepartmentList) {
                Gddepartment gddepartment = new Gddepartment();
                gddepartment.setDepartId(depart.getDepartId());
                gddepartment.setConfigId(configId);
                gddepartment.setDepartName(depart.getDepartName());
                gddepartment.setId(departMaxId++);
                departList.add(gddepartment);
            }
            //设置人员流程
            for (Gdperson person : gdpersonList) {
                Gdperson gdperson = new Gdperson();
                BeanUtils.copyProperties(person, gdperson);
                gdperson.setConfigId(configId);
                gdperson.setId(personMaxId++);
                personList.add(gdperson);
            }
            //保存部门
            gddepartmentMapper.insertBatchDepart(departList);
            if (StringUtil.isNotNull(personList) && personList.size() > 0){
                //如果长度超过了1000，那么使用数据库的IN查询会报错，IN查询最大只能包含1000个数据，所以需要根据1000分段查询
                int size = personList.size();
                //向上取整 , 获得次数，但是次数不多，只有几次，所以可以使用for循环分段查询
                int count = (int) Math.ceil(Double.valueOf(size) / 1000d);
                for (int i = 0; i < count; i++) {
                    int startIndex = i * 1000;
                    int endIndex = 1000 + i * 1000;
                    List<Gdperson> subList = null;
                    //判断是否截取的最后一次数据，如果是最后一次数据，则不能使用endIndex这个参数去截取了，有可能会存在endIndex参数值超过索引最大值的情况
                    if (i < count - 1) {
                        subList = personList.subList(startIndex, endIndex);
                    } else {
                        //分段采取最后的数据
                        subList = personList.subList(startIndex, personList.size());
                    }
                    //保存人员
                    gdpersonMapper.insertBatchPerson(subList);
                }
            }
            return ResultRespone.success(true, "修改成功");
        } else {
            return ResultRespone.failed(false, "无记录修改");
        }
    }

    @Override
    public ResultRespone getTypeTree(String viewType) {
        //查询配置好的工单类型流程
        List<Gdflowconfig> gdflowconfigList = this.list(Wrappers.<Gdflowconfig>lambdaQuery().eq(Gdflowconfig::getSfDelete, "1")
                .select(Gdflowconfig::getGdlx, Gdflowconfig::getGdxf1, Gdflowconfig::getGdxf2)
                .like(StringUtil.isNotEmpty(viewType),Gdflowconfig::getViewType,viewType));
        //以下是组成树形结构，因为数据比较特殊，没有父级ID的情况，所以挨个分组判断
        //按照工单类型分组
        Map<String , List<Gdflowconfig>> groupByGdlx = gdflowconfigList.stream().collect(Collectors.groupingBy(v -> v.getGdlx() + "-" + v.getGdlxName()));
        if (StringUtil.isNotNull(groupByGdlx)){
            List<TypeTree> typeTreeList = new ArrayList<>();
            groupByGdlx.forEach((k , v) -> {
                TypeTree typeTree = new TypeTree();
                String[] gdlx = k.split("-");
                String lxId = gdlx[0];
                String lxName = gdlx[1];
                if (StringUtil.isNotEmpty(lxId)){
                    typeTree.setLxId(Long.parseLong(lxId));
                }
                typeTree.setLxName(lxName);
                List<TypeTree> xf1List = new ArrayList<>();
                //工单细分1分组
                Map<String , List<Gdflowconfig>> groupByGdxf1 = v.stream().collect(Collectors.groupingBy(xf1 -> xf1.getGdxf1() + "-" + xf1.getGdxf1Name()));
                groupByGdxf1.forEach((xf1K , xf1V) -> {
                    String[] xf1lx = xf1K.replace("null" , "").split("-");
                    if (xf1lx.length != 0){
                        TypeTree xf1Tree = new TypeTree();
                        String xf1Id = xf1lx[0];
                        String xf1Name = xf1lx[1];
                        if (StringUtil.isNotEmpty(xf1Id)){
                            xf1Tree.setLxId(Long.parseLong(xf1Id));
                        }
                        xf1Tree.setLxName(xf1Name);
                        List<TypeTree> xf2List = new ArrayList<>();
                        //工单细分2分组
                        Map<String , List<Gdflowconfig>> groupByGdxf2 = xf1V.stream().collect(Collectors.groupingBy(xf2 -> xf2.getGdxf2() + "-" + xf2.getGdxf2Name()));
                        groupByGdxf2.forEach((xf2K , xf2V) -> {
                            String[] xf2lx = xf2K.replace("null" , "").split("-");
                            if (xf2lx.length != 0){
                                TypeTree xf2Tree = new TypeTree();
                                String xf2Id = xf2lx[0];
                                String xf2Name = xf2lx[1];
                                if (StringUtil.isNotEmpty(xf2Id)){
                                    xf2Tree.setLxId(Long.parseLong(xf2Id));
                                }
                                xf2Tree.setLxName(xf2Name);
                                xf2List.add(xf2Tree);
                            }
                        });
                        xf1Tree.setXf2List(xf2List);
                        xf1List.add(xf1Tree);
                    }
                });
                typeTree.setXf1List(xf1List);
                typeTreeList.add(typeTree);
            });
            List<Map> mapList = JSONArray.parseArray(JSONObject.toJSONString(typeTreeList) , Map.class);
            return ResultRespone.success(mapList);
        }else {
            return ResultRespone.success(false , "暂无配置流程");
        }


    }

    @Override
    public List<ConfingTypeVo> getOrderType() {
        return this.baseMapper.getOrderType();
    }

    @Override
    public String orderTypeCheck(ForeignOrderDto dto) {
        Gdflowconfig gdflowconfig= this.getById(dto.getGdlxid());
        if(gdflowconfig==null){
            return Constate.GDFLOWCONFIG_ID_NULL;
        }
        try {
            SecurityUtils.getUserId();
        }catch (Exception e){
            return "请登录";
        }

        return null;
    }


}
