"use client";
import { useCallback, useMemo, useRef, useState } from "react";
import { FileDecisionScope } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
import { create } from "@bufbuild/protobuf";
import { CancelWorkflowExecutionInputSchema, TerminateWorkflowExecutionInputSchema, PauseWorkflowExecutionInputSchema, ResumeWorkflowExecutionInputSchema, RecoverWorkflowExecutionInputSchema, SubmitWorkflowApprovalInputSchema, SubmitWorkflowTaskApprovalInputSchema, SubmitWorkflowFileDecisionInputSchema, } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/io_pb";
import { useStigmer } from "../hooks.js";
import { toError } from "../internal/toError.js";
import { useKeyedSubmission } from "../internal/useKeyedSubmission.js";
import { fileDecisionKey } from "../execution/useFileReview.js";
/**
 * Behavior hook that encapsulates workflow execution lifecycle actions.
 *
 * Each action calls the corresponding RPC and returns the updated
 * execution, or `null` on failure (with `error` populated).
 *
 * Pass `null` for `executionId` to disable all actions (they become
 * no-ops that return `null`).
 *
 * @example
 * ```tsx
 * const actions = useWorkflowExecutionActions(executionId, {
 *   onSuccess: () => refetchExecution(),
 * });
 *
 * <button onClick={() => actions.cancel("No longer needed")} disabled={actions.isSubmitting}>
 *   Cancel
 * </button>
 * ```
 */
