package com.easyagents.federation.sql.runtime;

import com.easyagents.federation.sql.api.FederationSqlErrorCode;
import com.easyagents.federation.sql.api.FederationSqlException;
import com.easyagents.federation.sql.execute.FederationExecutionGuard;
import java.time.Duration;

/**
 * 一次查询从编译到游标关闭共享的绝对截止时间。
 */
final class QueryDeadline implements FederationExecutionGuard, BoundedPlanCache.WaitGuard {

    private final long deadlineNanos;
    private final QueryCancellationRegistry.QueryRegistration registration;
    private final FederationSqlErrorCode timeoutCode;
    private final String timeoutMessage;

    private QueryDeadline(
        long deadlineNanos,
        QueryCancellationRegistry.QueryRegistration registration,
        FederationSqlErrorCode timeoutCode,
        String timeoutMessage
    ) {
        this.deadlineNanos = deadlineNanos;
        this.registration = registration;
        this.timeoutCode = timeoutCode;
        this.timeoutMessage = timeoutMessage;
    }

    /**
     * 计算从当前时刻开始的饱和绝对截止时间。
     *
     * @param duration 最大持续时间
     * @return 绝对截止纳秒
     */
    static long deadlineAfter(Duration duration) {
        return deadlineAfter(System.nanoTime(), duration);
    }

    /**
     * 基于指定单调时钟值计算截止时间，允许 {@link System#nanoTime()} 自然回绕。
     *
     * @param now 当前单调时钟值
     * @param duration 最大持续时间
     * @return 绝对截止纳秒；持续时间无法转换时返回无限时限标记
     */
    static long deadlineAfter(long now, Duration duration) {
        long nanos;
        try {
            nanos = duration.toNanos();
        } catch (ArithmeticException exception) {
            return Long.MAX_VALUE;
        }
        if (nanos == Long.MAX_VALUE) {
            return Long.MAX_VALUE;
        }
        // nanoTime 只保证差值语义；直接相加并允许补码回绕，剩余时间差仍然正确。
        return now + nanos;
    }

    /**
     * 创建仅约束公开编译调用的截止时间。
     *
     * @param duration 最大编译时间
     * @return 编译截止时间
     */
    static QueryDeadline compile(Duration duration) {
        return new QueryDeadline(
            deadlineAfter(duration),
            null,
            FederationSqlErrorCode.SQL_COMPILE_TIMEOUT,
            "SQL compilation exceeded the configured deadline"
        );
    }

    /**
     * 创建绑定查询取消终态的截止时间。
     *
     * @param deadlineNanos 请求级绝对截止时间
     * @param registration 查询登记
     * @return 查询截止时间
     */
    static QueryDeadline query(
        long deadlineNanos,
        QueryCancellationRegistry.QueryRegistration registration
    ) {
        return new QueryDeadline(
            deadlineNanos,
            registration,
            FederationSqlErrorCode.QUERY_TIMEOUT,
            "query exceeded the configured deadline"
        );
    }

    /** {@inheritDoc} */
    @Override
    public void ensureAllowed() {
        if (registration != null) {
            registration.ensureNotCancelled();
        }
        if (remainingNanos() <= 0L) {
            requestTimeout();
            if (registration != null) {
                registration.ensureNotCancelled();
            }
            throw new FederationSqlException(timeoutCode, timeoutMessage);
        }
    }

    /** {@inheritDoc} */
    @Override
    public long remainingNanos() {
        if (deadlineNanos == Long.MAX_VALUE) {
            return Long.MAX_VALUE;
        }
        return deadlineNanos - System.nanoTime();
    }

    /**
     * 将绑定查询推进为超时终态。
     */
    QueryCancellationRegistry.TerminationReason requestTimeout() {
        return registration == null
            ? QueryCancellationRegistry.TerminationReason.NONE
            : registration.requestTimeoutOutcome();
    }
}
