package com.tykj.workflowcore.ds.service;

import com.tykj.workflowcore.model_layer.entity.vo.ColumnVO;
import com.tykj.workflowcore.model_layer.entity.vo.TableVO;
import com.tykj.workflowcore.model_layer.service.ModelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static java.lang.String.format;
import static java.util.Objects.nonNull;

/**
 * 用于数据同步的数据操作执行者
 */
@Slf4j
@Service
public class DataOperation {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private DataSourceManager dataSourceManager;
    @Autowired
    private ModelService modelService;

    /**
     * 同步外界数据源中所有表结构
     * @param dataSourceName 指定数据源的名字
     */
    public void syncAllTablesFromDataSource(String dataSourceName) {
        dataSourceManager.switchToDataSource(dataSourceName);
        List<String> tableNames = getAllTableNames();
        for (String tableName : tableNames) {
            TableVO tableVO = new TableVO();
            tableVO.setModelName(tableName);
            tableVO.setModelType(3);
            tableVO.setDataList(getColumns(tableName));
            modelService.newTable(tableVO);
        }
    }

    private List<String> getAllTableNames() {
        return jdbcTemplate.queryForList("show tables").stream()
                .map(resultMap -> String.valueOf(resultMap.get("Tables_in_center")))
                .collect(Collectors.toList());
    }

    private List<ColumnVO> getColumns(String tableName) {
        return jdbcTemplate.queryForList(format("desc %s", tableName)).stream()
                .map(this::columnVO)
                .collect(Collectors.toList());
    }

    private ColumnVO columnVO(Map<String, Object> columnInfoMap) {
        String columnName = String.valueOf(columnInfoMap.get("Field"));
        String typeValue = String.valueOf(columnInfoMap.get("Type"));
        //
        boolean hasLength = typeValue.contains("(") && typeValue.contains(")");
        String columnType;
        Integer columnLength;
        if (hasLength) {
            //
            columnType = typeValue.substring(0, typeValue.indexOf("("));
            columnLength = Integer.valueOf(typeValue.substring(typeValue.indexOf("(") + 1, typeValue.indexOf(")")));
        } else {
            columnType = typeValue;
            columnLength = 0;
        }
        String keyValue = String.valueOf(columnInfoMap.get("Key"));
        Integer isPrimary = Objects.equals(keyValue, "PRI") ? 0 : 1;
        return new ColumnVO(
                null,
                isPrimary,
                columnType,
                columnName,
                Strings.EMPTY,
                columnLength,
                Strings.EMPTY
        );
    }

    public void syncData(String dataSourceName, String tableName) {
        dataSourceManager.switchToDataSource(dataSourceName);
        List<Map<String, Object>> dataList = getData(tableName);
        dataSourceManager.clear();
        clearTable(tableName);
        for (Map<String, Object> data : dataList) {
            String sql = insertSql(tableName, data);
            log.info("execute : {}", sql);
            jdbcTemplate.execute(sql);
        }
    }

    private List<Map<String, Object>> getData(String tableName) {
        return jdbcTemplate.queryForList(format("select * from %s", tableName));
    }

    private String insertSql(String tableName, Map<String, Object> data) {
        StringBuilder result = new StringBuilder();
        result.append("insert into ").append(tableName).append(" ");
        StringBuilder names = new StringBuilder();
        names.append("(");
        StringBuilder values = new StringBuilder();
        values.append("(");
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            if (nonNull(entry.getValue())) {
                names.append(entry.getKey()).append(",");
                values.append("'").append(entry.getValue()).append("'").append(",");
            }
        }
        names.delete(names.lastIndexOf(","), names.lastIndexOf(",") + 1);
        values.delete(values.lastIndexOf(","), values.lastIndexOf(",") + 1);
        names.append(")");
        values.append(")");
        result.append(names);
        result.append(" values ");
        result.append(values);
        return result.toString();
    }

    private void clearTable(String tableName) {
        jdbcTemplate.execute(format("truncate table %s", tableName));
    }

}
