/*
 *      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.business.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.*;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;

import org.apache.commons.lang.StringUtils;
import org.springblade.business.feignClient.ClientTreePublicCodeClientImpl;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.manager.entity.WbsTreeContract;
import org.springblade.manager.feign.WbsTreeContractClient;
import org.springblade.manager.vo.WbsTreeContractTreeVOS;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestParam;
import org.springblade.business.entity.TreeContractFirst;
import org.springblade.business.service.ITreeContractFirstService;
import org.springblade.core.boot.ctrl.BladeController;

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

/**
 * 合同段划分树首件关联表 控制器
 *
 * @author BladeX
 * @since 2022-06-16
 */
@RestController
@AllArgsConstructor
@RequestMapping("/treeContractFirst")
@Api(value = "合同段划分树首件关联表", tags = "合同段划分树首件关联表接口")
public class TreeContractFirstController extends BladeController {

	private final ITreeContractFirstService treeContractFirstService;

	private final WbsTreeContractClient wbsTreeContractClient;

	private final ClientTreePublicCodeClientImpl clientTreePublicCodeClient;

	/**
	 * 获取合同段划分树中被标记为首件的节点
	 * @param parentId 父节点，为空则查询第一级节点
	 * @param contractId 合同段ID
	 * @return 结果
	 */
	@GetMapping("/queryContractWbsTreeFirstByContractIdAndType")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "获取合同段划分树中被标记为首件的节点")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "parentId", value = "父节点，为空则查询第一级节点"),
			@ApiImplicitParam(name = "contractId", value = "合同段ID", required = true)
	})
	public R<List<WbsTreeContractTreeVOS>> queryContractWbsTreeFirstByContractIdAndType(@RequestParam String parentId, @RequestParam String contractId){
		List<WbsTreeContractTreeVOS> rootTreeNode;

		if(StringUtils.isEmpty(parentId)){
			//为空，说明初始化
			//获取根节点
			rootTreeNode = this.clientTreePublicCodeClient.queryContractWbsTreeByContractIdAndType(contractId, 1, "0");
		} else {
			//不为空，获取其下子节点
			rootTreeNode = this.wbsTreeContractClient.queryContractWbsTreeByContractIdAndType(contractId, 1, parentId);
		}

		//判断这些节点哪些是标记为首件的
		Iterator<WbsTreeContractTreeVOS> iterator = rootTreeNode.iterator();
		while (iterator.hasNext()){
			WbsTreeContractTreeVOS vos = iterator.next();

			if(vos.getChildren() != null && vos.getChildren().size() != 0){
				Iterator<WbsTreeContractTreeVOS> iterators = vos.getChildren().iterator();
				while (iterators.hasNext()){
					WbsTreeContractTreeVOS vo = iterators.next();
					TreeContractFirst first = this.treeContractFirstService.getOne(Wrappers.<TreeContractFirst>lambdaQuery().eq(TreeContractFirst::getWbsNodeId, vo.getPrimaryKeyId()).eq(TreeContractFirst::getIsDeleted, 0));
					if(first == null){
						//如果当前节点没被标记为首件则不显示当前节点
						iterators.remove();
					}
				}
			}

			if("0".equals(vos.getParentId())){
				//根节点不删除
				continue;
			}

			TreeContractFirst first = this.treeContractFirstService.getOne(Wrappers.<TreeContractFirst>lambdaQuery().eq(TreeContractFirst::getWbsNodeId, vos.getPrimaryKeyId()).eq(TreeContractFirst::getIsDeleted, 0));
			if(first == null){
				//如果当前节点没被标记为首件则不显示当前节点
				iterator.remove();
			}
		}

		return R.data(rootTreeNode);
	}

	/**
	 * 新增或删除 合同段划分树首件关联表
	 */
	@PostMapping("/saveOrDelete")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "新增或删除 合同段划分树首件关联")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "primaryKeyId", value = "标记为首件的节点primaryKeyId或pKeyId", required = true),
			@ApiImplicitParam(name = "saveOrDeleted", value = "新增为0，删除为1", required = true)
	})
	public R<List<String>> saveOrDelete(@RequestParam String primaryKeyId, @RequestParam Integer saveOrDeleted) {
		//获取当前操作用户
		BladeUser user = AuthUtil.getUser();
		//获取当前节点的信息
		WbsTreeContract nodeData = this.wbsTreeContractClient.getContractWbsTreeByPrimaryKeyId(Long.valueOf(primaryKeyId));
		if(nodeData == null){
			return R.data(-1, null, "未找到当前节点");
		}
		//获取当前节点的所有父节点和子节点
		StringBuilder parentIds = new StringBuilder(), childIds = new StringBuilder();
		//获取父节点
		this.currentNodeAllParent(parentIds, nodeData);
		//获取子节点
		this.currentNodeAllChild(childIds, nodeData);

		//判断是新增还是删除
		if(new Integer("0").equals(saveOrDeleted)){
			//检查当前请求的节点是否已经被关联
			TreeContractFirst firstData = this.treeContractFirstService.getOne(Wrappers.<TreeContractFirst>lambdaQuery().eq(TreeContractFirst::getIsDeleted, 0).eq(TreeContractFirst::getWbsNodeId, primaryKeyId));
			if(firstData != null){
				return R.data(JSONArray.parseArray(JSONObject.toJSONString(primaryKeyId), String.class));
			}

			//新增集合
			List<TreeContractFirst> save = new ArrayList<>();
			//新增当前节点
			save.add(new TreeContractFirst(Long.parseLong(nodeData.getProjectId()), Long.parseLong(nodeData.getContractId()), nodeData.getPKeyId(), user.getUserId(), user.getDeptId()));
			//新增当前节点下的子节点
			if(StringUtils.isNotEmpty(childIds.toString()) && !",".equals(childIds.toString())){
				String[] childArray = childIds.toString().split(",");
				for(String child : childArray){
					if(StringUtils.isNotEmpty(child)){
						save.add(new TreeContractFirst(Long.parseLong(nodeData.getProjectId()), Long.parseLong(nodeData.getContractId()), Long.parseLong(child), user.getUserId(), user.getDeptId()));
					}
				}
			}
			//新增父节点
			if(StringUtils.isNotEmpty(parentIds.toString()) && !",".equals(parentIds.toString())){
				//新增父节点需要判断当前父节点是否已经被标记为首件
				String[] parentIdArray = parentIds.toString().split(",");
				for(String parentId : parentIdArray){
					if(StringUtils.isNotEmpty(parentId)){
						//判断是否被标记为首件
						TreeContractFirst old = this.treeContractFirstService.getOne(Wrappers.<TreeContractFirst>lambdaQuery().eq(TreeContractFirst::getWbsNodeId, parentId).eq(TreeContractFirst::getIsDeleted, 0));
						if(old == null){
							//说明没有被标记，新增
							save.add(new TreeContractFirst(Long.parseLong(nodeData.getProjectId()), Long.parseLong(nodeData.getContractId()), Long.parseLong(parentId), user.getUserId(), user.getDeptId()));
						}
					}
				}
			}
			//最后操作落库
			this.treeContractFirstService.saveBatch(save);
			//返回当前操作的节点
			parentIds.append(",").append(primaryKeyId).append(childIds);
			List<String> result = JSONArray.parseArray(JSONObject.toJSONString(parentIds.toString().split(",")), String.class);
			//删掉为空的数据
			result.removeIf(StringUtils::isEmpty);
			return R.data(result);
		} else {
			//删除自身
			this.treeContractFirstService.update(Wrappers.<TreeContractFirst>lambdaUpdate().set(TreeContractFirst::getIsDeleted, 1).eq(TreeContractFirst::getWbsNodeId, primaryKeyId));
			//删除子节点
			if(StringUtils.isNotEmpty(childIds.toString()) && !",".equals(childIds.toString())){
				//存在子节点，均更改为删除状态
				this.treeContractFirstService.update(Wrappers.<TreeContractFirst>lambdaUpdate().set(TreeContractFirst::getIsDeleted, 1).in(TreeContractFirst::getWbsNodeId, Func.toLongList(childIds.toString())));
			}
			//删除父节点
			StringBuilder parentResult = new StringBuilder();
			if(StringUtils.isNotEmpty(parentIds.toString()) && !",".equals(parentIds.toString())){
				//删除父节点情况相对复杂，需要判断对应节点下的是否还存在子节点处于首件状态，如果存在那么当前父节点就不能被删除掉
				String[] parentIdArray = parentIds.toString().split(",");
				for(String parentId : parentIdArray){
					if(StringUtils.isNotEmpty(parentId)){
						//首先获取当前父节点的下一级子节点
						WbsTreeContract parentNode = this.wbsTreeContractClient.getContractNodeByPrimaryKeyId(parentId);
						List<WbsTreeContractTreeVOS> oneChild = this.wbsTreeContractClient.queryContractWbsTreeByContractIdAndType(nodeData.getContractId(), nodeData.getWbsType(), String.valueOf(parentNode.getId()));
						//获取唯一键
						List<String> ids = oneChild.stream().map(WbsTreeContractTreeVOS::getPrimaryKeyId).distinct().collect(Collectors.toList());
						//判断是否存在首件标记
						List<TreeContractFirst> result = this.treeContractFirstService.list(Wrappers.<TreeContractFirst>lambdaQuery().in(TreeContractFirst::getWbsNodeId, ids).eq(TreeContractFirst::getIsDeleted, 0));
						if(result != null && result.size() != 0){
							//result不为空且有数据，说明当前节点下的子节点仍存在除了 nodeData 外的节点处于首件标记，那么当前节点及其更上级节点都不能被取消首件标记，故直接中断循环
							break;
						} else {
							//反之，说明当前节点下的子节点已经不存在处理首件标记的有效记录，则当前节点可以被取消首件标记
							this.treeContractFirstService.update(Wrappers.<TreeContractFirst>lambdaUpdate().set(TreeContractFirst::getIsDeleted, 1).eq(TreeContractFirst::getWbsNodeId, parentId));
							parentResult.append(",").append(parentId);
							//之后对当前节点的上一级做相同判断
						}
					}
				}
			}
			parentResult.append(",").append(primaryKeyId).append(childIds);
			List<String> result = JSONArray.parseArray(JSONObject.toJSONString(parentResult.toString().split(",")), String.class);
			//删掉为空的数据
			result.removeIf(StringUtils::isEmpty);

			return R.data(result);
		}
	}

	/**
	 * 获取所有父节点
	 */
	private void currentNodeAllParent(StringBuilder parentIds, WbsTreeContract currentNode){
		if(!"0".equals(String.valueOf(currentNode.getParentId()))){
			//如果父节点不是0说明没到顶层
			WbsTreeContract parentNode = this.wbsTreeContractClient.queryCurrentNodeAllParent(Long.parseLong(currentNode.getContractId()), currentNode.getParentId());
			if(parentNode != null){
				parentIds.append(",").append(parentNode.getPKeyId());
				this.currentNodeAllParent(parentIds, parentNode);
			}
		}
	}

	/**
	 * 获取所有子节点
	 */
	private void currentNodeAllChild(StringBuilder childIds, WbsTreeContract currentNode){
		//获取所有子节点
		List<WbsTreeContract> childList = this.wbsTreeContractClient.queryCurrentNodeAllChild(Long.parseLong(currentNode.getContractId()), currentNode.getId());
		if(childList != null && childList.size() != 0){
			//首先找到当前节点下的第一级子节点
			Map<String,StringBuilder> idMap = new HashMap<>();
			Map<String, WbsTreeContract> treeMap = new HashMap<>();
			//一级子节点的primaryKeyId
			StringBuilder oneChild = new StringBuilder();
			childList.forEach(node -> {
				treeMap.put(node.getPKeyId().toString(), node);
				if(currentNode.getId().equals(node.getParentId())){
					oneChild.append(",").append(node.getPKeyId());
				}
			});
			idMap.put(currentNode.getPKeyId().toString(), oneChild);

			String[] childArray =  oneChild.toString().split(",");
			for(String childPKeyId : childArray){
				//继续向下查询正确的子节点
				this.foreachQueryChild(childPKeyId, idMap, treeMap, childList);
			}

			//执行 foreachQueryChild 后idMap中就是所有正确子节点的排布，将其全部拼接进 childIds 中
			Set<String> primaryKeys = idMap.keySet();
			for(String key : primaryKeys){
				childIds.append(",").append(idMap.get(key));
			}
		}
	}

	private void foreachQueryChild(String primaryKeyId, Map<String,StringBuilder> idMap, Map<String, WbsTreeContract> treeMap, List<WbsTreeContract> childList){
		if(childList.size() > 0){
			//获取当前节点
			WbsTreeContract node = treeMap.get(primaryKeyId);
			if(node != null){
				//一级子节点的primaryKeyId
				StringBuilder oneChild = new StringBuilder();

				childList.forEach(child -> {
					if(node.getId().equals(child.getParentId())){
						oneChild.append(",").append(child.getPKeyId());

						//工序为6，不会再存在下级节点
						if(!new Integer("6").equals(child.getDeptCategory())){
							//其子节点继续向下
							this.foreachQueryChild(child.getPKeyId().toString(), idMap, treeMap, childList);
						}
					}
				});

				idMap.put(node.getPKeyId().toString(), oneChild);
			}
		}
	}

}
