package com.easyagents.federation.sql.federation;

import com.easyagents.federation.sql.execute.FederationColumn;
import com.easyagents.federation.sql.source.SourceId;
import java.util.List;

/**
 * 一个可交给物理数据源 Adapter 执行的查询分片。
 *
 * @param fragmentId 计划内唯一分片标识
 * @param bindingName 查询范围 Binding 名称
 * @param sourceId 物理数据源标识
 * @param executableSql 目标数据库方言 SQL
 * @param parameterMapping 分片占位符到原始查询参数的零基索引映射
 * @param columns 分片输出列
 * @param costEstimate 分片搬运成本估算
 * @param pushedDownOperators 已下推至物理源的关系算子
 */
public record FederationFragmentPlan(
    String fragmentId,
    String bindingName,
    SourceId sourceId,
    String executableSql,
    List<Integer> parameterMapping,
    List<FederationColumn> columns,
    FederationCostEstimate costEstimate,
    List<String> pushedDownOperators
) {

    /**
     * 校验并创建不可变分片计划。
     */
    public FederationFragmentPlan {
        if (fragmentId == null || fragmentId.isBlank()
            || bindingName == null || bindingName.isBlank()
            || sourceId == null || executableSql == null || executableSql.isBlank()) {
            throw new IllegalArgumentException("fragment identity and SQL must be provided");
        }
        parameterMapping = List.copyOf(parameterMapping == null ? List.of() : parameterMapping);
        columns = List.copyOf(columns == null ? List.of() : columns);
        if (costEstimate == null) {
            throw new IllegalArgumentException("costEstimate must be provided");
        }
        pushedDownOperators = List.copyOf(
            pushedDownOperators == null ? List.of() : pushedDownOperators
        );
    }

    /**
     * 创建不携带显式成本输入的兼容分片计划。
     *
     * @param fragmentId 计划内唯一分片标识
     * @param bindingName 查询范围 Binding 名称
     * @param sourceId 物理数据源标识
     * @param executableSql 目标数据库方言 SQL
     * @param parameterMapping 参数映射
     * @param columns 输出列
     */
    public FederationFragmentPlan(
        String fragmentId,
        String bindingName,
        SourceId sourceId,
        String executableSql,
        List<Integer> parameterMapping,
        List<FederationColumn> columns
    ) {
        this(
            fragmentId,
            bindingName,
            sourceId,
            executableSql,
            parameterMapping,
            columns,
            new FederationCostEstimate(
                0,
                0,
                0,
                "calcite-default",
                "none",
                java.time.Instant.EPOCH,
                true,
                FederationStatisticsStatus.MISSING,
                false
            ),
            List.of()
        );
    }
}
