package com.njcn.gather.tool.adddata.component;

import com.njcn.gather.tool.adddata.pojo.bo.AddDataTableDefinition;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 数据补录表定义注册器。
 */
@Slf4j
@Component
public class AddDataTableRegistry implements InitializingBean {

    /** 元数据 SQL 资源。 */
    private static final String SCHEMA_RESOURCE_PATH = "sql/add-data/DATA_FLICKER.sql";

    /** 建表语句解析表达式。 */
    private static final Pattern TABLE_PATTERN = Pattern.compile("CREATE TABLE\\s+`([^`]+)`\\s*\\((.*?)\\)\\s*ENGINE",
            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);

    /** 列定义解析表达式。 */
    private static final Pattern COLUMN_PATTERN = Pattern.compile("^\\s*`([^`]+)`", Pattern.MULTILINE);

    /** 首版统一按 A/B/C/T 四类相别落库。 */
    private static final List<String> WRITE_PHASE_CODES = Collections.unmodifiableList(Arrays.asList("A", "B", "C", "T"));

    /** 宽表批次大小。 */
    private static final int WIDE_TABLE_BATCH_SIZE = 100;

    /** 窄表批次大小。 */
    private static final int NARROW_TABLE_BATCH_SIZE = 500;

    /** 表定义列表。 */
    private List<AddDataTableDefinition> tableDefinitions = Collections.emptyList();

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, List<String>> columnMap = parseSchemaColumns();
        List<AddDataTableDefinition> definitions = new ArrayList<AddDataTableDefinition>();
        definitions.add(buildDefinition(columnMap, "data_flicker", AddDataTableDefinition.TimeAxisType.FIXED_TEN_MINUTES, NARROW_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_fluc", AddDataTableDefinition.TimeAxisType.FIXED_TEN_MINUTES, NARROW_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_harmphasic_i", AddDataTableDefinition.TimeAxisType.REQUEST_INTERVAL, WIDE_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_harmphasic_v", AddDataTableDefinition.TimeAxisType.REQUEST_INTERVAL, WIDE_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_harmpower_p", AddDataTableDefinition.TimeAxisType.REQUEST_INTERVAL, WIDE_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_harmpower_q", AddDataTableDefinition.TimeAxisType.REQUEST_INTERVAL, WIDE_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_harmpower_s", AddDataTableDefinition.TimeAxisType.REQUEST_INTERVAL, WIDE_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_harmrate_i", AddDataTableDefinition.TimeAxisType.REQUEST_INTERVAL, WIDE_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_harmrate_v", AddDataTableDefinition.TimeAxisType.REQUEST_INTERVAL, WIDE_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_i", AddDataTableDefinition.TimeAxisType.REQUEST_INTERVAL, WIDE_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_inharm_i", AddDataTableDefinition.TimeAxisType.REQUEST_INTERVAL, WIDE_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_plt", AddDataTableDefinition.TimeAxisType.FIXED_TWO_HOURS, NARROW_TABLE_BATCH_SIZE));
        definitions.add(buildDefinition(columnMap, "data_v", AddDataTableDefinition.TimeAxisType.REQUEST_INTERVAL, WIDE_TABLE_BATCH_SIZE));
        tableDefinitions = Collections.unmodifiableList(definitions);
        log.info("加载 add-data 表定义完成，tableCount={}", tableDefinitions.size());
    }

    /**
     * 返回全部表定义。
     *
     * @return 表定义列表
     */
    public List<AddDataTableDefinition> getTableDefinitions() {
        return tableDefinitions;
    }

    /**
     * 根据表名查找表定义。
     *
     * @param tableName 表名
     * @return 表定义
     */
    public AddDataTableDefinition getDefinition(String tableName) {
        for (AddDataTableDefinition definition : tableDefinitions) {
            if (definition.getTableName().equals(tableName)) {
                return definition;
            }
        }
        throw new IllegalArgumentException("未找到 add-data 表定义：" + tableName);
    }

    /**
     * 解析 schema SQL 中的列定义。
     *
     * @return 表名与字段列表映射
     */
    private Map<String, List<String>> parseSchemaColumns() {
        String schemaText = loadSchemaText();
        Matcher tableMatcher = TABLE_PATTERN.matcher(schemaText);
        Map<String, List<String>> columnMap = new LinkedHashMap<String, List<String>>();
        while (tableMatcher.find()) {
            String tableName = tableMatcher.group(1);
            String tableBody = tableMatcher.group(2);
            Matcher columnMatcher = COLUMN_PATTERN.matcher(tableBody);
            List<String> columns = new ArrayList<String>();
            while (columnMatcher.find()) {
                columns.add(columnMatcher.group(1));
            }
            columnMap.put(tableName, columns);
        }
        return columnMap;
    }

    /**
     * 创建单表定义。
     *
     * @param columnMap 字段映射
     * @param tableName 表名
     * @param timeAxisType 时间轴类型
     * @param batchSize 批次大小
     * @return 表定义
     */
    private AddDataTableDefinition buildDefinition(Map<String, List<String>> columnMap, String tableName,
                                                   AddDataTableDefinition.TimeAxisType timeAxisType, int batchSize) {
        List<String> columns = columnMap.get(tableName);
        if (columns == null || columns.isEmpty()) {
            throw new IllegalStateException("未从 SQL 元数据中解析到表字段：" + tableName);
        }
        /*
         * 当前按用户最新确认，13 张表统一支持 A/B/C/T 四类数据类型。
         * 如果后续补齐逐表更细的相别映射，只需要在这里调整落库相别集合即可。
         */
        return new AddDataTableDefinition(tableName, columns, WRITE_PHASE_CODES, batchSize, timeAxisType);
    }

    /**
     * 加载 schema SQL 文本。
     *
     * @return SQL 文本
     */
    private String loadSchemaText() {
        ClassPathResource resource = new ClassPathResource(SCHEMA_RESOURCE_PATH);
        try {
            return StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new IllegalStateException("读取 add-data SQL 元数据失败：" + SCHEMA_RESOURCE_PATH, e);
        }
    }
}
