/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.manager.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springblade.business.entity.ConstructionLedger;
import org.springblade.business.mapper.ConstructionLedgerMapper;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.log.logger.BladeLogger;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.manager.dto.FormElementDTO;
import org.springblade.manager.dto.WbsTreeContractDTO;
import org.springblade.manager.entity.*;
import org.springblade.manager.excel.WbsExcelUtil;
import org.springblade.manager.mapper.*;
import org.springblade.manager.service.IWbsFormElementService;
import org.springblade.manager.service.IWbsTreeService;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.manager.vo.WbsNodeTableVO;
import org.springblade.manager.vo.WbsTreeAllListVO;
import org.springblade.manager.vo.WbsTreeContractVO;
import org.springblade.manager.vo.WbsTreeVO;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * 服务实现类
 *
 * @author liuyc
 * @since 2022-04-25
 */
@Service
@AllArgsConstructor
public class WbsTreeServiceImpl extends BaseServiceImpl<WbsTreeMapper, WbsTree> implements IWbsTreeService {

    private final BladeLogger logger;
    private final WbsTreeMapper wbsTreeMapper;
    private final ConstructionLedgerMapper constructionLedgerMapper;
    private final IWbsFormElementService wbsFormElementService;
    private final WbsInfoMapper wbsInfoMapper;
    private final WbsTreeContractMapper wbsTreeContractMapper;
    private final WbsTreePrivateMapper wbsTreePrivateMapper;
    private final WbsTreePrivateServiceImpl wbsTreePrivateService;
    private final ProjectInfoMapper projectInfoMapper;


    @Override
    public IPage<WbsTreeVO> selectWbsTreePage(IPage<WbsTreeVO> page, WbsTreeVO wbsTree) {
        return page.setRecords(baseMapper.selectWbsTreePage(page, wbsTree));
    }

    @Override
    public List<WbsTreeVO> lazyTree(String wbsId, String tenantId, Long parentId) {
        if (AuthUtil.isAdministrator()) {
            tenantId = StringPool.EMPTY;
        }
        return ForestNodeMerger.merge(baseMapper.lazyTree(wbsId, tenantId, parentId));
    }

    @Override
    public List<WbsTreeVO> tree(String wbsId, String tenantId, String type) {
        return ForestNodeMerger.merge(baseMapper.tree(wbsId, tenantId, type));
    }

    @Override
    public boolean submit(WbsTree dept) {
        if (Func.isEmpty(dept.getParentId())) {
            dept.setTenantId(AuthUtil.getTenantId());
            dept.setParentId(BladeConstant.TOP_PARENT_ID);
            dept.setAncestors(String.valueOf(BladeConstant.TOP_PARENT_ID));
        }
        if (dept.getParentId() > 0) {
            WbsTree parent = getById(dept.getParentId());
            if (Func.toLong(dept.getParentId()) == Func.toLong(dept.getId())) {
                throw new ServiceException("父节点不可选择自身!");
            }
            dept.setTenantId(parent.getTenantId());
            String ancestors = parent.getAncestors() + StringPool.COMMA + dept.getParentId();
            dept.setAncestors(ancestors);
        }
        dept.setStatus(1);
        dept.setIsDeleted(BladeConstant.DB_NOT_DELETED);
        return saveOrUpdate(dept);
    }

    private boolean submit2(FormElementDTO dept) {
        if (Func.isEmpty(dept.getParentId())) {
            dept.setTenantId(AuthUtil.getTenantId());
            dept.setParentId(BladeConstant.TOP_PARENT_ID);
            dept.setAncestors(String.valueOf(BladeConstant.TOP_PARENT_ID));
        }
        if (dept.getParentId() > 0) {
            WbsTree parent = getById(dept.getParentId());
            if (Func.toLong(dept.getParentId()) == Func.toLong(dept.getId())) {
                throw new ServiceException("父节点不可选择自身!");
            }
            dept.setTenantId(parent.getTenantId());
            String ancestors = parent.getAncestors() + StringPool.COMMA + dept.getParentId();
            dept.setAncestors(ancestors);
        }
        //设置类型默认值为 '2' 表单
        dept.setType(2);

        dept.setIsDeleted(BladeConstant.DB_NOT_DELETED);

        return saveOrUpdate(dept);
    }

