import { useRef, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { IssueRecoveryAction } from "@paperclipai/shared";
import { isNativeWorkspaceExportRepairCause } from "@paperclipai/shared";
import { accessApi } from "../api/access";
import { issuesApi } from "../api/issues";
import { useDraftOwner, useDraftOwnerReader } from "../hooks/useDraftOwner";
import { canBoardResolveRecoveryAction, isRetainedWorkspaceExportCause } from "../lib/recovery-reconcile";
import { queryKeys } from "../lib/queryKeys";
import { classifySendFailure, pendingSendKeyFor, readPendingSend, writePendingSend } from "../lib/pending-send";
import { asObject, cn } from "../lib/utils";
import { createUuid } from "../lib/uuid";
import { Button } from "./ui/button";
/** Requests preservation; the existing worker owns stop, copyback and verification. */
export function WorkspaceExportRecovery({ action, className, issueId, companyId, showStatus = true }: {
className?: string; action: IssueRecoveryAction | null; issueId?: string; companyId?: string; showStatus?: boolean;
}) {
if (action && issueId && companyId && isRetainedExport(action, issueId, companyId)) {
return
{automatic ? "Restoring saved work…" : "Workspace recovery needs operator assistance. The agent’s result is saved."}
; } function isRetainedExport(action: IssueRecoveryAction, issueId: string, companyId: string) { return action.companyId === companyId && action.sourceIssueId === issueId && action.kind === "active_run_watchdog" && ["active", "escalated"].includes(action.status) && ["board", "system"].includes(action.ownerType) && isRetainedWorkspaceExportCause(action.cause) && typeof action.evidence.runId === "string" && action.evidence.runId.length > 0; } type RecoveryInput = { actionId: string; runId: string }; function RetainedFilesRecovery({ action, issueId, companyId, className }: { action: IssueRecoveryAction; issueId: string; companyId: string; className?: string; }) { const runId = action.evidence.runId as string; const owner = useDraftOwner(); const readOwner = useDraftOwnerReader(); const client = useQueryClient(); const busy = useRef(false); const [acknowledged, setAcknowledged] = useState(false); const [checkedUnconfirmed, setCheckedUnconfirmed] = useState(false); const [notice, setNotice] = useState{saved ? "Saved files recovered. Task recovery is still being checked." : failedReceipt ? "File recovery has not finished. The saved source remains protected." : restoring ? "Recovering saved files. Work remains paused until recovery is verified." : waiting ? "File recovery is queued. Waiting for verified saved files." : "The saved files need recovery before work can continue."}
{canMutate ? <> {current && retryable && !waiting && (!pending || unconfirmed && checkedUnconfirmed || confirmedFailedAttempt) ? : null} {waiting || unconfirmed || failedReceipt || source.isError || source.data && !current ? : null} {source.isPending ?Inspecting the recorded file source…
: null} {source.isError || check.isError || notice ?{notice ?? (check.error instanceof Error ? check.error.message : "File recovery could not be inspected. Check its status again.")}
: null} {current && recovery.status === "blocked" && (serverAcknowledged || recovery.retryable !== true) ?File recovery has not finished. The saved source remains protected; service assistance is needed.
: null} {source.data && !current ?The recorded source is unavailable or has changed. Inspect recovery before continuing.
: null} > : access.isError ?Task access could not be checked. Refresh before requesting file recovery.
: access.isPending || !owner ?Checking file recovery access…
:A board member with task access can request file recovery.
}