"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveRecurringLifecycleDecision = resolveRecurringLifecycleDecision;
exports.isRecurringAutoStopDue = isRecurringAutoStopDue;
exports.isRecurringLifecycleTaskDue = isRecurringLifecycleTaskDue;
exports.hasRecurringAutoStopRunLimitReached = hasRecurringAutoStopRunLimitReached;
exports.incrementRecurringChildCreationCount = incrementRecurringChildCreationCount;
exports.buildStoppedRecurringParentWorkflowState = buildStoppedRecurringParentWorkflowState;
exports.normalizePersistedRecurringState = normalizePersistedRecurringState;
exports.normalizeRecurringAutoStopState = normalizeRecurringAutoStopState;
exports.clearRecurringAutoStop = clearRecurringAutoStop;
exports.applyRecurringAutoStopCommand = applyRecurringAutoStopCommand;
const types_1 = require("./types");
const schedule_primitives_1 = require("./schedule-primitives");
function resolveRecurringLifecycleDecision(workflowState, now = new Date()) {
    if (workflowState === null ||
        workflowState === undefined ||
        workflowState.schedule === undefined ||
        workflowState.schedule.mode === "off") {
        return "inactive";
    }
    if (isRecurringAutoStopDue(workflowState, now)) {
        return "stop_due";
    }
    if ((0, schedule_primitives_1.isDueAt)(workflowState.nextRunAt, now)) {
        return "run_due";
    }
    return "wait";
}
function isRecurringAutoStopDue(workflowState, now = new Date()) {
    const autoStop = workflowState?.recurring?.autoStop;
    return ((autoStop?.stopAt ? (0, schedule_primitives_1.isDueAt)(autoStop.stopAt, now) : false) ||
        hasRecurringAutoStopRunLimitReached(workflowState));
}
function isRecurringLifecycleTaskDue(workflowState, now = new Date()) {
    const decision = resolveRecurringLifecycleDecision(workflowState, now);
    return decision === "run_due" || decision === "stop_due";
}
function hasRecurringAutoStopRunLimitReached(workflowState) {
    const autoStop = workflowState?.recurring?.autoStop;
    return (autoStop?.stopAfterRuns !== null &&
        autoStop?.stopAfterRuns !== undefined &&
        autoStop.createdChildIssueCount >= autoStop.stopAfterRuns);
}
function incrementRecurringChildCreationCount(workflowState) {
    const autoStop = workflowState.recurring?.autoStop;
    if (autoStop === undefined) {
        return workflowState;
    }
    return {
        ...workflowState,
        recurring: {
            kind: "parent",
            autoStop: {
                ...autoStop,
                createdChildIssueCount: autoStop.createdChildIssueCount + 1,
            },
        },
    };
}
function buildStoppedRecurringParentWorkflowState(workflowState) {
    const nextState = {
        ...workflowState,
        schedule: (0, types_1.createOffWorkflowScheduleState)(),
        nextRunAt: null,
        plan: null,
    };
    delete nextState.scheduledRun;
    delete nextState.recurring;
    delete nextState.executionOwnership;
    return nextState;
}
function normalizePersistedRecurringState(recurring) {
    const autoStop = normalizeRecurringAutoStopState(recurring.autoStop);
    return autoStop === undefined
        ? { kind: "parent" }
        : { kind: "parent", autoStop };
}
function normalizeRecurringAutoStopState(autoStop) {
    if (autoStop === undefined) {
        return undefined;
    }
    if (autoStop.stopAt === null && autoStop.stopAfterRuns === null) {
        return undefined;
    }
    return {
        stopAt: autoStop.stopAt,
        stopAfterRuns: autoStop.stopAfterRuns,
        createdChildIssueCount: autoStop.createdChildIssueCount,
    };
}
function clearRecurringAutoStop(recurring) {
    return recurring === undefined ? undefined : { kind: "parent" };
}
function applyRecurringAutoStopCommand(input) {
    if (input.command === undefined) {
        return { kind: "ok", workflowState: input.workflowState };
    }
    if (input.command.mode === "off") {
        const workflowState = { ...input.workflowState };
        const recurring = clearRecurringAutoStop(workflowState.recurring);
        if (recurring === undefined) {
            delete workflowState.recurring;
        }
        else {
            workflowState.recurring = recurring;
        }
        return {
            kind: "ok",
            workflowState,
        };
    }
    if (input.workflowState.schedule === undefined ||
        input.workflowState.schedule.mode === "off" ||
        input.workflowState.scheduledRun !== undefined) {
        return { kind: "invalid" };
    }
    const previous = input.workflowState.recurring?.autoStop;
    const nextStopAt = resolveNextStopAt({
        previousStopAt: previous?.stopAt ?? null,
        command: input.command,
        acceptedAt: input.acceptedAt,
        displayTimeZone: input.displayTimeZone,
    });
    if (nextStopAt === undefined) {
        return { kind: "invalid" };
    }
    const stopAfterRuns = input.command.stopAfterRuns !== undefined
        ? input.command.stopAfterRuns
        : (previous?.stopAfterRuns ?? null);
    const createdChildIssueCount = input.command.stopAfterRuns !== undefined
        ? 0
        : (previous?.createdChildIssueCount ?? 0);
    const autoStop = normalizeRecurringAutoStopState({
        stopAt: nextStopAt,
        stopAfterRuns,
        createdChildIssueCount,
    });
    return {
        kind: "ok",
        workflowState: {
            ...input.workflowState,
            recurring: autoStop === undefined
                ? { kind: "parent" }
                : { kind: "parent", autoStop },
        },
    };
}
function resolveNextStopAt(input) {
    if (input.command.stopAfter !== undefined) {
        return resolveFutureStopAt((0, schedule_primitives_1.resolveWorkflowRunAfter)(input.command.stopAfter, input.acceptedAt), input.acceptedAt);
    }
    if (input.command.stopAt !== undefined) {
        return resolveFutureStopAt((0, schedule_primitives_1.normalizeWorkflowRunAt)(input.command.stopAt, input.displayTimeZone), input.acceptedAt);
    }
    return input.previousStopAt;
}
function resolveFutureStopAt(stopAt, acceptedAt) {
    if (stopAt === null) {
        return undefined;
    }
    const stopAtMs = Date.parse(stopAt);
    const acceptedAtMs = Date.parse(acceptedAt);
    if (!Number.isFinite(stopAtMs) ||
        !Number.isFinite(acceptedAtMs) ||
        stopAtMs <= acceptedAtMs) {
        return undefined;
    }
    return new Date(stopAtMs).toISOString();
}