    @Override
    public List<WbsNodeTableVO> selectByNodeTable(String id) {
        //查询节点下的所有表单
        List<WbsNodeTableVO> wbsNodeTableVOS = wbsTreeMapper.selectByNodeTable(id);
        return wbsNodeTableVOS;
    }

    @Override
    public boolean removeTableById(String id) {
        Integer integer = wbsTreeMapper.removeTableById(id);
        if (integer > 0) {
            return true;
        }
        return false;
    }

    @Override
    public List<WbsFormElement> selectFormElements(String id) {
        List<WbsFormElement> wbsFormElements = wbsTreeMapper.selectFormElements(id);
        return wbsFormElements;
    }


    private String selectTableIdByTableName(String deptName) {
        QueryWrapper<WbsTree> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("dept_name", deptName);
        WbsTree wbsTree = wbsTreeMapper.selectOne(queryWrapper);
        if (!("").equals(wbsTree) && wbsTree == null) {
            return "-1";
        }
        return String.valueOf(wbsTree.getId());
    }


    @Override
    public Boolean importWbsTree(MultipartFile excelFile, WbsTree wbsTreeFu, WbsTree wbsTree1) throws IOException {
        //赋值
        wbsTreeFu.setAncestors("0");
        wbsTree1.setProjectNodeId(wbsTree1.getId());
        //获取文件路径
        File file = WbsExcelUtil.convert(excelFile);
        String canonicalPath = file.getCanonicalPath();
        //解析excel
        WbsExcelUtil excelUtil = new WbsExcelUtil();
        ArrayList<Map<String, String>> result = excelUtil.readExcelToObj(canonicalPath);
        for (Map<String, String> map : result) {
            map.forEach((nodeType, nodeName) -> {
                WbsTree wbsTreeZi = new WbsTree();
                if (StringUtils.isNotEmpty(nodeName)) {
                    //初始化默认值
                    wbsTreeZi.setTenantId(AuthUtil.getTenantId());
                    wbsTreeZi.setDeptName(nodeName);
                    wbsTreeZi.setDeptCategory(Integer.valueOf(nodeType));
                    wbsTreeZi.setWbsId(wbsTreeFu.getWbsId());
                    wbsTreeZi.setParentId(wbsTreeFu.getParentId());
                    wbsTreeZi.setAncestors(wbsTreeFu.getAncestors());
                    wbsTreeZi.setProjectNodeId(wbsTree1.getProjectNodeId());
                    //新增节点返回未创建成功查询出来的wbsTree对象、创建成功后的wbsTreeZi对象
                    WbsTree wbsTree = importTree(wbsTreeZi);
                    //后置初始化默认值
                    if (wbsTree == null) {
                        Long id = wbsTreeZi.getId();
                        //设置ancestors祖级id集合
                        StringBuilder stringBuffer = new StringBuilder();
                        StringBuilder appendStr = stringBuffer.append(",").append(wbsTreeZi.getParentId());
                        String ancestors = wbsTreeZi.getAncestors() + appendStr;
                        //修改ancestors的值
                        updateDate(ancestors, id);
                        wbsTreeFu.setParentId(id);
                        wbsTreeFu.setAncestors(ancestors);
                    } else {
                        wbsTreeFu.setParentId(wbsTree.getId());
                        wbsTreeFu.setAncestors(wbsTree.getAncestors());
                    }
                }
            });
        }
        //修改根节点ProjectNodeId
        int row = baseMapper.updateById(wbsTree1);
        if (row > 0) {
            return true;
        }
        return false;
    }

