"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useEffect, useRef, useState } from "react";
import { ExecutionArtifactKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
import { cn } from "@stigmer/theme";
import { useArtifactContent } from "./useArtifactContent";
import { isTextArtifact, formatArtifactSize } from "./artifact-utils";
import { ArtifactContentRenderer } from "./ArtifactContentRenderer";
import { useDetectStigmerResource } from "../library/useDetectStigmerResource";
import { useDetectSkillPackage } from "../library/useDetectSkillPackage";
import { useApplyResource, } from "../library/useApplyResource";
const COPIED_FEEDBACK_MS = 2000;
/**
 * Artifact preview content with detection pipeline and Apply/Push CTA.
 *
 * Renders the header (name, size, detection badge, close button),
 * content body (file content or directory listing), and action bar
 * (copy, download, Apply/Push). The parent is responsible for rendering
 * it inside a `<dialog>`, modal, sheet, overlay, or inline context as
 * needed.
 *
 * Orchestrates the same detection pipeline as {@link ArtifactCard}:
 *
 * - **FILE artifacts**: Fetches text content via {@link useArtifactContent},
 *   renders via {@link ArtifactContentRenderer} (markdown, YAML, JSON, or
 *   plain text based on file type), and detects Agent/McpServer resources
 *   via {@link useDetectStigmerResource}.
 *
 * - **DIRECTORY artifacts**: Shows the file listing from
 *   `artifact.entries` and detects skill packages via
 *   {@link useDetectSkillPackage}.
 *
 * Content fetching begins immediately on mount. Unmounting the component
 * resets all internal state (detection, apply result, clipboard). For
 * gated rendering (e.g. only when a dialog is open), conditionally
 * mount this component rather than passing an `active` flag.
 *
 * @example
 * ```tsx
 * // Inside a dialog, modal, or overlay:
 * <ArtifactPreviewContent
 *   artifact={artifact}
 *   executionId={execution.id}
 *   org={activeOrg}
 *   isTerminal={isTerminalPhase(execution.status?.phase)}
 *   onClose={() => setOpen(false)}
 *   onApplied={(result) => toast(`${result.kind} applied`)}
 * />
 * ```
 *
 * @see {@link ArtifactPreviewModal} — wraps this component in a native `<dialog>`
 * @see {@link ArtifactCard} — compact card that triggers preview via `onPreview`
 * @see {@link useArtifactContent} — content-fetching hook (headless alternative)
 * @see {@link useDetectStigmerResource} — YAML resource detection (headless)
 * @see {@link useDetectSkillPackage} — skill package detection (headless)
 * @see {@link useApplyResource} — apply/push behavior hook (headless)
 */
export function ArtifactPreviewContent({ artifact, executionId, org, isTerminal, onClose, onApplied, className, }) {
    const isDirectory = artifact.kind === ExecutionArtifactKind.DIRECTORY;
    const canFetchContent = !isDirectory && isTextArtifact(artifact);
    // ---------------------------------------------------------------------------
    // Detection orchestration
    // ---------------------------------------------------------------------------
    const { content, contentType, isTruncated, isLoading: isContentLoading, error: contentError, } = useArtifactContent(canFetchContent ? executionId : null, canFetchContent ? artifact.storageKey : null, undefined, artifact.contentHash || undefined);
    const yamlDetection = useDetectStigmerResource(canFetchContent ? content : null);
    const { detection: skillDetection, isLoading: isSkillLoading } = useDetectSkillPackage(isDirectory ? artifact : null, isDirectory ? executionId : null);
    // ---------------------------------------------------------------------------
    // Derived detection state
    // ---------------------------------------------------------------------------
    const isDetected = yamlDetection.detected || skillDetection.detected;
    const isDetecting = (canFetchContent && isContentLoading) || (isDirectory && isSkillLoading);
    let detectionLabel = null;
    if (yamlDetection.detected) {
        detectionLabel = `${yamlDetection.displayName} detected`;
    }
    else if (skillDetection.detected) {
        const count = skillDetection.fileCount;
        detectionLabel = `Skill \u00B7 ${count} ${count === 1 ? "file" : "files"}`;
    }
    // ---------------------------------------------------------------------------
    // Apply state
    // ---------------------------------------------------------------------------
    const { applyYamlResource, pushSkillPackage, isApplying, error: applyError, clearError, } = useApplyResource();
    const [applyResult, setApplyResult] = useState(null);
    const handleApply = useCallback(async () => {
        clearError();
        try {
            let result;
            if (yamlDetection.detected && content) {
                result = await applyYamlResource(content, org);
            }
            else if (skillDetection.detected) {
                result = await pushSkillPackage({
                    org,
                    executionId,
                    storageKey: artifact.storageKey,
                });
            }
            else {
                return;
            }
            setApplyResult(result);
            onApplied?.(result);
        }
        catch {
            // error state managed by useApplyResource
        }
    }, [
        yamlDetection.detected,
        skillDetection.detected,
        content,
        org,
        executionId,
        artifact.storageKey,
        applyYamlResource,
        pushSkillPackage,
        clearError,
        onApplied,
    ]);
    // ---------------------------------------------------------------------------
    // Copy to clipboard
    // ---------------------------------------------------------------------------
    const [copied, setCopied] = useState(false);
    const handleCopy = useCallback(() => {
        if (!content)
            return;
        navigator.clipboard.writeText(content).then(() => {
            setCopied(true);
            setTimeout(() => setCopied(false), COPIED_FEEDBACK_MS);
        });
    }, [content]);
    let ctaLabel = null;
    if (yamlDetection.detected) {
        ctaLabel = `Apply to ${org}`;
    }
    else if (skillDetection.detected) {
        ctaLabel = `Push Skill to ${org}`;
    }
    // ---------------------------------------------------------------------------
    // Render
    // ---------------------------------------------------------------------------
    return (_jsxs("div", { className: cn("flex max-h-[80vh] flex-col", className), children: [_jsx(ContentHeader, { artifact: artifact, isDirectory: isDirectory, detectionLabel: detectionLabel, isDetecting: isDetecting, onClose: onClose }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto border-t border-border", children: isDirectory ? (_jsx(DirectoryContentView, { artifact: artifact, skillDetection: skillDetection })) : (_jsx(FileContentStateView, { artifact: artifact, content: content, contentType: contentType, isLoading: isContentLoading, error: contentError, isTruncated: isTruncated })) }), _jsx(ActionBar, { artifact: artifact, isDirectory: isDirectory, hasContent: content !== null, copied: copied, onCopy: handleCopy, isDetected: isDetected, ctaLabel: ctaLabel, isTerminal: isTerminal, isApplying: isApplying, applyResult: applyResult, applyError: applyError, onApply: handleApply }), _jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: copied && "Content copied to clipboard" })] }));
}
/**
 * Full preview modal for execution artifacts using a native `<dialog>`.
 *
 * Thin shell around {@link ArtifactPreviewContent} that adds
 * `showModal()` / `close()` lifecycle, `::backdrop` overlay, focus
 * trap, and Escape key handling — with no dependency on
 * `@base-ui/react`.
 *
 * The content component is conditionally mounted when `open` is true,
 * so all internal state (detection, apply result, clipboard) resets
 * automatically when the dialog closes.
 *
 * @example
 * ```tsx
 * const [previewArtifact, setPreviewArtifact] =
 *   useState<ExecutionArtifact | null>(null);
 *
 * {previewArtifact && (
 *   <ArtifactPreviewModal
 *     artifact={previewArtifact}
 *     executionId={execution.id}
 *     org={activeOrg}
 *     isTerminal={isTerminalPhase(execution.status?.phase)}
 *     open
 *     onClose={() => setPreviewArtifact(null)}
 *     onApplied={(result) => toast(`${result.kind} applied`)}
 *   />
 * )}
 * ```
 *
 * @see {@link ArtifactPreviewContent} — the content component (use directly for non-dialog contexts)
 * @see {@link ArtifactCard} — compact card that triggers preview via `onPreview`
 */
export function ArtifactPreviewModal({ artifact, executionId, org, isTerminal, open, onClose, onApplied, className, }) {
    const dialogRef = useRef(null);
    useEffect(() => {
        const dialog = dialogRef.current;
        if (!dialog)
            return;
        if (open && !dialog.open) {
            dialog.showModal();
        }
        else if (!open && dialog.open) {
            dialog.close();
        }
    }, [open]);
    const handleCancel = useCallback((e) => {
        e.preventDefault();
        onClose();
    }, [onClose]);
    return (_jsx("dialog", { ref: dialogRef, onCancel: handleCancel, "aria-label": `Preview ${artifact.name}`, className: cn("fixed inset-0 m-auto w-full max-w-3xl rounded-lg border border-border bg-background p-0 text-foreground shadow-lg outline-none", "[&::backdrop]:bg-black/50", className), children: open && (_jsx(ArtifactPreviewContent, { artifact: artifact, executionId: executionId, org: org, isTerminal: isTerminal, onClose: onClose, onApplied: onApplied })) }));
}
// ---------------------------------------------------------------------------
// Shared style constants
// ---------------------------------------------------------------------------
const FOCUS_RING_CLASSES = "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:rounded-sm";
// ---------------------------------------------------------------------------
// ContentHeader (internal)
// ---------------------------------------------------------------------------
function ContentHeader({ artifact, isDirectory, detectionLabel, isDetecting, onClose, }) {
    return (_jsxs("div", { className: "flex items-start gap-3 p-4 pb-3", children: [_jsx("span", { className: "mt-0.5 shrink-0 text-muted-foreground", children: isDirectory ? _jsx(FolderIcon, {}) : _jsx(FileIcon, {}) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("h2", { className: "truncate text-sm font-semibold text-foreground", children: [artifact.name, isDirectory && "/"] }), _jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-xs tabular-nums text-muted-foreground", children: formatArtifactSize(artifact.sizeBytes) }), isDetecting && !detectionLabel && (_jsx("span", { className: "h-4 w-24 animate-pulse rounded-full bg-muted", "aria-hidden": "true" })), detectionLabel && (_jsx("span", { className: "inline-flex items-center rounded-full bg-primary-subtle px-2 py-0.5 text-xs font-medium text-primary", children: detectionLabel }))] })] }), _jsx("button", { type: "button", onClick: onClose, "aria-label": "Close preview", className: cn("shrink-0 rounded-sm p-1 text-muted-foreground transition-colors hover:text-foreground", FOCUS_RING_CLASSES), children: _jsx(CloseIcon, {}) })] }));
}
// ---------------------------------------------------------------------------
// FileContentStateView (internal — loading/error/empty states + renderer)
// ---------------------------------------------------------------------------
const SKELETON_LINE_WIDTHS = [85, 72, 90, 65, 78, 88, 70, 82];
function FileContentStateView({ artifact, content, contentType, isLoading, error, isTruncated, }) {
    if (isLoading) {
        return (_jsx("div", { className: "space-y-2 p-4", "aria-busy": "true", "aria-label": "Loading content", children: SKELETON_LINE_WIDTHS.map((width, i) => (_jsx("div", { className: "h-4 animate-pulse rounded bg-muted", style: { width: `${width}%` }, "aria-hidden": "true" }, i))) }));
    }
    if (error) {
        return (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 p-8 text-center", children: [_jsx(ErrorAlertIcon, {}), _jsx("p", { className: "text-sm text-destructive", children: error.message })] }));
    }
    if (content === null) {
        return (_jsx("div", { className: "p-8 text-center text-sm text-muted-foreground", children: "Content not available for preview." }));
    }
    return (_jsx(ArtifactContentRenderer, { content: content, fileName: artifact.name, contentType: contentType, isTruncated: isTruncated }));
}
// ---------------------------------------------------------------------------
// DirectoryContentView (internal)
// ---------------------------------------------------------------------------
function DirectoryContentView({ artifact, skillDetection, }) {
    const entries = artifact.entries;
    return (_jsxs("div", { className: "p-4", children: [skillDetection.detected && (_jsxs("div", { className: "mb-4 rounded-md bg-primary-subtle p-3", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: skillDetection.skillName }), skillDetection.skillDescription && (_jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: skillDetection.skillDescription }))] })), entries.length > 0 ? (_jsxs("div", { children: [_jsxs("h3", { className: "mb-2 text-xs font-medium text-muted-foreground", children: ["Files (", entries.length, ")"] }), _jsx("ul", { className: "space-y-0.5", role: "list", children: entries.map((entry) => (_jsxs("li", { className: "flex items-center gap-2 rounded-sm px-2 py-1 font-mono text-xs text-foreground", children: [_jsx(EntryIcon, { name: entry }), _jsx("span", { className: "min-w-0 truncate", children: entry })] }, entry))) })] })) : (_jsx("p", { className: "text-sm text-muted-foreground", children: "File listing not available." }))] }));
}
function EntryIcon({ name }) {
    if (name.endsWith("/"))
        return _jsx(FolderSmallIcon, {});
    return _jsx(FileSmallIcon, {});
}
// ---------------------------------------------------------------------------
// ActionBar (internal)
// ---------------------------------------------------------------------------
function ActionBar({ artifact, isDirectory, hasContent, copied, onCopy, isDetected, ctaLabel, isTerminal, isApplying, applyResult, applyError, onApply, }) {
    return (_jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-border px-4 py-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [!isDirectory && hasContent && (_jsxs("button", { type: "button", onClick: onCopy, "aria-label": copied ? "Copied to clipboard" : "Copy content", className: cn("inline-flex items-center gap-1.5 text-xs font-medium transition-colors", copied
                            ? "text-success"
                            : "text-muted-foreground hover:text-foreground", FOCUS_RING_CLASSES), children: [copied ? _jsx(CheckIcon, {}) : _jsx(CopyIcon, {}), copied ? "Copied" : "Copy"] })), _jsxs("a", { href: artifact.downloadUrl, download: true, className: cn("inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground", FOCUS_RING_CLASSES), children: [_jsx(DownloadIcon, {}), isDirectory ? "Download ZIP" : "Download"] })] }), _jsx("div", { className: "shrink-0", children: applyResult ? (_jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs font-medium text-success", children: [_jsx(CheckIcon, {}), "Applied ", "\u00B7", " ", applyResult.name || applyResult.kind] })) : applyError ? (_jsxs("span", { className: "inline-flex items-center gap-2", role: "alert", children: [_jsx("span", { className: "text-xs text-destructive", children: applyError.message }), _jsx("button", { type: "button", onClick: onApply, className: cn("text-xs font-medium text-destructive underline transition-colors hover:text-destructive-muted", FOCUS_RING_CLASSES), children: "Retry" })] })) : isDetected && ctaLabel ? (_jsx("span", { "data-cursor-target": "apply-resource-button", children: _jsx(ApplyButton, { label: ctaLabel, isTerminal: isTerminal, isApplying: isApplying, onApply: onApply }) })) : null })] }));
}
function ApplyButton({ label, isTerminal, isApplying, onApply, }) {
    const canApply = isTerminal && !isApplying;
    return (_jsx("button", { type: "button", onClick: canApply ? onApply : undefined, disabled: !canApply, "aria-busy": isApplying, className: cn("rounded-md px-4 py-1.5 text-xs font-medium transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", "disabled:cursor-not-allowed", canApply
            ? "bg-primary text-primary-foreground hover:bg-primary-hover"
            : "bg-muted text-muted-foreground"), children: isApplying ? (_jsxs("span", { className: "inline-flex items-center gap-1.5", children: [_jsx(SpinnerIcon, {}), "Applying", "\u2026"] })) : (label) }));
}
// ---------------------------------------------------------------------------
// Inline SVG icons (SDK pattern: no external icon dependency)
// ---------------------------------------------------------------------------
function CloseIcon() {
    return (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M3 3L11 11" }), _jsx("path", { d: "M11 3L3 11" })] }));
}
function FileIcon() {
    return (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M9.5 1.5H5C4.17 1.5 3.5 2.17 3.5 3V13C3.5 13.83 4.17 14.5 5 14.5H11C11.83 14.5 12.5 13.83 12.5 13V4.5L9.5 1.5Z" }), _jsx("path", { d: "M9.5 1.5V4.5H12.5" })] }));
}
function FolderIcon() {
    return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "M14.5 12.5C14.5 13.33 13.83 14 13 14H3C2.17 14 1.5 13.33 1.5 12.5V3.5C1.5 2.67 2.17 2 3 2H6L8 4.5H13C13.83 4.5 14.5 5.17 14.5 6V12.5Z" }) }));
}
function FileSmallIcon() {
    return (_jsxs("svg", { width: "12", height: "12", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0 text-muted-foreground", "aria-hidden": "true", children: [_jsx("path", { d: "M8 1H4C3.45 1 3 1.45 3 2V12C3 12.55 3.45 13 4 13H10C10.55 13 11 12.55 11 12V4L8 1Z" }), _jsx("path", { d: "M8 1V4H11" })] }));
}
function FolderSmallIcon() {
    return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0 text-muted-foreground", "aria-hidden": "true", children: _jsx("path", { d: "M13 11C13 11.55 12.55 12 12 12H2C1.45 12 1 11.55 1 11V3C1 2.45 1.45 2 2 2H5L7 4H12C12.55 4 13 4.45 13 5V11Z" }) }));
}
function CopyIcon() {
    return (_jsxs("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0", "aria-hidden": "true", children: [_jsx("rect", { x: "4", y: "4", width: "6.5", height: "6.5", rx: "1" }), _jsx("path", { d: "M8 4V2.5C8 1.95 7.55 1.5 7 1.5H2.5C1.95 1.5 1.5 1.95 1.5 2.5V7C1.5 7.55 1.95 8 2.5 8H4" })] }));
}
function DownloadIcon() {
    return (_jsxs("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0", "aria-hidden": "true", children: [_jsx("path", { d: "M6 1.5V8.5" }), _jsx("path", { d: "M3 6L6 9L9 6" }), _jsx("path", { d: "M2 10.5H10" })] }));
}
function CheckIcon() {
    return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0", "aria-hidden": "true", children: _jsx("path", { d: "M2 6.5L4.5 9L10 3" }) }));
}
function SpinnerIcon() {
    return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "1.5", className: "shrink-0 animate-spin", "aria-hidden": "true", children: _jsx("path", { d: "M6 1.5A4.5 4.5 0 1 1 1.5 6", strokeLinecap: "round" }) }));
}
function ErrorAlertIcon() {
    return (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "text-destructive", "aria-hidden": "true", children: [_jsx("circle", { cx: "8", cy: "8", r: "6.5" }), _jsx("path", { d: "M8 5.5V8.5" }), _jsx("circle", { cx: "8", cy: "11", r: "0.5", fill: "currentColor", stroke: "none" })] }));
}
//# sourceMappingURL=ArtifactPreviewModal.js.map