package com.common.service.impl;

import com.common.entity.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * 达梦安全版 SQL生成服务实现（子查询包装模式）
 *
 * 继承自 SqlGeneratorServiceImpl，重写 generateSql() 方法。
 * 当配置了时间窗口（TUMBLE/HOP/SESSION）时，采用子查询包装方式生成SQL，
 * 将时间窗口函数 TUMBLE()/HOP()/SESSION() 的计算下沉到内层子查询中，
 * 外层 GROUP BY 直接引用别名 window_time，规避达梦安全版 GROUP BY 不支持自定义函数的问题。
 *
 * 注意：本类不注册为 Spring Bean（不加 @Service），由 RealtimeAnalysisEngineDm 直接实例化，
 * 避免与父类 SqlGeneratorServiceImpl 产生类型冲突影响 OfflineAnalysisEngine。
 *
 * 产出示例：
 * SELECT ...聚合函数..., window_time
 * FROM (
 *     SELECT 原始列..., TUMBLE(log_time, INTERVAL '5 MINUTE') AS window_time
 *     FROM syslog_normal_alarm AS t
 *     WHERE ...
 * )
 * GROUP BY src_ip, dest_ip, window_time
 */
@Slf4j
public class SqlGeneratorServiceImplDm extends SqlGeneratorServiceImpl {

    /**
     * 重写：根据规则动态生成SQL
     * 有窗口配置 → 子查询包装模式
     * 无窗口配置 → 委托父类原有逻辑
     */
    @Override
    public String generateSql(AnalysisAnalysisRule rule,
                              List<AnalysisField> fields,
                              List<AnalysisWhereCondition> whereConditions,
                              List<AnalysisFilter> filters,
                              List<AnalysisGroupByColumn> groupByColumns,
                              List<AnalysisGroupByHaving> havingConditions,
                              AnalysisGroupByWindow groupByWindow,
                              String startTime,
                              String endTime) {
        // 如果有时间窗口配置 → 走子查询包装模式（达梦安全版兼容方案）
        if (groupByWindow != null && StringUtils.isNotBlank(groupByWindow.getWindowType())) {
            return generateSubquerySql(fields, filters, groupByColumns,
                    havingConditions, groupByWindow, startTime, endTime);
        }
        // 无窗口配置 → 委托父类原有逻辑（平铺SQL）
        return super.generateSql(rule, fields, whereConditions, filters,
                groupByColumns, havingConditions, groupByWindow, startTime, endTime);
    }

    // ==================== 子查询包装模式核心方法 ====================

    /**
     * 生成子查询包装的完整SQL（达梦安全版兼容方案）
     *
     * SQL结构：
     *   SELECT [外层聚合列...], window_time
     *   FROM (
     *       SELECT [内层原始列...], TUMBLE(log_time, ...) AS window_time
     *       FROM syslog_normal_alarm AS t
     *       WHERE ...
     *   )
     *   GROUP BY [分组列...], window_time
     *   HAVING ...
     */
    private String generateSubquerySql(List<AnalysisField> fields,
                                       List<AnalysisFilter> filters,
                                       List<AnalysisGroupByColumn> groupByColumns,
                                       List<AnalysisGroupByHaving> havingConditions,
                                       AnalysisGroupByWindow groupByWindow,
                                       String startTime,
                                       String endTime) {
        // 1. 内层子查询SELECT：原始列 + TUMBLE(...) AS window_time
        String innerSelect = buildInnerSelectForWindow(fields, groupByColumns, groupByWindow);

        // 2. FROM + WHERE（在内层子查询中）
        String fromClause = generateFromClause(fields, null);
        String whereClause = generateWhereClauseFromFilters(filters, startTime, endTime);

        // 3. 外层SELECT：聚合列 + window_time
        String outerSelect = buildOuterSelectForWindow(fields);

        // 4. 外层GROUP BY：分组列 + window_time（别名，非函数调用）
        String groupByClause = buildGroupByForWindow(groupByColumns);

        // 5. HAVING（不变，复用父类）
        String havingClause = generateHavingClauseFromConditions(havingConditions);

        // 6. 拼接最终SQL
        return assembleSubquerySql(outerSelect, innerSelect, fromClause,
                whereClause, groupByClause, havingClause);
    }