export function useWorkflowExecutionActions(executionId, options) {
    const stigmer = useStigmer();
    const [isSubmitting, setIsSubmitting] = useState(false);
    const [error, setError] = useState(null);
    // Approvals are per-gate (a workflow can hold many at once), so each kind gets
    // its own keyed in-flight + error state — keyed by tool-call id for agent-tool
    // approvals and by task name for human_input task approvals. The lifecycle
    // actions below stay on the shared scalar (they are header singletons).
    const approvals = useKeyedSubmission();
    const taskApprovals = useKeyedSubmission();
    const fileDecisions = useKeyedSubmission();
    const executionIdRef = useRef(executionId);
    executionIdRef.current = executionId;
    const stigmerRef = useRef(stigmer);
    stigmerRef.current = stigmer;
    const onSuccessRef = useRef(options?.onSuccess);
    onSuccessRef.current = options?.onSuccess;
    const clearError = useCallback(() => setError(null), []);
    const wrap = useCallback(async (fn, fireOnSuccess = true) => {
        if (!executionIdRef.current)
            return null;
        setIsSubmitting(true);
        setError(null);
        try {
            const result = await fn();
            if (fireOnSuccess)
                onSuccessRef.current?.(result);
            return result;
        }
        catch (err) {
            setError(toError(err));
            return null;
        }
        finally {
            setIsSubmitting(false);
        }
    }, []);
    const cancel = useCallback((reason) => wrap(() => stigmerRef.current.workflowExecution.cancel(create(CancelWorkflowExecutionInputSchema, {
        id: executionIdRef.current,
        reason: reason ?? "",
    }))), [wrap]);
    const terminate = useCallback((reason) => wrap(() => stigmerRef.current.workflowExecution.terminate(create(TerminateWorkflowExecutionInputSchema, {
        id: executionIdRef.current,
        reason: reason ?? "",
    }))), [wrap]);
    const pause = useCallback((reason) => wrap(() => stigmerRef.current.workflowExecution.pause(create(PauseWorkflowExecutionInputSchema, {
        id: executionIdRef.current,
        reason: reason ?? "",
    }))), [wrap]);
    const resume = useCallback(() => wrap(() => stigmerRef.current.workflowExecution.resume(create(ResumeWorkflowExecutionInputSchema, {
        id: executionIdRef.current,
    }))), [wrap]);
    const recover = useCallback((reason) => wrap(() => stigmerRef.current.workflowExecution.recover(create(RecoverWorkflowExecutionInputSchema, {
        id: executionIdRef.current,
        reason: reason ?? "",
    }))), [wrap]);
    // Approvals do NOT go through `wrap`: their in-flight + error state is keyed
    // (per gate), and the keyed primitive re-throws after recording, so we swallow
    // to `null` here to keep the `WorkflowExecution | null` contract. They never
    // fire `onSuccess` — their effects arrive via the event stream.
    const submitApproval = useCallback((toolCallId, action, comment) => {
        if (!executionIdRef.current)
            return Promise.resolve(null);
        return approvals
            .run(toolCallId, () => stigmerRef.current.workflowExecution.submitApproval(create(SubmitWorkflowApprovalInputSchema, {
            executionId: executionIdRef.current,
            toolCallId,
            action,
            comment: comment ?? "",
        })))
            .catch(() => null);
    }, [approvals.run]);
    const submitTaskApproval = useCallback((taskName, outcome, formData, comment) => {
        if (!executionIdRef.current)
            return Promise.resolve(null);
        return taskApprovals
            .run(taskName, () => stigmerRef.current.workflowExecution.submitWorkflowTaskApproval(create(SubmitWorkflowTaskApprovalInputSchema, {
            executionId: executionIdRef.current,
            taskName,
            outcome,
            formData: formData,
            reviewer: "",
            comment: comment ?? "",
        })))
            .catch(() => null);
    }, [taskApprovals.run]);
    // File decisions are per-target (a workflow can surface many change sets across
    // parallel children), so they use the keyed primitive keyed exactly like
    // FileReviewCard expects (fileDecisionKey). Never fires onSuccess — the effect
    // arrives via the execution stream.
    const submitFileDecision = useCallback((childAgentExecutionId, changeSetId, action, options) => {
        if (!executionIdRef.current)
            return Promise.resolve(null);
        const fileChangeId = options?.fileChangeId ?? "";
        const scope = options?.scope ??
            (fileChangeId ? FileDecisionScope.FILE : FileDecisionScope.CHANGE_SET);
        const key = fileDecisionKey(changeSetId, fileChangeId || undefined);
        return fileDecisions
            .run(key, () => stigmerRef.current.workflowExecution.submitFileDecision(create(SubmitWorkflowFileDecisionInputSchema, {
            executionId: executionIdRef.current,
            childAgentExecutionId,
            changeSetId,
            scope,
            fileChangeId,
            action,
            expectedDigest: options?.expectedDigest ?? "",
            reason: options?.reason ?? "",
            acknowledgeUnreviewable: options?.acknowledgeUnreviewable ?? false,
        })))
            .catch(() => null);
    }, [fileDecisions.run]);
    return useMemo(() => ({
        cancel,
        terminate,
        pause,
        resume,
        recover,
        submitApproval,
        submitTaskApproval,
        submitFileDecision,
        isSubmitting,
        error,
        clearError,
        approvalSubmittingToolCallIds: approvals.submittingKeys,
        approvalErrorsByToolCallId: approvals.errorsByKey,
        taskApprovalSubmittingTaskNames: taskApprovals.submittingKeys,
        taskApprovalErrorsByTaskName: taskApprovals.errorsByKey,
        fileDecisionSubmittingKeys: fileDecisions.submittingKeys,
        fileDecisionErrorsByKey: fileDecisions.errorsByKey,
    }), [
        cancel,
        terminate,
        pause,
        resume,
        recover,
        submitApproval,
        submitTaskApproval,
        submitFileDecision,
        isSubmitting,
        error,
        clearError,
        approvals.submittingKeys,
        approvals.errorsByKey,
        taskApprovals.submittingKeys,
        taskApprovals.errorsByKey,
        fileDecisions.submittingKeys,
        fileDecisions.errorsByKey,
    ]);
}
//# sourceMappingURL=useWorkflowExecutionActions.js.map