package com.bocloud.ims.service.upgrade.migration;

import com.bocloud.ims.entity.common.MapBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.util.Assert;

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

/**
 * 简单数据迁移任务，为指定的表执行数据迁移操作
 * 1. 源库和新库中表字段名称必须完全一致
 * 2. 从源库中查询数据插入到新库中
 * @author luyanchao
 * @date 2021-06-09
 */
public abstract class SimpleDataMigrationTask extends DataMigrationTask {

    /**
     * spring上下文
     */
    private final ApplicationContext context;

    /**
     * 构造方法
     * @param context spring上下文
     */
    protected SimpleDataMigrationTask(ApplicationContext context) {
        this.context = context;
    }

    /**
     * 获取要处理的表
     * @return 要处理的表
     */
    public abstract String[] getTables();

    @Override
    public void run() {
        Assert.notNull(this.fromDataSource, "fromDataSource can't be null");
        NamedParameterJdbcTemplate targetJdbcTemplate = context.getBean(NamedParameterJdbcTemplate.class);
        NamedParameterJdbcTemplate fromJdbcTemplate = new NamedParameterJdbcTemplate(this.fromDataSource);
        for (String table : this.getTables()) {
            // 先查元数据表获取所有的列名称
            String sql = "select COLUMN_NAME from information_schema.COLUMNS " +
                    "where TABLE_SCHEMA = database() and TABLE_NAME = :table";
            Map<String, Object> params = MapBuilder.init().put("table", table).get();
            List<Map<String, Object>> fromDbColumnResult = fromJdbcTemplate.queryForList(sql, params);
            List<Map<String, Object>> targetDbColumnResult = targetJdbcTemplate.queryForList(sql, params);
            Assert.isTrue(fromDbColumnResult.size() == targetDbColumnResult.size(), "Unequal number of column. Table：" + table);
            List<String> fromDbColumnNames = fromDbColumnResult.stream()
                    .map(map -> map.get("COLUMN_NAME").toString()).collect(Collectors.toList());
            List<String> targetDbColumnNames = targetDbColumnResult.stream()
                    .map(map -> map.get("COLUMN_NAME").toString()).collect(Collectors.toList());
            Assert.isTrue(fromDbColumnNames.equals(targetDbColumnNames), "Unequal column name");
            // 导数据
            String sqlColumns = String.join(",", targetDbColumnNames);
            String sqlValues = targetDbColumnNames.stream().map(name -> ":" + name).collect(Collectors.joining(", "));
            String sqlSelect = "select " + sqlColumns + " from " + table + " where 1=1 ";
            String sqlInsert = "insert into " + table + "("  + sqlColumns + ") values (" + sqlValues + ") ";
            List<Map<String, Object>> fromDbDatas = fromJdbcTemplate.queryForList(sqlSelect, new HashMap<>());
            fromDbDatas.forEach(data -> targetJdbcTemplate.update(sqlInsert, data));
        }
    }

    protected ApplicationContext getContext() {
        return context;
    }
}
