package com.boman.gen.service;

import com.boman.common.core.utils.StringUtils;
import com.boman.common.core.utils.obj.ObjectUtils;
import com.boman.domain.dto.AjaxResult;
import com.boman.common.redis.RedisKey;
import com.boman.common.redis.service.RedisService;
import com.boman.domain.GenTable;
import com.boman.domain.GenTableColumn;
import com.boman.domain.GenTableRelation;
import com.boman.domain.SysDictData;
import com.boman.domain.constant.FormDataConstant;
import com.boman.system.api.RemoteDictDataService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.boman.common.core.utils.obj.ObjectUtils.requireNonNull;

/**
 * @author tjf
 * @Date: 2021/04/27/15:07
 */
@Service
public class LoadTableServerImpl implements ILoadTableServer{
    @Autowired
    private IGenTableService genTableService;
    @Autowired
    private IGenTableColumnService genTableColumnService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private IGenTableRelationService genTableRelationService;
    @Autowired
    private RemoteDictDataService remoteDictDataService;


    @Override
    public AjaxResult loadTable(GenTable genTable) {
        List<GenTable> tableList = genTableService.selectGenTableList(genTable);
        requireNonNull(tableList, "tableList is empty");

        // load table and tableColumn
        List<Long> tableIdList = tableList.stream().map(GenTable::getId).collect(Collectors.toList());
        List<GenTableColumn> genTableColumns = genTableColumnService.listByTableIdList(tableIdList);
        requireNonNull(genTableColumns, "genTableColumns is empty");
        packTableAndInsertToRedis(tableList, genTableColumns);

        List<GenTableRelation> relationList = genTableRelationService.selectGenTableRelationList(new GenTableRelation());
        if (relationList.size() > 0) {
            // load gen_table_relation表数据到redis
            redisService.setCacheObject(RedisKey.RELATION_INFO, relationList, 12L, TimeUnit.DAYS);
            // load tableRelation
            packRelationAndInsertToRedis(tableList, relationList, genTableColumns);
        }
        return AjaxResult.success(tableList);
    }

    /**
     * 手动刷新redis
     * @return
     */
    @Override
    public AjaxResult updateRedisTable() {
        //获取所有的表和表字段,更新到redis中
        List<GenTable> tableList = genTableService.selectGenTableList(new GenTable());
        if (null == tableList || tableList.isEmpty()) {
            return AjaxResult.error("当前没有可更新数据");
        }
        List<Long> tableIdList = tableList.stream().map(GenTable::getId).collect(Collectors.toList());
        List<GenTableColumn> genTableColumns = genTableColumnService.listByTableIdList(tableIdList);
        if (null == genTableColumns || genTableColumns.isEmpty()) {
            return AjaxResult.error("当前没有可更新数据");
        }
        packTableAndInsertToRedis(tableList, genTableColumns);
        return AjaxResult.success();
    }

    /**
     * 功能描述: 把主表关联的附表的信息和附表的字段信息存进redis
     *
     * @param tableList    tableList 所有表对象信息
     * @param relationList 所有主表和附表的关联关系
     * @param tableColumns 所有表字段
     */
    private void packRelationAndInsertToRedis(List<GenTable> tableList, List<GenTableRelation> relationList
            , List<GenTableColumn> tableColumns) {
        for (GenTable table : tableList) {
            List<GenTable> tableListTemp = new ArrayList<>(16);
            //对关联关系表进行排序
            relationList = relationList.stream().sorted(Comparator.comparing(GenTableRelation::getRelationParentId).thenComparing(GenTableRelation::getSort)).collect(Collectors.toList());

            for (GenTableRelation relation : relationList) {
                if (relation.getRelationParentId().equals(table.getId())) {
                    //关联主表PK gen_table_column的id
                    Long childId = relation.getRelationChildId();
                    //根据gen_table_column的id查询出表id
                    GenTableColumn genTableColumn = genTableColumnService.selectGenTableColumnListByColumnId(childId);
                    // TODO: 2021/4/8
                    //从tableList中去取出对应表的对象
                    if (genTableColumn != null) {
                        List<GenTable> collect = tableList.stream()
                                .filter(genTable -> genTable.getId().equals(genTableColumn.getTableId()))
                                .collect(Collectors.toList());
                        GenTable genTable = collect.get(0);
                        List<GenTableColumn> collectColumn = tableColumns.stream()
                                .filter(genTableColumns -> genTableColumns.getTableId().equals(genTableColumn.getTableId()))
                                .collect(Collectors.toList());
                        genTable.setColumns(collectColumn);
                        tableListTemp.add(genTable);
                    }
                }
            }
            table.setRelationList(tableListTemp);
            redisService.setCacheObject(RedisKey.RELATION + table.getTableName(), table, 12L, TimeUnit.DAYS);
        }
    }