    /**
     * 构建内层子查询的SELECT子句
     * 产出：
     *   SELECT src_ip, dest_ip, origin_event_name, ..., TUMBLE(log_time, INTERVAL '5 MINUTE') AS window_time
     */
    private String buildInnerSelectForWindow(List<AnalysisField> fields,
                                              List<AnalysisGroupByColumn> groupByColumns,
                                              AnalysisGroupByWindow groupByWindow) {
        Set<String> columns = new LinkedHashSet<>();

        // 1. 从 fields 中提取所有原始列名（不含聚合函数）
        if (fields != null) {
            for (AnalysisField field : fields) {
                if (StringUtils.isNotBlank(field.getColumnName())) {
                    columns.add(field.getColumnName());
                }
            }
        }

        // 2. 从 groupByColumns 中提取原始列名
        if (groupByColumns != null) {
            for (AnalysisGroupByColumn col : groupByColumns) {
                if (StringUtils.isNotBlank(col.getColumnName())) {
                    columns.add(col.getColumnName());
                }
            }
        }

        // 3. 追加时间窗口表达式（带 AS window_time 别名）
        //    复用父类 protected 方法 buildTimeWindowExpression
        String windowExpr = buildTimeWindowExpression(groupByWindow);

        List<String> parts = new ArrayList<>(columns);
        if (StringUtils.isNotBlank(windowExpr)) {
            parts.add(windowExpr);
        }

        return "SELECT " + String.join(",\n       ", parts);
    }

    /**
     * 构建外层SELECT子句（聚合层）
     * 产出：
     *   SELECT JSONB_AGG(DISTINCT src_port) AS attack_port, ..., window_time
     */
    private String buildOuterSelectForWindow(List<AnalysisField> fields) {
        // 复用父类 generateSelectClause(fields, null)
        // 传 null 窗口 → 不追加 TUMBLE(...) AS window_time，仅生成聚合函数列
        String baseSelect = generateSelectClause(fields, null);

        // 手动追加 window_time（此时是普通列引用，不是函数调用）
        return baseSelect + ",\n       window_time";
    }

    /**
     * 构建外层GROUP BY子句
     * 产出：
     *   GROUP BY origin_event_name, src_ip, dest_ip, window_time
     *
     * 关键差异：使用别名 window_time，而非 TUMBLE(log_time, ...) 函数调用
     */
    private String buildGroupByForWindow(List<AnalysisGroupByColumn> groupByColumns) {
        // 复用父类 generateGroupByClause(columns, null)
        // 传 null 窗口 → 不追加 TUMBLE(...) 函数调用，仅生成业务分组列
        String baseGroupBy = generateGroupByClause(groupByColumns, null);

        if (StringUtils.isBlank(baseGroupBy)) {
            return "GROUP BY window_time";
        }
        // 在现有 GROUP BY 后追加 window_time
        return baseGroupBy + ", window_time";
    }

    /**
     * 拼接子查询包装SQL
     */
    private String assembleSubquerySql(String outerSelect, String innerSelect,
                                       String fromClause, String whereClause,
                                       String groupByClause, String havingClause) {
        StringBuilder sql = new StringBuilder();
        // 外层SELECT
        sql.append(outerSelect).append("\n");
        // 子查询开始
        sql.append("FROM (\n");
        sql.append("    ").append(innerSelect).append("\n");
        sql.append("    ").append(fromClause).append("\n");
        if (StringUtils.isNotBlank(whereClause)) {
            sql.append("    ").append(whereClause).append("\n");
        }
        sql.append(")\n");
        // 外层GROUP BY
        if (StringUtils.isNotBlank(groupByClause)) {
            sql.append(groupByClause).append("\n");
        }
        // HAVING
        if (StringUtils.isNotBlank(havingClause)) {
            sql.append(havingClause).append("\n");
        }
        return sql.toString();
    }
}