    private WbsTree importTree(WbsTree wbsTreeZi) {
        //查重
        QueryWrapper<WbsTree> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("wbs_id", wbsTreeZi.getWbsId());
        queryWrapper.eq("dept_name", wbsTreeZi.getDeptName());
        queryWrapper.eq("dept_category", wbsTreeZi.getDeptCategory());
        queryWrapper.eq("project_node_id", wbsTreeZi.getProjectNodeId());
        WbsTree wbsTrees = baseMapper.selectOne(queryWrapper);
        if (wbsTrees == null) {
            //初始化默认值
            wbsTreeZi.setStatus(1);
            wbsTreeZi.setType(1);
            wbsTreeZi.setMajorDataType(1);
            if (wbsTreeZi.getDeptCategory() == 6) {
                wbsTreeZi.setIsConcrete(0);
                wbsTreeZi.setIsExpernode(0);
            }
            baseMapper.insert(wbsTreeZi);
        }
        //TODO 暂时未想到好的处理方法来判断重复条新增问题
        return wbsTrees;
    }

    private boolean updateDate(String ancestors, Long id) {
        Integer row = baseMapper.updateById2(ancestors, id);
        if (row > 0) {
            return true;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String submitWbsTreeInProject(WbsTreeContractDTO pawDTO) {
        String wbsTreeIds = pawDTO.getWbsTreeIds();
        if (StringUtils.isEmpty(wbsTreeIds)) {
            return "1";
        }
        String[] ids = wbsTreeIds.split(",");
        List<String> idList1 = Arrays.asList(ids);
        List<String> idList2 = new ArrayList<>();
        //查询出当前私有库下所有的wbs节点
        QueryWrapper<WbsTreePrivate> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("wbs_id", pawDTO.getWbsId());
        queryWrapper.eq("project_id", pawDTO.getProjectId());
        queryWrapper.eq("type", 1);
        List<WbsTreePrivate> wbsTreePrivates = wbsTreePrivateMapper.selectList(queryWrapper);
        for (WbsTreePrivate wbsTreePrivate : wbsTreePrivates) {
            idList2.add(String.valueOf(wbsTreePrivate.getId()));
        }
        List<String> diffrent = WbsTreeContractServiceImpl.getDiffrent(idList1, idList2);
        diffrent.forEach(System.out::print);
        if (diffrent.size() == 0) {
            List<String> tableId1 = new ArrayList<>();
            List<String> tableId2 = new ArrayList<>();
            //查找wbs总树节点下是否新增了元素表，进行同步更新到wbs私有树中
            List<WbsTree> allNodeList = findAllNodeList(wbsTreeIds);
            List<WbsTree> wbsTreeListAll = new ArrayList<>();
            for (WbsTree wbsTree : allNodeList) {
                System.out.println("wbsTree.getId" + wbsTree.getId());
                QueryWrapper<WbsTree> queryWrapper1 = new QueryWrapper<>();
                queryWrapper1.eq("wbs_id", pawDTO.getWbsId());
                queryWrapper1.eq("type", 2);
                queryWrapper1.eq("parent_id", wbsTree.getId());
                List<WbsTree> wbsTreeList = wbsTreeMapper.selectList(queryWrapper1);
                wbsTreeListAll.addAll(wbsTreeList);
            }
            for (WbsTree wbsTree : wbsTreeListAll) {
                tableId1.add(String.valueOf(wbsTree.getId()));
            }
            //获取项目私有树下所有的元素表
            QueryWrapper<WbsTreePrivate> queryWrapper3 = new QueryWrapper<>();
            queryWrapper3.eq("wbs_id", pawDTO.getWbsId());
            queryWrapper3.eq("project_id", pawDTO.getProjectId());
            queryWrapper3.eq("type", 2);
            List<WbsTreePrivate> wbsTreePrivates1 = wbsTreePrivateMapper.selectList(queryWrapper3);
            for (WbsTreePrivate wbsTreePrivate : wbsTreePrivates1) {
                tableId2.add(String.valueOf(wbsTreePrivate.getId()));
            }
            List<String> diffrent1 = WbsTreeContractServiceImpl.getDiffrent(tableId1, tableId2);
            if (diffrent1.size() == 0) {
                return "2";
            } else {
                if (tableId1.size() > tableId2.size()) {
                    //新增同步元素表
                    for (String tableId : diffrent1) {
                        WbsTree wbsTree = wbsTreeMapper.selectById(tableId);
                        wbsTreePrivateMapper.insertCombination1(wbsTree, pawDTO.getProjectId());
                    }
                    return "3";
                }
                //暂未说明是否要同步删除私有库元素表
            }
        } else {
            if (idList1.size() > idList2.size()) {
                for (String id : diffrent) {
                    //项目私有wbs节点库存在该节点且为删除状态,那么修改is_deleted=0,否则新增
                    WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.selectByCondition2(id, pawDTO.getProjectId(), pawDTO.getWbsId());
                    if (wbsTreePrivate != null) {
                        //修改该节点
                        wbsTreePrivateMapper.updateByCondition(id, pawDTO.getProjectId(), pawDTO.getWbsId());
                        //修改该节点下元素表
                        wbsTreePrivateMapper.updateTableByCondition(id, pawDTO.getProjectId(), pawDTO.getWbsId());
                    } else {
                        //此处引用WBS公共库节点
                        WbsTree wbsTree = wbsTreeMapper.selectById(id);
                        if (wbsTree != null) {
                            Integer row = wbsTreePrivateMapper.insertCombination1(wbsTree, pawDTO.getProjectId());
                            //根据wbsTreeId就是子级的parentId判断该节点是否存在元素表type=2的节点,查询该节点下是否有元素表
                            Long tableParentId = wbsTree.getId();
                            List<WbsTree> wbsTreeTableList = wbsTreeMapper.selectIsTable(tableParentId);
                            wbsTreeTableList.forEach(System.out::print);
                            if (wbsTreeTableList.size() > 0) {
                                //新增元素表
                                for (WbsTree tree : wbsTreeTableList) {
                                    wbsTreePrivateMapper.insertCombination1(tree, pawDTO.getProjectId());
                                }
                            }
                            //初始化合同段wbs私有树
                            Integer row2 = wbsTreeContractMapper.insertWbsTreeContract2(wbsTree, pawDTO.getProjectId(), pawDTO.getContractId());
                            if (row > 0 && row2 > 0) {
                                logger.info(wbsTree.getId().toString(), "项目wbs私有树操作成功");
                            }
                            //保存引用模板id
                            projectInfoMapper.updateTemplateIdById(pawDTO.getProjectId(), pawDTO.getWbsId());
                            pawDTO.setTemplateProjectId(pawDTO.getWbsId());
                        }
                        //引用其他项目WBS私有库节点
                        WbsTreePrivate wbsTreePrivate1 = wbsTreePrivateMapper.selectByCondition(id, pawDTO.getTemplateProjectId());
                        if (wbsTreePrivate1 != null) {
                            Integer row = wbsTreePrivateMapper.insertCombination2(wbsTreePrivate1, pawDTO.getProjectId());
                            //根据wbsTreePrivate1Id就是子级的parentId判断该节点是否存在元素表type=2的节点,查询该节点下是否有元素表
                            Long tableParentId = wbsTreePrivate1.getId();
                            List<WbsTree> wbsTreeTableList = wbsTreePrivateMapper.selectIsTable(tableParentId);
                            if (wbsTreeTableList.size() > 0) {
                                for (WbsTree tree : wbsTreeTableList) {
                                    wbsTreePrivateMapper.insertCombination1(tree, pawDTO.getProjectId());
                                }
                            }
                            //初始化合同段wbs私有树
                            Integer row2 = wbsTreeContractMapper.insertWbsTreeContract1(pawDTO.getProjectId(), wbsTreePrivate1);
                            if (row > 0 && row2 > 0) {
                                logger.info(wbsTreePrivate1.getId().toString(), "项目wbs私有树操作成功");
                            }
                            //保存引用模板id
                            projectInfoMapper.updateTemplateIdById(pawDTO.getProjectId(), pawDTO.getTemplateProjectId());
                            pawDTO.setTemplateProjectId(pawDTO.getTemplateProjectId());
                        }
                    }
                }
            } else {
                for (String id : diffrent) {
                    //逻辑删除当前节点
                    wbsTreePrivateMapper.deleteByCondition(id, pawDTO.getWbsId(), pawDTO.getProjectId());
                    //逻辑删除当前节点下元素表 id = parentId
                    wbsTreePrivateMapper.deleteByCondition2(id, pawDTO.getWbsId(), pawDTO.getProjectId());
                }
            }
        }
        return "4";
    }

    public List<WbsTree> findAllNodeList(String wbsTreeIds) {
        String[] ids = wbsTreeIds.split(",");
        List<Long> idList = new ArrayList<>();
        for (String id : ids) {
            idList.add(Long.valueOf(id));
        }
        return baseMapper.selectBatchIds(idList);
    }

    @Override
    public WbsTreeAllListVO findWbsTreeList(Integer type) {
        WbsTreeAllListVO wbsTreeAllListVO = new WbsTreeAllListVO();
        //查询Wbs总树
        List<WbsInfo> wbsInfos = wbsInfoMapper.selectAll(type);
        wbsTreeAllListVO.setWbsInfos(wbsInfos);
        //查询项目私有树 TODO 默认type=1质检查询wbs总树+项目私有树 如果=2实验不需要wbs私有树可以加判断不查询
        List<WbsTreePrivate> wbsTreePrivates = wbsTreePrivateMapper.selectAll();
        wbsTreeAllListVO.setWbsTreePrivates(wbsTreePrivates);
        //查询合同段私有树 TODO 暂时未说明是否要引用合同段私有树（已确认暂时不引用合同树）
        /*List<WbsTreeContractVO> wbsTreeContractDTOS = wbsTreeContractMapper.selectAll();
        wbsTreeAllListVO.setWbsTreeContracts(wbsTreeContractDTOS);*/
        return wbsTreeAllListVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveFormElement(FormElementDTO formElementDTO) {
        if (formElementDTO.getElementList().size() <= 0) {
            return R.fail("操作失败,请先添加表单元素");
        }
        String filedName = "";
        String filedType = "";
        String filedLength = "";
        for (WbsFormElement wbsFormElement : formElementDTO.getElementList()) {
            filedName = wbsFormElement.getEName();
            filedType = String.valueOf(wbsFormElement.getEType());
            filedLength = String.valueOf(wbsFormElement.getELength());
        }
        if (StringUtils.isEmpty(filedName) || StringUtils.isEmpty(filedType) || StringUtils.isEmpty(filedLength)) {
            return R.fail("操作失败,请完整填写元素参数");
        }
        //初始化表名
        String newTableName = "m_wbs_form_" + DateUtil.time() + "_" + formElementDTO.getDeptName();
        formElementDTO.setInitTableName(newTableName);
        //创建表单
        boolean b1 = submit2(formElementDTO);
        //判重
        String tableId = selectTableIdByTableName(formElementDTO.getDeptName());
        if (("-1").equals(tableId)) {
            return R.fail("表单名已经存在,请重新填写表单名");
        }
        //赋值
        List<WbsFormElement> elementList = formElementDTO.getElementList();
        for (WbsFormElement wbsFormElement : elementList) {
            wbsFormElement.setFId(tableId);
        }
        //新增元素
        boolean b2 = wbsFormElementService.saveBatch(elementList);
        //通过fId查找当前表下的所有元素
        List<WbsFormElement> list = wbsFormElementService.selectElementListByFid(tableId);
        //初始化实体表单
        Boolean b3 = wbsFormElementService.initTable(list, newTableName);
        if (b1 && b2 && b3) {
            return R.data(formElementDTO, "新增表单,元素,初始化实体表成功");
        } else {
            throw new RuntimeException("操作失败");
        }
        //TODO 初始化元素（动态更新元素-就是当用户编辑新增元素时，实体表也要同步新增一个字段，编辑、删除一样需要同步，需要在写3个接口）
    }


}
