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

import com.bocloud.ims.entity.common.MapBuilder;
import com.bocloud.ims.service.upgrade.UpgradeVersion;
import io.jsonwebtoken.lang.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Component;

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

/**
 * hmc数据导入任务
 * @author luyanchao
 * @date 2021-06-09
 */
@Component("5.0-5.5-SimpleDataMigrationTask")
public class SimpleDataMigrationTask extends com.bocloud.ims.service.upgrade.migration.SimpleDataMigrationTask {

    /**
     * 构造方法
     * @param context spring上下文
     * @param smsUserTask 依赖SmsUserTask
     */
    @Autowired
    public SimpleDataMigrationTask(ApplicationContext context, SmsUserTask smsUserTask) {
        super(context);
        this.dependOn(smsUserTask);
    }

    @Override
    public String[] getTables() {
        return new String[]{
                // HMC
                "hmc_hea_logical_port", "hmc_hea_physical_port", "hmc_host_ethernet_adapter", "hmc_io_adapter",
                "hmc_io_bus", "hmc_ipl_config", "hmc_partition", "hmc_partition_io", "hmc_partition_memory",
                "hmc_partition_network_adapter", "hmc_partition_processor", "hmc_partition_scsi_adapter",
                "hmc_partition_vfc_adapter", "hmc_physical_disk", "hmc_physical_fibre_channel", "hmc_profile",
                "hmc_profile_fibre_adapter", "hmc_profile_ioslot", "hmc_profile_lhea", "hmc_profile_network_adapter",
                "hmc_profile_scsi_adapter", "hmc_server", "hmc_system_capability", "hmc_system_memory_config",
                "hmc_system_processor_config", "hmc_system_shared_processor_pool", "hmc_virtual_disk", "hmc_volume_group",
                "hmc_virtual_fibre_channel_mapping", "hmc_virtual_network_bridge", "hmc_virtual_switch",
                // AGILE
                "agile_cabinet","agile_cabinet_group","agile_device","agile_device_group","agile_device_link",
                "agile_device_port","agile_dhcp_group","agile_end_port","agile_epg","agile_epg_item",
                "agile_external_connect","agile_external_gateway","agile_external_network","agile_fabric_pool",
                "agile_host","agile_ilo_cabinet_pool","agile_ilo_ip","agile_ilo_ip_pool","agile_ilo_message","agile_ip",
                "agile_logic_port","agile_logic_port_device_port","agile_logic_port_ip","agile_logic_router",
                "agile_logic_switch","agile_logic_switch_business_bind","agile_resource_pool_link",
                "agile_router_fabric_pool","agile_sfc_contract","agile_sfc_contract_rule","agile_sfc_order",
                "agile_sfc_scapp","agile_sfc_scapp_path_hop","agile_sfc_template","agile_sfc_type",
                "agile_static_router","agile_subnet","agile_tenant","agile_tenant_dhcp_group",
                "agile_tenant_external_gateway","agile_tenant_fabric_pool","agile_tenant_vmm","agile_vas",
                "agile_vas_link","agile_vas_port","agile_vpc","agile_vpc_business_bind","agile_vpc_connection",
                "agile_vpc_fabric_pool"
        };
    }

    @Override
    public UpgradeVersion getUpgradeVersion() {
        return UpgradeVersion.from50to55;
    }

    private Map<Long, Long> getIdMap(List<Map<String, Object>> oldList, List<Map<String, Object>> newList) {
        Map<Long, Long> idMap = new HashMap<>();
        for (Map<String, Object> oldUser : oldList) {
            Long id50 = Long.parseLong(oldUser.get("id").toString());
            String account50 = oldUser.get("account").toString();
            for (Map<String, Object> newUser : newList) {
                Long id55 = Long.parseLong(newUser.get("id").toString());
                String account55 = newUser.get("account").toString();
                if (account50.equals(account55)) {
                    idMap.put(id50, id55);
                    break;
                }
            }
        }
        return idMap;
    }

    @Override
    public void run() {
        super.run();
        // 处理creator_id, owner_id, mender_id
        NamedParameterJdbcTemplate targetJdbcTemplate = this.getContext().getBean(NamedParameterJdbcTemplate.class);
        NamedParameterJdbcTemplate fromJdbcTemplate = new NamedParameterJdbcTemplate(this.fromDataSource);
        // 查询5.0和5.5管理端用户id的对应关系
        String sql50Manager = "select id, account from manager where is_deleted = 0 ";
        String sql50User = "select id, account from user where is_deleted = 0 ";
        List<Map<String, Object>> v50ManagerResult = fromJdbcTemplate.queryForList(sql50Manager, new HashMap<>());
        List<Map<String, Object>> v50UserResult = fromJdbcTemplate.queryForList(sql50User, new HashMap<>());
        String sql55Manager = "select id, account from user where is_deleted = 0 and is_manager = 1";
        String sql55User = "select id, account from user where is_deleted = 0 and is_manager = 0";
        List<Map<String, Object>> v55ManagerResult = targetJdbcTemplate.queryForList(sql55Manager, new HashMap<>());
        List<Map<String, Object>> v55UserResult = targetJdbcTemplate.queryForList(sql55User, new HashMap<>());
        Map<Long, Long> managerIdMap = this.getIdMap(v50ManagerResult, v55ManagerResult);
        Map<Long, Long> userIdMap = this.getIdMap(v50UserResult, v55UserResult);
        // 由于5.0我们无法区分creator_id, owner_id, mender_id对应的是manager表还是user表
        // 所以，如果某个id在manager表和user表同时都有，则认为来源于manager表
        // 所以这里可以直接将managerIdMap和userIdMap合并，重合的id用managerIdMap覆盖userIdMap
        Map<Long, Long> finalIdMap = new HashMap<>(userIdMap);
        finalIdMap.putAll(managerIdMap);
        // 开始处理
        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>> columnResult = targetJdbcTemplate.queryForList(sql, params);
            List<String> columnNames = columnResult.stream().map(map -> map.get("COLUMN_NAME").toString()).collect(Collectors.toList());
            if (columnNames.contains("creator_id")) {
                for (Map.Entry<Long, Long> idMapEntry : finalIdMap.entrySet()) {
                    Map<String, Object> sqlParams = new HashMap<>();
                    sqlParams.put("idNew", idMapEntry.getValue());
                    sqlParams.put("idOld", idMapEntry.getKey());
                    String sqlUpdate = "update " + table + " set creator_id = :idNew where creator_id = :idOld ";
                    targetJdbcTemplate.update(sqlUpdate, sqlParams);
                }
            }
            if (columnNames.contains("mender_id")) {
                for (Map.Entry<Long, Long> idMapEntry : finalIdMap.entrySet()) {
                    Map<String, Object> sqlParams = new HashMap<>();
                    sqlParams.put("idNew", idMapEntry.getValue());
                    sqlParams.put("idOld", idMapEntry.getKey());
                    String sqlUpdate = "update " + table + " set mender_id = :idNew where mender_id = :idOld ";
                    targetJdbcTemplate.update(sqlUpdate, sqlParams);
                }
            }
            if (columnNames.contains("owner_id")) {
                for (Map.Entry<Long, Long> idMapEntry : finalIdMap.entrySet()) {
                    Map<String, Object> sqlParams = new HashMap<>();
                    sqlParams.put("idNew", idMapEntry.getValue());
                    sqlParams.put("idOld", idMapEntry.getKey());
                    String sqlUpdate = "update " + table + " set owner_id = :idNew where owner_id = :idOld ";
                    targetJdbcTemplate.update(sqlUpdate, sqlParams);
                }
            }
        }
    }
}
