"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TaskLifecycleTimestampValidationError = exports.TASK_LIFECYCLE_TIMESTAMP_IN_FUTURE = void 0;
exports.requireObservedLifecycleTimestamp = requireObservedLifecycleTimestamp;
exports.revalidateObservedLifecycleTimestamp = revalidateObservedLifecycleTimestamp;
const task_lifecycle_1 = require("./task-lifecycle");
exports.TASK_LIFECYCLE_TIMESTAMP_IN_FUTURE = 'TASK_LIFECYCLE_TIMESTAMP_IN_FUTURE';
class TaskLifecycleTimestampValidationError extends Error {
    code;
    field;
    suppliedTimestamp;
    normalizedInstant;
    observedAt;
    differenceMs;
    notBefore;
    constructor(options) {
        super(options.message);
        this.name = 'TaskLifecycleTimestampValidationError';
        this.code = options.code;
        this.field = options.field;
        this.suppliedTimestamp = options.suppliedTimestamp;
        this.normalizedInstant = options.normalizedInstant;
        this.observedAt = options.observedAt;
        this.differenceMs = options.differenceMs;
        this.notBefore = options.notBefore;
    }
}
exports.TaskLifecycleTimestampValidationError = TaskLifecycleTimestampValidationError;
/**
 * Validates an explicit lifecycle event against the clock observed by this
 * process while preserving the caller's original offset-bearing value.
 */
function requireObservedLifecycleTimestamp(options) {
    const observedAt = options.observedAt ?? new Date(Date.now()).toISOString();
    const value = typeof options.value === 'string' ? options.value.trim() : options.value;
    if (typeof value !== 'string' || !(0, task_lifecycle_1.isTaskLifecycleTimestamp)(value)) {
        throw new TaskLifecycleTimestampValidationError({
            code: 'invalid-timestamp',
            message: `${options.label} must be an ISO-8601 timestamp with an explicit timezone.`,
            field: options.field,
            suppliedTimestamp: options.value,
            normalizedInstant: null,
            observedAt,
            differenceMs: null,
            notBefore: options.notBefore ?? null,
        });
    }
    const eventAtMs = Date.parse(value);
    const observedAtMs = Date.parse(observedAt);
    const normalizedInstant = new Date(eventAtMs).toISOString();
    if (!Number.isFinite(observedAtMs)) {
        throw new TypeError(`Observed lifecycle clock '${observedAt}' is invalid.`);
    }
    if (eventAtMs > observedAtMs) {
        const differenceMs = eventAtMs - observedAtMs;
        throw new TaskLifecycleTimestampValidationError({
            code: 'timestamp-in-future',
            message: `${options.label} '${value}' resolves to '${normalizedInstant}', but the command observed '${observedAt}' (${differenceMs} ms in the future). No lifecycle writes were performed.`,
            field: options.field,
            suppliedTimestamp: value,
            normalizedInstant,
            observedAt,
            differenceMs,
            notBefore: options.notBefore ?? null,
        });
    }
    if (options.notBefore !== undefined && options.notBefore !== null) {
        const notBeforeMs = Date.parse(options.notBefore);
        if (!Number.isFinite(notBeforeMs)) {
            throw new TypeError(`Lifecycle lower bound '${options.notBefore}' is invalid.`);
        }
        if (eventAtMs < notBeforeMs) {
            throw new TaskLifecycleTimestampValidationError({
                code: 'before-lower-bound',
                message: `${options.label} cannot precede ${options.notBeforeLabel ?? 'the required lifecycle lower bound'} '${options.notBefore}'.`,
                field: options.field,
                suppliedTimestamp: value,
                normalizedInstant,
                observedAt,
                differenceMs: eventAtMs - notBeforeMs,
                notBefore: options.notBefore,
            });
        }
    }
    return value;
}
function revalidateObservedLifecycleTimestamp(value, field, label) {
    requireObservedLifecycleTimestamp({ value, field, label });
}
