package org.springblade.flow.visual.onlinedev.common.relation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springblade.bi.client.model.CubeDataModel;
import org.springblade.cube.dto.CubeTableName;
import org.springblade.cube.dto.TableLinkJoin;
import org.springblade.cube.dto.TableLinkJoin.JoinKey;
import org.springblade.flow.util.JsonUtil;

import com.alibaba.fastjson2.JSON;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 表单选择的数据库表和关联关系操作工具类
 * 
 * @author william
 * @date 2022年9月2日 上午11:05:57
 */
@Slf4j
public class RelationUtil {
	public final static String ROOT_TABLE_PARENT = "root";

	public static void main(String[] args) {
		String tablesFile = "C://Users/wenli/Downloads/测试用的json/tables.json";
//		String linksJoinFile = "C://Users/wenli/Downloads/测试用的json/join.json";
		String cubeDataFile = "C://Users/wenli/Downloads/测试用的json/cubeData.json";
		String tables = FileUtil.readUtf8String(tablesFile);
//		String linksJoin = FileUtil.readUtf8String(linksJoinFile);
		String cubeDataJson = FileUtil.readUtf8String(cubeDataFile);

		CubeDataModel cubeData = JSON.parseObject(cubeDataJson.getBytes(), CubeDataModel.class);

		List<RelationBean> list = rebuild(tables, cubeData);
		List<RelationBean> tree = rebuildTreeRalation(list);

		log.info(JSON.toJSONString(tree));
	}

	/**
	 * 将数据转换为树型结构
	 *
	 * @param sources sources
	 * 
	 * @return {@link RelationBean}
	 */
	public static List<RelationBean> rebuildTreeRalation(List<RelationBean> sources) {
		if (CollUtil.isEmpty(sources)) {
			return Collections.emptyList();
		}

		Map<String, List<RelationBean>> zoneByParentIdMap = sources.stream()
				.collect(Collectors.groupingBy(RelationBean::getRelationTable));
		sources.forEach(zone -> zone.setChildren(zoneByParentIdMap.get(zone.getTable())));
		return sources.stream().filter(v -> v.getRelationTable().equals(ROOT_TABLE_PARENT))
				.collect(Collectors.toList());
	}

	/**
	 * 在线表单创建或者更新时，需要根据数据集重新组装数据
	 * 
	 * @param tables 前端提交的表单字段关联表字段的原始数据
	 * @param cubeData 数据集信息
	 * 
	 * @return {@link RelationBean}
	 */
	public static List<RelationBean> rebuild(String tables, CubeDataModel cubeData) {
		List<RelationField> dataList = JSON.parseArray(tables, RelationField.class);
		if (CollUtil.isNotEmpty(dataList)) {
			List<TableLinkJoin> joinList = JsonUtil.getJsonToList(cubeData.getLinksJoin(), TableLinkJoin.class);
			HashMap<String, RelationBean> map = new HashMap<>();
			List<CubeTableName> cubeTableNames = JsonUtil.getJsonToList(cubeData.getCubeTableNames(),
					CubeTableName.class);
			cubeTableNames.forEach(cubeTable -> {
				RelationBean relation = new RelationBean();
				relation.setTable(cubeTable.getTableName());
				relation.setRelationTable(ROOT_TABLE_PARENT);
				relation.setTableName(cubeTable.getTableAliasName());

				List<RelationField> fieldList = new ArrayList<>();
				dataList.forEach(item -> {
					if (relation.getTable().equalsIgnoreCase(item.getTableName())) {
						fieldList.add(item);
					}
				});
				relation.setFields(fieldList);

				if (CollUtil.isNotEmpty(joinList)) {
					joinList.forEach(join -> {
						String target = join.getTarget();
						if (target.equalsIgnoreCase(cubeTable.getTableName())) {
							relation.setRelationTable(join.getSource());
							List<RelationKey> keys = new ArrayList<>();
							List<JoinKey> joinKeys = join.getJoinKeys();
							if (CollUtil.isNotEmpty(joinKeys)) {
								for (JoinKey key : joinKeys) {
									if (key.isTargetKeyVtState() || key.isSourceKeyVtState()) {
										// 虚拟字段，忽略
									} else {
										RelationKey relationKey = new RelationKey();
										relationKey.setSourceKey(key.getSourceKey());
										relationKey.setTargetKey(key.getTargetKey());
										keys.add(relationKey);
									}
								}
							}
							relation.setKeys(keys);
							relation.setJoinType(join.getJoinType().name());
						}
					});
				}

				map.put(cubeTable.getTableName(), relation);
			});

			List<RelationBean> relationList = new ArrayList<>();
			map.forEach((key, value) -> {
				relationList.add(value);
			});

//			log.info("rebuild relationList is " + JSON.toJSONString(relationList, true));
			return relationList;
		} else {
			log.info("rebuild dataList is null");
		}
		return null;
	}

	/**
	 * 根据字段和表名找对应的RelationField对象
	 * 
	 * @param parentField
	 * @param parentTable
	 * @param fieldList
	 * @return
	 */
	public static RelationField getRelationFieldByFieldAndTable(String parentField, String parentTable,
			List<RelationField> fieldList) {
		for (RelationField rf : fieldList) {
			if (rf.getField().equalsIgnoreCase(parentField) && rf.getTableName().equalsIgnoreCase(parentTable)) {
				return rf;
			}
		}

		return null;
	}

	/**
	 * 根据子表字段和表名查找关联的父表字段信息
	 * 
	 * @param childTable
	 * @param childField
	 * @param joinList
	 * @param fieldList
	 * @return
	 */
	public static RelationField getParentRelationField(String childTable, String childField,
			List<TableLinkJoin> joinList, List<RelationField> fieldList) {
		if (CollUtil.isEmpty(joinList)) {
			return null;
		}
		for (TableLinkJoin join : joinList) {
			String target = join.getTarget();
			if (childTable.equalsIgnoreCase(target)) {
				// 找到关联表
				List<JoinKey> keyList = join.getJoinKeys();
				for (JoinKey key : keyList) {
					if (key.getTargetKey().equalsIgnoreCase(childField)) {
						// 找到父表关联字段
						RelationField field = getRelationFieldByFieldAndTable(key.getSourceKey(), join.getSource(),
								fieldList);
						return field;
					}
				}
			}
		}

		return null;
	}

	/**
	 * 判断某个数据集是否有关联表
	 * 
	 * @param cubeData
	 * @return
	 */
	public static boolean hasLinkTable(CubeDataModel cubeData) {
		String linkJson = cubeData.getLinksJoin();
		List<TableLinkJoin> joinList = JsonUtil.getJsonToList(linkJson, TableLinkJoin.class);
		return CollUtil.isNotEmpty(joinList);
	}

	public static RelationField findByColumnName(String columnName, List<RelationField> fieldList) {
		for (RelationField rf : fieldList) {
			if (columnName.equalsIgnoreCase(rf.getField())) {
				return rf;
			}
		}
		return null;
	}
}