    /**
     * 功能描述: 把table中塞入对应的column， 同时把所有的信息塞到redis中
     *
     * @param tableList       tableList
     * @param genTableColumns 所有的列
     */
    private void packTableAndInsertToRedis(List<GenTable> tableList, List<GenTableColumn> genTableColumns) {
        for (GenTable table : tableList) {
            List<GenTableColumn> columnList = new ArrayList<>(16);
            for (GenTableColumn tableColumn : genTableColumns) {
                if (table.getId().equals(tableColumn.getTableId())) {
                    // 存一个tableName留作备用
                    tableColumn.setTableName(table.getTableName());
                    String dictType = tableColumn.getDictType();
                    if(StringUtils.isNotBlank(dictType)){
                        //查询对应的字典数据集合
                        List<SysDictData> sysDictData = remoteDictDataService.listByType(dictType);
                        if (sysDictData.size() > 0){
                            tableColumn.setSysDictData(sysDictData);
                        }
                    }
                    // 把外键信息存进去，留着查询的时候用
                    packFkInfo(tableColumn);
                    columnList.add(tableColumn);
                }
            }
            table.setColumns(columnList);
            table.setIsContainsBlob(isContainsBlob(columnList));
            redisService.setCacheObject(RedisKey.TABLE_INFO + table.getTableName(), table, 12L, TimeUnit.DAYS);
        }
    }

    private void packFkInfo(GenTableColumn tableColumn) {
        Long fkColumnId = tableColumn.getForeignKey();
        if (ObjectUtils.isNotEmpty(fkColumnId)) {
            // 外键在table_column中的id
            GenTableColumn fkTableColumn = genTableColumnService.selectGenTableColumnListByColumnId(fkColumnId);
            String fkColumnName = fkTableColumn.getColumnName();
            Long fkTableId = fkTableColumn.getTableId();
            GenTable fkGenTable = genTableService.getByTableId(fkTableId);
            // 显示键 table_column 表的id
            Long dkColumnId = fkGenTable.getDkColumn();
            String dkColumnName = fkColumnName;
            if(dkColumnId != null){
                GenTableColumn dkTableColumn = genTableColumnService.selectGenTableColumnListByColumnId(dkColumnId);
                 dkColumnName = dkTableColumn.getColumnName();
            }
            String fkTableName = fkGenTable.getTableName();
            Map<String, Object> fkInfo = Maps.newConcurrentMap();
            fkInfo.put(FormDataConstant.FK_TABLE_NAME, fkTableName);
            fkInfo.put(FormDataConstant.FK_COLUMN_NAME, fkColumnName);
            fkInfo.put(FormDataConstant.DK_COLUMN_NAME, dkColumnName);
            tableColumn.setFkInfo(fkInfo);
        }
    }

    public boolean isContainsBlob(List<GenTableColumn> columnList) {
        if (CollectionUtils.isEmpty(columnList)) {
            return false;
        }

        ArrayList<String> blob = Lists.newArrayList("blob", "tinyblob", "mediumblob", "longblob");
        for (GenTableColumn column : columnList) {
            if (blob.contains(column.getColumnType())) {
                return true;
            }
        }

        return false;
    }
}
