package com.tykj.workflowcore.model_layer.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tykj.workflowcore.base.result.ApiException;
import com.tykj.workflowcore.model_layer.dao.AggregationDao;
import com.tykj.workflowcore.model_layer.dao.ColumnInfoDao;
import com.tykj.workflowcore.model_layer.dao.TableInfoDao;
import com.tykj.workflowcore.model_layer.dao.TableInfoExDao;
import com.tykj.workflowcore.model_layer.entity.Aggregation;
import com.tykj.workflowcore.model_layer.entity.ColumnInfo;
import com.tykj.workflowcore.model_layer.entity.TableInfo;
import com.tykj.workflowcore.model_layer.entity.TableInfoEx;
import com.tykj.workflowcore.model_layer.entity.vo.ColumnEXVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

import static java.lang.String.format;

/**
 * @author C
 */
@Service
public class ModelHelper {

    @Autowired
    private TableInfoDao tableInfoDao;
    @Autowired
    private ColumnInfoDao columnInfoDao;
    @Autowired
    private TableInfoExDao tableInfoExDao;
    @Autowired
    private AggregationDao aggregationDao;

    /**
     * 获取指定数据模型的json格式数据示例
     *
     * @param tableInfoId 指定id
     * @return json格式的数据示例
     */
    public String getJsonExpample(Integer tableInfoId) {
        /* 你要放10个元素，10/0.75+1=14 */
        Map<String, Object> result = new HashMap<>();
        //根据表id查出字段信息 并加入Map结果
        List<ColumnInfo> columnInfos = columnInfoDao.findAllByDbId(tableInfoId);
        for (ColumnInfo columnInfo : columnInfos) {
            result.put(columnInfo.getFieldName(), null);
        }
        //做json转换并返回
        try {
            return new ObjectMapper().writeValueAsString(result);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new ApiException("json转换时出现异常");
        }
    }

    /**
     * 获取指定聚合对象模型的json格式数据示例
     *
     * @param tableInfoExId 指定id
     * @return json格式的数据示例
     */
    public String getExJsonExample(Integer tableInfoExId) {
        Map<String, Object> result = new HashMap<>();
        TableInfoEx tableInfoEX = tableInfoExDao.findById(tableInfoExId)
                .orElseThrow(() -> new ApiException(format("未找到该id的数据:%s", tableInfoExId)));
        //根据主表id查出主表部分字段信息 并加入Map结果
        List<ColumnInfo> columnInfos = columnInfoDao.findAllByDbId(tableInfoEX.getMainTableId());
        for (ColumnInfo columnInfo : columnInfos) {
            result.put(columnInfo.getFieldName(), null);
        }
        //查出相关聚合信息并做处理
        List<Aggregation> aggregations = aggregationDao.findAllByTableInfoExIdAndParentId(tableInfoExId, null);
        getSubResult(result, aggregations);
        //做json转换并返回
        try {
            return new ObjectMapper().writeValueAsString(result);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new ApiException("json转换时出现异常");
        }
    }

    private void getSubResult(Map<String, Object> result, List<Aggregation> aggregations) {
        for (Aggregation aggregation : aggregations) {
            List<ColumnInfo> subColumnInfos = columnInfoDao.findAllByDbId(aggregation.getSideTableId());
            Map<String, Object> subResult = new HashMap<>();
            for (ColumnInfo subColumnInfo : subColumnInfos) {
                subResult.put(subColumnInfo.getFieldName(), null);
            }
            String subTableName = tableInfoDao.findById(aggregation.getSideTableId())
                    .orElseThrow(() -> new RuntimeException(format("未找到该id的数据:%s", aggregation.getSideTableId())))
                    .getModelName();
            //如果聚合信息下还有子聚合信息 则往下递归处理
            boolean hasSub = Objects.nonNull(aggregation.getAggregations()) && !aggregation.getAggregations().isEmpty();
            if (hasSub) {
                getSubResult(subResult, aggregation.getAggregations());
            }
            //判断关联类型 根据关联类型做不同处理 0:一对一 1:一对多 2:多对多
            Integer relationshipType = aggregation.getRelationship();
            switch (relationshipType) {
                case 0:
                    result.put(subTableName, subResult);
                    break;
                case 1:
                case 2:
                    List<Map<String, Object>> subResults = new ArrayList<>();
                    subResults.add(subResult);
                    result.put(subTableName, subResults);
                    break;
                default:
                    throw new ApiException(format("未识别的聚合类型:%s", relationshipType));
            }

        }
    }

    /**
     * 根据聚合对象id 查询出其相关所有字段信息（包含对象嵌套字段）
     *
     * @param tableInfoExId 聚合对象id
     * @return 聚合对象字段信息
     */
    public List<ColumnEXVO> getColumnEXVOs(Integer tableInfoExId) {
        List<ColumnEXVO> result = new ArrayList<>();
        TableInfoEx tableInfoEX = tableInfoExDao.findById(tableInfoExId)
                .orElseThrow(() -> new ApiException(format("未找到该id的数据:%s", tableInfoExId)));
        //根据主表id查出主表部分字段信息 并加入Map结果
        List<ColumnInfo> columnInfos = columnInfoDao.findAllByDbId(tableInfoEX.getMainTableId());
        //普通字段部分
        List<ColumnEXVO> part1 = columnInfos.stream()
                .map(this::columnEXVO)
                .collect(Collectors.toList());
        //对象字段部分
        List<Aggregation> aggregations = aggregationDao.findAllByTableInfoExIdAndParentId(tableInfoExId, null);
        List<ColumnEXVO> part2 = columnEXVOs(aggregations);

        result.addAll(part1);
        result.addAll(part2);
        return result;
    }

    private ColumnEXVO columnEXVO(ColumnInfo columnInfo) {
        return new ColumnEXVO(
                columnInfo.getId(),
                columnInfo.getPrimaryKey(),
                columnInfo.getFieldType(),
                columnInfo.getFieldName(),
                columnInfo.getFieldTitle(),
                columnInfo.getFieldLength(),
                columnInfo.getDescription(),
                -1,
                new ArrayList<>()
        );
    }

    private List<ColumnEXVO> columnEXVOs(List<Aggregation> aggregations) {
        List<ColumnEXVO> result = new ArrayList<>();
        for (Aggregation aggregation : aggregations) {
            List<ColumnInfo> columnInfos = columnInfoDao.findAllByDbId(aggregation.getSideTableId());
            List<ColumnEXVO> columns = columnInfos.stream()
                    .map(this::columnEXVO)
                    .collect(Collectors.toList());
            TableInfo tableInfo = tableInfoDao.findById(aggregation.getSideTableId())
                    .orElseThrow(() -> new RuntimeException(format("未找到该id的数据:%s", aggregation.getSideTableId())));
            //如果聚合信息下还有子聚合信息 则往下递归获取字段信息
            boolean hasSub = Objects.nonNull(aggregation.getAggregations()) && !aggregation.getAggregations().isEmpty();
            if (hasSub) {
                List<ColumnEXVO> objColumns = columnEXVOs(aggregation.getAggregations());
                columns.addAll(objColumns);
            }
            ColumnEXVO columnEXVO = new ColumnEXVO(
                    null,
                    0,
                    Object.class.getTypeName(),
                    tableInfo.getModelName(),
                    tableInfo.getModelTitle(),
                    -1,
                    tableInfo.getDescription(),
                    aggregation.getRelationship(),
                    columns
            );
            result.add(columnEXVO);
        }
        return result;
    }

}
