package com.easyagents.federation.sql.federation;

import java.io.Serializable;

/**
 * 联邦查询的调用方资源上限；Engine 会与自己的硬上限取更严格值。
 *
 * @param maximumReferencedSources 单条 SQL 最多实际引用的数据源数
 * @param maximumFragments 最多物理查询分片数
 * @param maximumConcurrentFragments 最大并发分片数
 * @param maximumIntermediateRows 最多读取的中间结果行数
 * @param maximumIntermediateBytes 最多读取的中间结果估算字节数
 * @param maximumExecutionTimeMillis 联邦执行总时限
 */
public record FederationExecutionPolicy(
    int maximumReferencedSources,
    int maximumFragments,
    int maximumConcurrentFragments,
    long maximumIntermediateRows,
    long maximumIntermediateBytes,
    long maximumExecutionTimeMillis
) implements Serializable {

    private static final FederationExecutionPolicy BASIC = new FederationExecutionPolicy(
        2,
        8,
        2,
        100_000,
        64L * 1024L * 1024L,
        60_000
    );

    /**
     * 校验资源上限。
     */
    public FederationExecutionPolicy {
        if (maximumReferencedSources <= 0
            || maximumFragments <= 0
            || maximumConcurrentFragments <= 0
            || maximumIntermediateRows <= 0
            || maximumIntermediateBytes <= 0
            || maximumExecutionTimeMillis <= 0) {
            throw new IllegalArgumentException("federation execution limits must be positive");
        }
        if (maximumConcurrentFragments > maximumFragments) {
            throw new IllegalArgumentException(
                "maximumConcurrentFragments must not exceed maximumFragments"
            );
        }
    }

    /**
     * 返回适合首批联邦查询的保守默认策略。
     *
     * @return 默认策略
     */
    public static FederationExecutionPolicy basic() {
        return BASIC;
    }

    /**
     * 将两个策略收敛为逐项更严格的有效策略。
     *
     * @param other 另一个策略
     * @return 有效策略
     */
    public FederationExecutionPolicy intersect(FederationExecutionPolicy other) {
        if (other == null) {
            return this;
        }
        return new FederationExecutionPolicy(
            Math.min(maximumReferencedSources, other.maximumReferencedSources),
            Math.min(maximumFragments, other.maximumFragments),
            Math.min(maximumConcurrentFragments, other.maximumConcurrentFragments),
            Math.min(maximumIntermediateRows, other.maximumIntermediateRows),
            Math.min(maximumIntermediateBytes, other.maximumIntermediateBytes),
            Math.min(maximumExecutionTimeMillis, other.maximumExecutionTimeMillis)
        );
    }
}
