"use client";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useCallback, useRef, useEffect, useLayoutEffect, useMemo, } from "react";
import { Check, X, ArrowUp, ChevronDown, ChevronLeft, Lightbulb, LoaderCircle, } from "lucide-react";
import { Button } from "../../components/ui/button";
import { Badge } from "../../components/ui/badge";
import { Textarea } from "../../components/ui/textarea";
import { Popover, PopoverTrigger, PopoverContent, } from "../../components/ui/popover";
import { CloseButton } from "../../components/ui/close-button";
import { cn } from "../../lib/utils";
import { sanitizeSvg } from "../../lib/sanitize";
import { useEditContext } from "../client/editContext";
import { startAgent, closeAgent } from "../services/agentService";
import { subscribeAgent as subscribeAgentRegistry } from "../services/agentSubscriptionRegistry";
import { getAiTextEditPrompts, getEditorSettings, } from "../services/systemService";
import { loadAiProfiles } from "../services/aiService";
import { localStorageService } from "../services/localStorageService";
import { diffWords } from "diff";
// Default Profile ID for the Inline Text Editor profile
const DEFAULT_INLINE_TEXT_EDITOR_PROFILE_ID = "8e53c90c-2eac-476b-b03d-d0c2cfbbcd8a";
const AI_TEXT_EDIT_MODELS_STORAGE_KEY = "aiTextEdit.selectedModelIds";
const START_AGENT_TIMEOUT_MS = 15_000;
const INLINE_AI_DIALOG_VIEWPORT_PADDING = 16;
export function clampInlineAiDialogPosition(position, dialogSize, viewportSize, padding = INLINE_AI_DIALOG_VIEWPORT_PADDING) {
    const minX = Math.min(padding, viewportSize.width / 2);
    const minY = Math.min(padding, viewportSize.height / 2);
    const maxX = Math.max(minX, viewportSize.width - dialogSize.width - minX);
    const maxY = Math.max(minY, viewportSize.height - dialogSize.height - minY);
    return {
        x: Math.min(Math.max(position.x, minX), maxX),
        y: Math.min(Math.max(position.y, minY), maxY),
    };
}
/** Normalize profile ID to a stable key (lowercase, no braces) so storage works regardless of API casing. */
function normalizeProfileIdForStorage(profileId) {
    return profileId.replace(/^\{|\}$/g, "").toLowerCase();
}
function getStoredModelIds(profileId) {
    try {
        const parsed = localStorageService.getItem(AI_TEXT_EDIT_MODELS_STORAGE_KEY);
        if (!parsed)
            return null;
        const normalizedKey = normalizeProfileIdForStorage(profileId);
        // Prefer exact normalized key, then find any key that normalizes to the same
        let ids = parsed?.[normalizedKey] ?? null;
        if (!ids && parsed && typeof parsed === "object") {
            for (const key of Object.keys(parsed)) {
                if (normalizeProfileIdForStorage(key) === normalizedKey) {
                    ids = parsed[key] ?? null;
                    break;
                }
            }
        }
        return Array.isArray(ids) ? ids : null;
    }
    catch {
        return null;
    }
}
function setStoredModelIds(profileId, modelIds) {
    try {
        const parsed = localStorageService.getItem(AI_TEXT_EDIT_MODELS_STORAGE_KEY) || {};
        const normalizedKey = normalizeProfileIdForStorage(profileId);
        // Merge: keep other profiles' keys as-is, but normalize keys we care about so we don't accumulate duplicates
        const data = {};
        const seen = new Set();
        for (const key of Object.keys(parsed)) {
            const n = normalizeProfileIdForStorage(key);
            if (seen.has(n))
                continue;
            seen.add(n);
            data[n] = parsed[key] ?? [];
        }
        data[normalizedKey] = modelIds;
        localStorageService.setItem(AI_TEXT_EDIT_MODELS_STORAGE_KEY, data);
    }
    catch {
        // ignore
    }
}
function isActiveModelRunStatus(status) {
    return (status === "pending" || status === "thinking" || status === "streaming");
}
const AI_TEXT_EDIT_SINGLE_RESPONSE_FORMAT_INSTRUCTION = `Return ONLY valid JSON (no markdown, no code fences, no extra text).
Use exactly one of these shapes:
{"replacementText":"<the modified text>"}
{"error":"<short explanation of why you cannot complete this request>"}`;
function normalizeAiTextEditResultCount(resultCount) {
    return typeof resultCount === "number" && Number.isFinite(resultCount)
        ? Math.max(1, Math.min(20, Math.floor(resultCount)))
        : 1;
}
function getAiTextEditResponseFormatInstruction(resultCount) {
    const normalizedResultCount = normalizeAiTextEditResultCount(resultCount);
    if (normalizedResultCount <= 1) {
        return AI_TEXT_EDIT_SINGLE_RESPONSE_FORMAT_INSTRUCTION;
    }
    return `Return ONLY valid JSON (no markdown, no code fences, no extra text).
Use exactly one of these shapes:
{"replacementTexts":["<result 1>","<result 2>"]}
{"error":"<short explanation of why you cannot complete this request>"}
Return exactly ${normalizedResultCount} results in replacementTexts. Each array item must be a complete standalone replacement/insert text. Do not include numbering or bullets inside the values.`;
}
function extractJsonObjectCandidates(input) {
    const candidates = [];
    for (let start = input.indexOf("{"); start >= 0; start = input.indexOf("{", start + 1)) {
        let depth = 0;
        let inString = false;
        let escaped = false;
        for (let i = start; i < input.length; i++) {
            const ch = input[i];
            if (inString) {
                if (escaped) {
                    escaped = false;
                }
                else if (ch === "\\") {
                    escaped = true;
                }
                else if (ch === '"') {
                    inString = false;
                }
                continue;
            }
            if (ch === '"') {
                inString = true;
                continue;
            }
            if (ch === "{")
                depth++;
            if (ch === "}") {
                depth--;
                if (depth === 0) {
                    candidates.push(input.slice(start, i + 1));
                    break;
                }
            }
        }
    }
    return candidates;
}
function cleanAgentResponse(raw) {
    return raw
        .trim()
        .replace(/^```[\s\S]*?\n/, "")
        .replace(/\n```$/, "")
        .trim();
}
/**
 * Extract just the human-readable text from a (possibly incomplete) streaming
 * agent response. Strips the markdown fence and pulls the in-progress value of
 * the `replacementText` JSON field so the user sees only the generated text,
 * not the surrounding JSON envelope.
 */
function extractStreamingPreview(raw) {
    const cleaned = cleanAgentResponse(raw);
    if (!cleaned)
        return "";
    const keyMatch = cleaned.match(/"replacementText"\s*:\s*"/);
    if (!keyMatch || keyMatch.index === undefined) {
        // No replacementText field yet — show nothing rather than partial JSON.
        return "";
    }
    const start = keyMatch.index + keyMatch[0].length;
    let i = start;
    let escaped = false;
    while (i < cleaned.length) {
        const ch = cleaned[i];
        if (escaped) {
            escaped = false;
            i++;
            continue;
        }
        if (ch === "\\") {
            escaped = true;
            i++;
            continue;
        }
        if (ch === '"')
            break;
        i++;
    }
    let body = cleaned.slice(start, i);
    // Drop a trailing lone backslash that would make JSON.parse fail mid-stream.
    if (escaped)
        body = body.slice(0, -1);
    try {
        return JSON.parse('"' + body + '"');
    }
    catch {
        return body;
    }
}
function coerceAiTextEditResponse(parsed) {
    const parsedObj = parsed;
    if (!parsedObj || typeof parsedObj !== "object") {
        return null;
    }
    if (typeof parsedObj.error === "string" &&
        parsedObj.error.trim().length > 0) {
        return { error: parsedObj.error.trim() };
    }
    if (typeof parsedObj.replacementText === "string") {
        return { replacementText: parsedObj.replacementText };
    }
    if (Array.isArray(parsedObj.replacementTexts)) {
        const replacementTexts = parsedObj.replacementTexts.filter((value) => typeof value === "string");
        if (replacementTexts.length > 0) {
            return { replacementTexts };
        }
    }
    return null;
}
function tryParseAiTextEditJson(json) {
    try {
        let parsed = JSON.parse(json);
        // Some models return JSON wrapped as a JSON string; parse one extra level.
        if (typeof parsed === "string") {
            const reparsed = JSON.parse(parsed);
            parsed = reparsed;
        }
        return coerceAiTextEditResponse(parsed);
    }
    catch {
        return null;
    }
}
export function parseAiTextEditResponse(raw) {
    const cleaned = cleanAgentResponse(raw);
    if (!cleaned) {
        return { error: "AI returned an empty response." };
    }
    const parsedStrict = tryParseAiTextEditJson(cleaned);
    if (parsedStrict) {
        return parsedStrict;
    }
    if (cleaned.trim().startsWith("{")) {
        try {
            const parsed = JSON.parse(cleaned);
            if (!parsed || typeof parsed !== "object") {
                return { error: "AI returned an invalid response format." };
            }
            return {
                error: "AI response is missing `replacementText`, `replacementTexts`, or `error`.",
            };
        }
        catch {
            // Fall through to candidate extraction for mixed prose/JSON responses.
        }
    }
    const candidates = extractJsonObjectCandidates(cleaned);
    for (const candidate of candidates) {
        const recovered = tryParseAiTextEditJson(candidate);
        if (recovered) {
            return recovered;
        }
    }
    if (cleaned && !cleaned.includes("{")) {
        return { error: cleaned.slice(0, 300) };
    }
    return { error: "AI returned invalid JSON. Please try again." };
}
function extractAgentErrorMessage(message) {
    const payload = message?.payload ?? {};
    const payloadData = payload?.data ?? {};
    const candidates = [
        payload?.error,
        payload?.Error,
        payload?.message,
        payload?.Message,
        payload?.statusMessage,
        payload?.StatusMessage,
        payloadData?.error,
        payloadData?.Error,
        payloadData?.message,
        payloadData?.Message,
        payloadData?.statusMessage,
        payloadData?.StatusMessage,
        message?.data?.error,
    ];
    for (const candidate of candidates) {
        if (typeof candidate === "string" && candidate.trim()) {
            return candidate.trim();
        }
    }
    return null;
}
function withTimeout(promise, timeoutMs, timeoutMessage) {
    return new Promise((resolve, reject) => {
        const timeoutId = window.setTimeout(() => {
            reject(new Error(timeoutMessage));
        }, timeoutMs);
        promise.then((value) => {
            window.clearTimeout(timeoutId);
            resolve(value);
        }, (error) => {
            window.clearTimeout(timeoutId);
            reject(error);
        });
    });
}
/**
 * Shared instruction box: a rounded composer with the send button inside the
 * textarea shell and the model selector below it.
 */
function InstructionComposer({ inputRef, value, onChange, onSubmit, onKeyDown, placeholder, minHeightClass, submitTitle, canSubmit, models, hasMultipleModels, modelPopoverOpen, onModelPopoverOpenChange, selectedModelIds, selectedModelsCount, selectedModelSummary, onToggleModel, onFocusChange, }) {
    const formRef = useRef(null);
    const [focused, setFocused] = useState(false);
    // Single line at rest; grows to its full height while focused or holding text.
    const isExpanded = focused || value.trim().length > 0;
    // Report focus up so the popover width follows the custom prompt field.
    useEffect(() => {
        onFocusChange?.(focused);
    }, [focused, onFocusChange]);
    useEffect(() => {
        return () => onFocusChange?.(false);
    }, [onFocusChange]);
    // Collapse again once focus leaves the composer entirely. Interactions with the
    // footer controls or the (portaled) model popover keep it expanded.
    const handleBlur = () => {
        window.setTimeout(() => {
            const active = document.activeElement;
            if (formRef.current?.contains(active ?? null) ||
                (active instanceof Element &&
                    active.closest("[data-radix-popper-content-wrapper]"))) {
                return;
            }
            setFocused(false);
        }, 0);
    };
    return (_jsx("form", { ref: formRef, onSubmit: (event) => {
            event.preventDefault();
            onSubmit();
        }, className: "w-full", children: _jsx("div", { className: "flex w-full items-start gap-2", children: _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-2", children: [_jsxs("div", { className: "border-border-default focus-within:border-neutral-grey-100 focus-within:ring-neutral-grey-100/10 bg-neutral-grey-5/30 relative min-w-0 overflow-hidden rounded-[12px] border transition-colors duration-200 focus-within:ring-4", children: [_jsx(Textarea, { ref: inputRef, value: value, onChange: (event) => onChange(event.target.value), onKeyDown: onKeyDown, onFocus: () => setFocused(true), onBlur: handleBlur, placeholder: placeholder, rows: 1, className: cn("w-full resize-none rounded-none border-0 bg-transparent px-2 pr-11 text-xs shadow-none transition-colors duration-200 outline-none focus-visible:border-0 focus-visible:shadow-none", isExpanded
                                    ? `${minHeightClass} pt-3 pb-10 leading-normal`
                                    : "h-8 min-h-0 py-0 leading-8") }), _jsx("button", { type: "submit", disabled: !canSubmit, className: cn("absolute right-1.5 flex h-6 w-6 items-center justify-center rounded-[4px] p-0 transition-colors duration-200", isExpanded ? "bottom-1.5" : "top-1", canSubmit
                                    ? "bg-neutral-grey-100 hover:bg-neutral-grey-100/90 text-white"
                                    : "bg-neutral-grey-5 text-neutral-grey-50 cursor-not-allowed"), title: submitTitle, children: _jsx(ArrowUp, { strokeWidth: 1, className: "h-4 w-4" }) })] }), hasMultipleModels && (_jsx("div", { className: "flex items-center overflow-hidden", children: _jsxs(Popover, { open: modelPopoverOpen, onOpenChange: onModelPopoverOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn("inline-flex items-center gap-1 rounded-[4px] px-2 py-1.5 text-[11px] font-medium transition-colors duration-200", "text-neutral-grey-50 hover:text-neutral-grey-100 hover:bg-neutral-grey-5", modelPopoverOpen &&
                                            "text-neutral-grey-100 bg-neutral-grey-5"), title: selectedModelSummary
                                            ? `Models: ${selectedModelSummary}`
                                            : "Choose models", children: [_jsx("span", { className: "max-w-[150px] truncate", children: selectedModelSummary ?? "Choose models" }), _jsx(ChevronDown, { strokeWidth: 1, className: "h-3 w-3" })] }) }), _jsxs(PopoverContent, { className: "w-56 p-1.5", align: "start", sideOffset: 8, children: [_jsxs("div", { className: "badge-pad flex items-center justify-between", children: [_jsx("span", { className: "text-neutral-grey-50 text-[10px] font-medium tracking-wider", children: "Models" }), _jsxs("span", { className: "text-neutral-grey-100 text-[10px] font-medium", children: [selectedModelsCount, " selected"] })] }), _jsx("div", { className: "space-y-0.5", children: models.map((model) => (_jsxs("button", { type: "button", onClick: () => onToggleModel(model.id), className: cn("flex w-full items-center gap-2 rounded-[4px] px-2 py-1.5 text-left text-xs transition-colors", selectedModelIds.includes(model.id)
                                                    ? "bg-neutral-grey-5 text-neutral-grey-100"
                                                    : "text-neutral-grey-50 hover:bg-neutral-grey-5"), children: [_jsx("span", { className: cn("flex h-3.5 w-3.5 items-center justify-center rounded border", selectedModelIds.includes(model.id)
                                                            ? "border-neutral-grey-100 bg-neutral-grey-100 text-white"
                                                            : "border-border-default bg-white text-transparent"), children: _jsx(Check, { strokeWidth: 1, className: "h-3 w-3" }) }), model.name] }, model.id))) })] })] }) }))] }) }) }));
}
export function InlineAiDialog({ selectedText = "", contextBefore, contextAfter, onAccept, onClose, position, className, }) {
    const editContext = useEditContext();
    const [state, setState] = useState("input");
    const [instruction, setInstruction] = useState("");
    const [error, setError] = useState(null);
    const [conversationHistory, setConversationHistory] = useState([]);
    const [quickActions, setQuickActions] = useState([]);
    const [profileId, setProfileId] = useState(DEFAULT_INLINE_TEXT_EDITOR_PROFILE_ID);
    const [activeProfile, setActiveProfile] = useState(undefined);
    const [selectedModelIds, setSelectedModelIds] = useState([]);
    const [modelRuns, setModelRuns] = useState({});
    const inputRef = useRef(null);
    const dialogRef = useRef(null);
    const [adjustedPosition, setAdjustedPosition] = useState(position);
    const keepDialogInViewport = useCallback(() => {
        if (!position || !dialogRef.current)
            return;
        const rect = dialogRef.current.getBoundingClientRect();
        const nextPosition = clampInlineAiDialogPosition(position, { width: rect.width, height: rect.height }, { width: window.innerWidth, height: window.innerHeight });
        setAdjustedPosition((currentPosition) => currentPosition?.x === nextPosition.x &&
            currentPosition?.y === nextPosition.y
            ? currentPosition
            : nextPosition);
    }, [position]);
    useLayoutEffect(() => {
        if (!position || !dialogRef.current) {
            setAdjustedPosition(position);
            return;
        }
        keepDialogInViewport();
        const resizeObserver = typeof ResizeObserver === "undefined"
            ? null
            : new ResizeObserver(keepDialogInViewport);
        resizeObserver?.observe(dialogRef.current);
        window.addEventListener("resize", keepDialogInViewport);
        return () => {
            resizeObserver?.disconnect();
            window.removeEventListener("resize", keepDialogInViewport);
        };
    }, [keepDialogInViewport, position]);
    // Agent state for the current multi-model run
    const activeAgentIdsRef = useRef(new Set());
    const unsubscribeRef = useRef(null);
    const modelRunsRef = useRef({});
    const latestRawContentRef = useRef({});
    const lastParsedRawRef = useRef({});
    // Model popover state
    const [modelPopoverOpen, setModelPopoverOpen] = useState(false);
    // Whether the custom-prompt composer is focused, so the popover can grow with it.
    const [promptFocused, setPromptFocused] = useState(false);
    // ALT+letter quick select state
    const [altSearchBuffer, setAltSearchBuffer] = useState("");
    const [isAltPressed, setIsAltPressed] = useState(false);
    const altSearchTimeoutRef = useRef(null);
    // Available models from the profile
    const availableModels = activeProfile?.models || [];
    const hasMultipleModels = availableModels.length > 1;
    // Build the selected model list (fallback to first model if somehow stale)
    const selectedModels = useMemo(() => {
        if (!availableModels.length)
            return [];
        const byId = new Map(availableModels.map((m) => [m.id, m]));
        const selected = selectedModelIds
            .map((id) => byId.get(id))
            .filter(Boolean);
        return selected;
    }, [selectedModelIds, availableModels]);
    const selectedModelSummary = useMemo(() => {
        if (!selectedModels.length)
            return null;
        if (selectedModels.length === 1)
            return selectedModels[0]?.name || null;
        return `${selectedModels.length} models selected`;
    }, [selectedModels]);
    useEffect(() => {
        const loadSettings = async () => {
            try {
                const [promptsResult, settingsResult] = await Promise.all([
                    getAiTextEditPrompts(),
                    getEditorSettings(),
                ]);
                if (promptsResult.type === "success" &&
                    promptsResult.data &&
                    promptsResult.data.length > 0) {
                    setQuickActions(promptsResult.data);
                }
                if (settingsResult.type === "success" &&
                    settingsResult.data?.aiTextEditProfileId) {
                    setProfileId(settingsResult.data.aiTextEditProfileId);
                }
            }
            catch (err) {
                console.error("[InlineAiDialog] Error loading settings:", err);
            }
        };
        loadSettings();
    }, []);
    // Load the profile when profileId changes to get available models
    useEffect(() => {
        const loadProfile = async () => {
            if (!profileId)
                return;
            try {
                const profiles = await loadAiProfiles();
                const normalizedProfileId = normalizeProfileIdForStorage(profileId);
                const profile = profiles.find((p) => normalizeProfileIdForStorage(p.id) === normalizedProfileId);
                if (profile) {
                    setActiveProfile(profile);
                    const availableModelIds = new Set((profile.models ?? []).map((m) => m.id));
                    const defaultModelId = profile.defaultModelId || profile.models?.[0]?.id;
                    const stored = getStoredModelIds(profileId);
                    const validStored = stored?.filter((id) => availableModelIds.has(id));
                    if (stored && stored.length === 0) {
                        setSelectedModelIds([]);
                    }
                    else if (validStored?.length) {
                        setSelectedModelIds(validStored);
                    }
                    else if (defaultModelId) {
                        setSelectedModelIds([defaultModelId]);
                    }
                }
            }
            catch (err) {
                console.error("[InlineAiDialog] Error loading profile:", err);
            }
        };
        loadProfile();
    }, [profileId]);
    useEffect(() => {
        modelRunsRef.current = modelRuns;
    }, [modelRuns]);
    // Persist model selection to localStorage when it or profileId changes
    useEffect(() => {
        if (profileId && activeProfile) {
            setStoredModelIds(profileId, selectedModelIds);
        }
    }, [profileId, activeProfile, selectedModelIds]);
    // The custom-prompt composer starts collapsed (single line) and expands on
    // focus, so the input is intentionally not auto-focused on mount.
    const evaluateRunCompletion = useCallback((runs) => {
        const values = Object.values(runs);
        if (!values.length)
            return;
        const allTerminal = values.every((run) => run.status === "done" || run.status === "error");
        if (!allTerminal)
            return;
        const doneRuns = values.filter((run) => run.status === "done" &&
            (run.replacementTexts?.length || run.replacementText?.length));
        if (doneRuns.length === 0) {
            setError("All selected models failed. See each model’s card for details. You can retry or change your instruction.");
            // Stay in preview so the user sees per-model error cards and can Retry/Discard
            return;
        }
        setError(null);
        // State is already "preview" – we show results side-by-side as they stream in
    }, []);
    const updateModelRun = useCallback((agentId, updater) => {
        setModelRuns((prev) => {
            const current = prev[agentId];
            if (!current)
                return prev;
            const updated = updater(current);
            const next = { ...prev, [agentId]: updated };
            modelRunsRef.current = next;
            evaluateRunCompletion(next);
            return next;
        });
    }, [evaluateRunCompletion]);
    // Routed through agentSubscriptionRegistry so a single server subscription
    // is shared across panes / dialogs / async helpers.
    const subscriptionReleasesRef = useRef(new Map());
    const subscribeAgentInline = useCallback((agentId) => {
        if (subscriptionReleasesRef.current.has(agentId))
            return;
        subscriptionReleasesRef.current.set(agentId, subscribeAgentRegistry(agentId));
    }, []);
    const unsubscribeAllAgents = useCallback(() => {
        for (const release of subscriptionReleasesRef.current.values()) {
            release();
        }
        subscriptionReleasesRef.current.clear();
    }, []);
    const closeAllActiveAgents = useCallback(() => {
        for (const agentId of activeAgentIdsRef.current) {
            closeAgent(agentId).catch(() => { });
        }
        activeAgentIdsRef.current.clear();
        latestRawContentRef.current = {};
        lastParsedRawRef.current = {};
    }, []);
    // Cleanup on unmount
    useEffect(() => {
        return () => {
            unsubscribeAllAgents();
            if (unsubscribeRef.current) {
                unsubscribeRef.current();
            }
            closeAllActiveAgents();
        };
    }, [unsubscribeAllAgents, closeAllActiveAgents]);
    const ensureSocketListener = useCallback(() => {
        if (!editContext?.addSocketMessageListener || unsubscribeRef.current) {
            return;
        }
        const handleMessage = (message) => {
            const messageAgentId = message.agentId || message.payload?.agentId;
            if (!messageAgentId || !activeAgentIdsRef.current.has(messageAgentId)) {
                return;
            }
            const msgType = message.type;
            if (msgType === "agent:run:delta") {
                const deltaData = message.payload?.data;
                const content = deltaData?.deltaContent || "";
                const isIncremental = deltaData?.isIncremental !== false;
                if (!content)
                    return;
                const previousRaw = latestRawContentRef.current[messageAgentId] || "";
                const nextRaw = isIncremental ? previousRaw + content : content;
                latestRawContentRef.current[messageAgentId] = nextRaw;
                const existingRun = modelRunsRef.current[messageAgentId];
                if (existingRun) {
                    modelRunsRef.current = {
                        ...modelRunsRef.current,
                        [messageAgentId]: {
                            ...existingRun,
                            status: "streaming",
                            rawContent: nextRaw,
                        },
                    };
                }
                updateModelRun(messageAgentId, (current) => {
                    const nextRawContent = isIncremental
                        ? current.rawContent + content
                        : content;
                    return {
                        ...current,
                        status: "streaming",
                        rawContent: nextRawContent,
                    };
                });
            }
            else if (msgType === "agent:run:status" ||
                msgType === "agent:status:update") {
                const statusData = message.payload?.data || message.payload || {};
                const normalizedStatus = (statusData.state || statusData.status || "")
                    .toString()
                    .toLowerCase();
                if (normalizedStatus === "error") {
                    const errorMsg = extractAgentErrorMessage(message) ||
                        "AI could not complete this request.";
                    updateModelRun(messageAgentId, (current) => {
                        if (current.status === "done")
                            return current; // don't overwrite success
                        return { ...current, status: "error", error: errorMsg };
                    });
                }
                else if (normalizedStatus === "running" ||
                    normalizedStatus === "thinking" ||
                    normalizedStatus === "streamopen" ||
                    normalizedStatus === "executingtoolcalls" ||
                    normalizedStatus === "toolapprovalgranted" ||
                    normalizedStatus === "toolapprovalrejected") {
                    updateModelRun(messageAgentId, (current) => {
                        if (current.status !== "pending")
                            return current;
                        return { ...current, status: "thinking" };
                    });
                }
            }
            else if (msgType === "agent:run:error" || msgType === "agent:error") {
                const errorMsg = extractAgentErrorMessage(message) ||
                    "AI could not complete this request.";
                updateModelRun(messageAgentId, (current) => {
                    if (current.status === "done")
                        return current; // don't overwrite success
                    return { ...current, status: "error", error: errorMsg };
                });
            }
            else if (msgType === "agent:message:complete" ||
                msgType === "agent:run:complete") {
                const lifecycleError = extractAgentErrorMessage(message);
                if (lifecycleError) {
                    updateModelRun(messageAgentId, (current) => ({
                        ...current,
                        status: "error",
                        error: lifecycleError,
                    }));
                    return;
                }
                const current = modelRunsRef.current[messageAgentId];
                const rawContentToParse = latestRawContentRef.current[messageAgentId] ??
                    current?.rawContent ??
                    "";
                if (lastParsedRawRef.current[messageAgentId] === rawContentToParse) {
                    return;
                }
                lastParsedRawRef.current[messageAgentId] = rawContentToParse;
                const parsed = parseAiTextEditResponse(rawContentToParse);
                if (parsed.error) {
                    updateModelRun(messageAgentId, (run) => ({
                        ...run,
                        status: "error",
                        error: parsed.error,
                    }));
                }
                else {
                    const replacementTexts = parsed.replacementTexts ??
                        (parsed.replacementText != null ? [parsed.replacementText] : []);
                    updateModelRun(messageAgentId, (run) => ({
                        ...run,
                        status: "done",
                        replacementText: replacementTexts[0] ?? "",
                        replacementTexts,
                        error: undefined,
                    }));
                }
            }
        };
        unsubscribeRef.current =
            editContext.addSocketMessageListener(handleMessage);
    }, [editContext, updateModelRun]);
    const executeAiModification = useCallback(async (customInstruction, resultCount = 1) => {
        if (!editContext)
            return;
        if (!selectedModels.length) {
            setError("Select at least one model.");
            return;
        }
        setError(null);
        setModelRuns({});
        modelRunsRef.current = {};
        latestRawContentRef.current = {};
        lastParsedRawRef.current = {};
        unsubscribeAllAgents();
        closeAllActiveAgents();
        try {
            // Build the message with context around the selection if available
            const hasContext = contextBefore || contextAfter;
            const contextInfo = hasContext
                ? `CONTEXT (text surrounding the selection):
Before: "${contextBefore || ""}"
After: "${contextAfter || ""}"

`
                : "";
            const responseFormatInstruction = getAiTextEditResponseFormatInstruction(resultCount);
            const requestedResultCount = normalizeAiTextEditResultCount(resultCount);
            let message;
            if (selectedText) {
                message = `${contextInfo}I need you to modify ONLY the following selected portion of the text:

SELECTED TEXT TO MODIFY:
"""
${selectedText}
"""

${customInstruction}

Return ONLY the modified version of the selected text, not the entire field.
${responseFormatInstruction}`;
            }
            else {
                message = `${contextInfo}I need you to generate text at the cursor position.

${customInstruction}

Return ONLY the text to insert at the cursor position, not the entire field.
${responseFormatInstruction}`;
            }
            setConversationHistory((prev) => [...prev, customInstruction]);
            let agentContext = undefined;
            // Inline edits inherently act on the current field/page, so always
            // include the current item (and any selected components) as context.
            const item = editContext.currentItemDescriptor;
            if (item) {
                agentContext = {
                    items: [
                        {
                            id: item.id,
                            language: item.language,
                            version: item.version,
                            name: editContext.item?.name,
                            path: editContext.item?.path,
                        },
                    ],
                    // Include selected components if any
                    components: editContext.getSelection().length
                        ? editContext.getSelection().map((componentId) => ({
                            componentId,
                            pageItem: {
                                id: item.id,
                                language: item.language,
                                version: item.version,
                                name: editContext.item?.name,
                            },
                        }))
                        : undefined,
                    // Set the current item as the active context
                    currentItemId: item.id,
                };
            }
            ensureSocketListener();
            const initialRuns = {};
            for (const model of selectedModels) {
                const agentId = crypto.randomUUID();
                activeAgentIdsRef.current.add(agentId);
                latestRawContentRef.current[agentId] = "";
                delete lastParsedRawRef.current[agentId];
                initialRuns[agentId] = {
                    agentId,
                    modelId: model.id,
                    modelName: model.name,
                    requestedResultCount,
                    status: "pending",
                    rawContent: "",
                };
            }
            setModelRuns(initialRuns);
            modelRunsRef.current = initialRuns;
            setState("preview"); // Show results immediately side-by-side as they stream in
            await Promise.all(Object.values(initialRuns).map(async (run) => {
                subscribeAgentInline(run.agentId);
                try {
                    await withTimeout(startAgent({
                        agentId: run.agentId,
                        message,
                        sessionId: editContext.sessionId,
                        profileId: profileId,
                        mode: "autonomous",
                        model: run.modelId,
                        context: agentContext,
                    }), START_AGENT_TIMEOUT_MS, `Timed out starting ${run.modelName}. Please try again.`);
                    updateModelRun(run.agentId, (current) => {
                        if (current.status !== "pending")
                            return current;
                        return { ...current, status: "thinking" };
                    });
                }
                catch (runErr) {
                    const errorMsg = runErr instanceof Error
                        ? runErr.message
                        : "Failed to start model run";
                    updateModelRun(run.agentId, (current) => ({
                        ...current,
                        status: "error",
                        error: errorMsg,
                    }));
                }
            }));
        }
        catch (err) {
            console.error("AI modification error:", err);
            setError(err instanceof Error ? err.message : "An error occurred");
            setState("input");
        }
    }, [
        editContext,
        selectedText,
        contextBefore,
        contextAfter,
        profileId,
        activeProfile,
        selectedModels,
        closeAllActiveAgents,
        unsubscribeAllAgents,
        ensureSocketListener,
        subscribeAgentInline,
        updateModelRun,
    ]);
    const handleQuickAction = useCallback((action) => {
        executeAiModification(action.instruction, action.resultCount);
    }, [executeAiModification]);
    // ALT+letter quick select for quick actions
    useEffect(() => {
        // Only active in input state
        if (state !== "input")
            return;
        const handleKeyDown = (e) => {
            // Track ALT key state
            if (e.key === "Alt") {
                setIsAltPressed(true);
                e.preventDefault();
                return;
            }
            // Handle letter typing while ALT is pressed
            if (isAltPressed && e.key.length === 1 && /[a-zA-Z]/.test(e.key)) {
                e.preventDefault();
                // Clear any existing timeout
                if (altSearchTimeoutRef.current) {
                    clearTimeout(altSearchTimeoutRef.current);
                }
                const newBuffer = altSearchBuffer + e.key.toLowerCase();
                setAltSearchBuffer(newBuffer);
                // Find matching actions (case-insensitive prefix match on label)
                const matches = quickActions.filter((action) => action.label.toLowerCase().startsWith(newBuffer));
                if (matches.length === 1 && matches[0]) {
                    // Execute the action immediately if it's a unique match
                    handleQuickAction(matches[0]);
                    setAltSearchBuffer("");
                    setIsAltPressed(false);
                }
                else if (matches.length > 1) {
                    // Multiple matches - check if any match is EXACTLY the buffer
                    const exactMatch = matches.find((m) => m.label.toLowerCase() === newBuffer);
                    if (exactMatch) {
                        handleQuickAction(exactMatch);
                        setAltSearchBuffer("");
                        setIsAltPressed(false);
                    }
                    else {
                        // Wait for more input
                        altSearchTimeoutRef.current = setTimeout(() => {
                            setAltSearchBuffer("");
                        }, 1500);
                    }
                }
                else {
                    // No matches - auto-clear buffer after 1.5s of no typing
                    altSearchTimeoutRef.current = setTimeout(() => {
                        setAltSearchBuffer("");
                    }, 1500);
                }
            }
        };
        const handleKeyUp = (e) => {
            if (e.key === "Alt") {
                // Clear buffer when ALT is released
                setIsAltPressed(false);
                setAltSearchBuffer("");
                if (altSearchTimeoutRef.current) {
                    clearTimeout(altSearchTimeoutRef.current);
                }
            }
        };
        window.addEventListener("keydown", handleKeyDown);
        window.addEventListener("keyup", handleKeyUp);
        return () => {
            window.removeEventListener("keydown", handleKeyDown);
            window.removeEventListener("keyup", handleKeyUp);
            if (altSearchTimeoutRef.current) {
                clearTimeout(altSearchTimeoutRef.current);
            }
        };
    }, [state, isAltPressed, altSearchBuffer, quickActions, handleQuickAction]);
    const handleUseRunResult = useCallback((replacementText) => {
        if (!replacementText)
            return;
        onAccept(replacementText);
    }, [onAccept]);
    const handleModelBadgeClick = useCallback((event, agentId) => {
        if (!event.ctrlKey)
            return;
        event.preventDefault();
        event.stopPropagation();
        if (editContext?.isMobile) {
            editContext.openSidebar("agents-panel");
        }
        else {
            editContext?.setShowAgentsPanel(true);
        }
        const dispatchOpenAgent = () => {
            window.dispatchEvent(new CustomEvent("editor:openAgent", {
                detail: { agentId },
            }));
        };
        if (editContext?.isMobile) {
            window.setTimeout(dispatchOpenAgent, 500);
        }
        else {
            dispatchOpenAgent();
        }
    }, [editContext]);
    const toggleModelSelection = useCallback((modelId) => {
        setSelectedModelIds((prev) => {
            if (prev.includes(modelId)) {
                return prev.filter((id) => id !== modelId);
            }
            return [...prev, modelId];
        });
    }, []);
    const handleTryAgain = useCallback(() => {
        unsubscribeAllAgents();
        closeAllActiveAgents();
        setState("input");
        setInstruction("");
        setError(null);
        setConversationHistory([]);
        setModelRuns({});
        modelRunsRef.current = {};
        latestRawContentRef.current = {};
        lastParsedRawRef.current = {};
    }, [unsubscribeAllAgents, closeAllActiveAgents]);
    const handleClose = useCallback(() => {
        unsubscribeAllAgents();
        closeAllActiveAgents();
        onClose();
    }, [unsubscribeAllAgents, closeAllActiveAgents, onClose]);
    useEffect(() => {
        const handleEscapeKey = (event) => {
            if (event.key !== "Escape")
                return;
            event.preventDefault();
            event.stopPropagation();
            handleClose();
        };
        document.addEventListener("keydown", handleEscapeKey, true);
        return () => {
            document.removeEventListener("keydown", handleEscapeKey, true);
        };
    }, [handleClose]);
    const renderTextWithContext = (centerText, isResult = false) => {
        const hasContext = contextBefore || contextAfter;
        // No context available - just show the selected text
        if (!hasContext) {
            return (_jsx("span", { className: cn("rounded px-0.5 font-medium", isResult
                    ? "bg-feedback-green-light text-feedback-green"
                    : "bg-neutral-grey-5 text-neutral-grey-100 italic"), children: centerText }));
        }
        // Show context with ellipsis indicators
        return (_jsxs("div", { className: "text-xs leading-relaxed whitespace-pre-wrap", children: [contextBefore && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-neutral-grey-50", children: "..." }), _jsx("span", { className: "text-neutral-grey-50", children: contextBefore })] })), _jsx("span", { className: cn("mx-0.5 rounded px-0.5 font-medium", isResult
                        ? "bg-feedback-green-light text-feedback-green"
                        : "bg-neutral-grey-5 text-neutral-grey-100 italic"), children: centerText }), contextAfter && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-neutral-grey-50", children: contextAfter }), _jsx("span", { className: "text-neutral-grey-50", children: "..." })] }))] }));
    };
    const renderSuggestionPreview = (replacementText) => {
        const hasContext = contextBefore || contextAfter;
        const hasOriginalSelection = selectedText.trim().length > 0;
        const diff = hasOriginalSelection
            ? diffWords(selectedText, replacementText)
            : [];
        const suggestedTextClass = "bg-feedback-green-light text-feedback-green rounded px-0.5";
        return (_jsxs("div", { className: "font-mono text-sm whitespace-pre-wrap", children: [hasContext && contextBefore && (_jsxs("span", { className: "text-neutral-grey-50", children: [_jsx("span", { children: "..." }), _jsx("span", { children: contextBefore })] })), hasOriginalSelection ? (diff.map((part, index) => {
                    if (part.added) {
                        return (_jsx("span", { className: suggestedTextClass, children: part.value }, index));
                    }
                    if (part.removed) {
                        return null;
                    }
                    return (_jsx("span", { className: suggestedTextClass, children: part.value }, index));
                })) : (_jsx("span", { className: suggestedTextClass, children: replacementText })), hasContext && contextAfter && (_jsxs("span", { className: "text-neutral-grey-50", children: [_jsx("span", { children: contextAfter }), _jsx("span", { children: "..." })] }))] }));
    };
    const modelRunValues = useMemo(() => Object.values(modelRuns), [modelRuns]);
    const useCompactResultList = useMemo(() => modelRunValues.some((run) => run.requestedResultCount > 1 ||
        (run.replacementTexts?.length ?? 0) > 1), [modelRunValues]);
    const compactSuggestions = useMemo(() => {
        const seenSuggestions = new Set();
        return modelRunValues.flatMap((run) => {
            const replacementTexts = run.replacementTexts ??
                (run.replacementText != null ? [run.replacementText] : []);
            return replacementTexts
                .filter((replacementText) => {
                const dedupeKey = replacementText
                    .trim()
                    .replace(/\s+/g, " ")
                    .toLocaleLowerCase();
                if (!dedupeKey || seenSuggestions.has(dedupeKey)) {
                    return false;
                }
                seenSuggestions.add(dedupeKey);
                return true;
            })
                .map((replacementText, index) => ({
                id: `${run.agentId}-${index}`,
                agentId: run.agentId,
                modelName: run.modelName,
                text: replacementText,
            }));
        });
    }, [modelRunValues]);
    const handleKeyDown = useCallback((e) => {
        if (e.key === "Escape") {
            e.preventDefault();
            handleClose();
        }
    }, [handleClose]);
    const handleTextareaKeyDown = useCallback((e) => {
        if (e.key === "Enter" && !e.shiftKey) {
            e.preventDefault();
            if (instruction.trim()) {
                executeAiModification(instruction.trim());
                setInstruction("");
            }
        }
    }, [instruction, executeAiModification]);
    return (_jsxs("div", { ref: dialogRef, className: cn("border-border-default agent-inline-dialog flex max-h-[80vh] max-w-[calc(100vw-32px)] flex-col overflow-hidden rounded-[12px] border bg-white/95 shadow-lg backdrop-blur-sm transition-all duration-300 ease-in-out [&_button]:rounded-[4px]", 
        // Popover grows while the custom prompt field is focused or results are shown.
        promptFocused || state === "preview" ? "w-[390px]" : "w-[190px]", "animate-in fade-in-0 zoom-in-95 duration-200 ease-out", className), style: position
            ? {
                position: "fixed",
                left: adjustedPosition?.x ?? position.x,
                top: adjustedPosition?.y ?? position.y,
                zIndex: 1100,
            }
            : undefined, onKeyDown: handleKeyDown, children: [state === "preview" && (_jsxs("div", { className: "border-border-default flex flex-shrink-0 items-center gap-2.5 border-b px-3 py-3", children: [_jsx("button", { onClick: handleTryAgain, className: "hover:bg-neutral-grey-5 -ml-1.5 rounded-[4px] p-1.5 transition-colors", title: "Back", "aria-label": "Back", children: _jsx(ChevronLeft, { strokeWidth: 1, className: "text-neutral-grey-50 h-4 w-4" }) }), _jsx("span", { className: "text-neutral-grey-100 text-sm leading-tight font-medium", children: "Choose a result" }), _jsx("div", { className: "ml-auto flex items-center gap-1", children: _jsx(CloseButton, { onClick: handleClose, label: "Close" }) })] })), _jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto p-3", children: [state === "input" && (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [isAltPressed && (_jsxs("div", { className: "text-neutral-grey-100 bg-neutral-grey-5 animate-in fade-in flex items-center gap-2 rounded-xl px-2 py-1.5 text-xs duration-150", children: [_jsx("kbd", { className: "badge-pad-sm bg-neutral-grey-5 rounded font-mono text-[10px] font-bold", children: "ALT" }), _jsx("span", { className: "font-medium", children: altSearchBuffer ? (_jsxs(_Fragment, { children: ["Type to select:", " ", _jsx("span", { className: "font-bold", children: altSearchBuffer })] })) : ("Type first letters of an action...") })] })), _jsx("div", { className: "flex flex-col", children: quickActions.map((action) => {
                                            const hasSvgIcon = action.icon?.trim() &&
                                                (action.icon.trim().startsWith("<svg") ||
                                                    action.icon.trim().startsWith("<?xml"));
                                            const labelLower = action.label.toLowerCase();
                                            const isMatch = isAltPressed &&
                                                altSearchBuffer &&
                                                labelLower.startsWith(altSearchBuffer);
                                            const isPartialMatch = isAltPressed &&
                                                altSearchBuffer &&
                                                labelLower.includes(altSearchBuffer) &&
                                                !isMatch;
                                            return (_jsxs("button", { onClick: () => handleQuickAction(action), className: cn("flex w-full items-center gap-2.5 rounded-[4px] px-2 py-2 text-left text-xs transition-colors duration-150", "text-neutral-grey-100 hover:text-neutral-grey-100 hover:bg-neutral-grey-5", isMatch &&
                                                    "bg-neutral-grey-5 text-neutral-grey-100 ring-neutral-grey-100 ring-2", isPartialMatch && "bg-neutral-grey-5/50", isAltPressed &&
                                                    !isMatch &&
                                                    !isPartialMatch &&
                                                    "opacity-50"), children: [hasSvgIcon && (_jsx("div", { className: "text-neutral-grey-100 flex h-4 w-4 shrink-0 items-center justify-start [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
                                                            __html: sanitizeSvg(action.icon.trim()),
                                                        } })), isAltPressed && altSearchBuffer ? (_jsxs("span", { children: [_jsx("span", { className: cn(isMatch &&
                                                                    "font-bold underline underline-offset-2"), children: action.label.slice(0, altSearchBuffer.length) }), action.label.slice(altSearchBuffer.length)] })) : (action.label)] }, action.id));
                                        }) })] }), _jsx(InstructionComposer, { inputRef: inputRef, value: instruction, onChange: setInstruction, onSubmit: () => {
                                    if (instruction.trim()) {
                                        executeAiModification(instruction.trim());
                                        setInstruction("");
                                    }
                                }, onKeyDown: handleTextareaKeyDown, placeholder: conversationHistory.length > 0
                                    ? "How can I improve this further?"
                                    : "Describe...", minHeightClass: "min-h-[92px]", submitTitle: "Send (Enter)", canSubmit: !!instruction.trim() && selectedModels.length > 0, models: availableModels, hasMultipleModels: hasMultipleModels, modelPopoverOpen: modelPopoverOpen, onModelPopoverOpenChange: setModelPopoverOpen, selectedModelIds: selectedModelIds, selectedModelsCount: selectedModels.length, selectedModelSummary: selectedModelSummary, onToggleModel: toggleModelSelection, onFocusChange: setPromptFocused }), error && (_jsxs("div", { className: "text-feedback-red bg-feedback-red-light border-feedback-red animate-in fade-in slide-in-from-top-1 flex items-start gap-2 rounded-xl border px-3 py-2 text-xs duration-200", children: [_jsx(X, { strokeWidth: 1, className: "mt-0.5 h-3.5 w-3.5 shrink-0" }), _jsx("span", { children: error })] }))] })), state === "preview" && (_jsxs("div", { className: "animate-in fade-in slide-in-from-bottom-2 space-y-4 duration-300", children: [modelRunValues.length > 0 &&
                                (useCompactResultList ? (_jsxs("div", { className: "border-border-default overflow-hidden rounded-lg border bg-white", children: [compactSuggestions.length > 0 ? (compactSuggestions.map((suggestion) => (_jsxs("button", { type: "button", onClick: () => handleUseRunResult(suggestion.text), className: "hover:bg-neutral-grey-5 border-border-default flex h-8 w-full items-center gap-2 border-b px-3 text-left text-xs last:border-b-0", title: suggestion.text, children: [_jsx("span", { className: "text-neutral-grey-100 min-w-0 flex-1 truncate", children: suggestion.text }), selectedModels.length > 1 && (_jsx("span", { className: "text-neutral-grey-50 max-w-[96px] shrink-0 truncate text-[10px]", title: suggestion.modelName, children: suggestion.modelName }))] }, suggestion.id)))) : (_jsxs("div", { className: "text-neutral-grey-50 flex min-h-9 items-center gap-1.5 px-3 text-xs italic", children: [modelRunValues.some((run) => isActiveModelRunStatus(run.status)) && (_jsx(LoaderCircle, { strokeWidth: 1, className: "h-3.5 w-3.5 animate-spin" })), modelRunValues.some((run) => isActiveModelRunStatus(run.status))
                                                    ? "Waiting for suggestions..."
                                                    : "No suggestions returned."] })), compactSuggestions.length === 0 &&
                                            modelRunValues
                                                .filter((run) => run.status === "error")
                                                .map((run) => (_jsx("div", { className: "text-feedback-red border-border-default border-t px-3 py-2 text-xs", children: run.error || `${run.modelName} failed.` }, `${run.agentId}-error`)))] })) : (_jsx("div", { className: "flex flex-col gap-4", children: modelRunValues.map((run) => {
                                        const replacementTexts = run.replacementTexts ??
                                            (run.replacementText != null
                                                ? [run.replacementText]
                                                : []);
                                        return (_jsxs("div", { className: cn("border-border-default flex flex-col gap-4 rounded-lg border bg-white p-4", run.status === "error" && "border-feedback-red"), children: [_jsxs("div", { className: "text-neutral-grey-100 flex items-center gap-2 text-xs leading-none font-medium", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Lightbulb, { strokeWidth: 1, className: "text-neutral-grey-100 h-5 w-5 shrink-0" }), _jsx("span", { children: "Suggestion" })] }), selectedModels.length > 1 && (_jsx(Badge, { asChild: true, variant: "secondary", size: "sm", className: "ml-auto max-w-[180px] cursor-default truncate", children: _jsx("button", { type: "button", onClick: (event) => handleModelBadgeClick(event, run.agentId), title: `${run.modelName} (Ctrl+click to open agent chat)`, children: run.modelName }) }))] }), _jsxs("div", { className: "max-h-[220px] min-h-[44px] overflow-y-auto", children: [run.status === "pending" && (_jsxs("span", { className: "text-neutral-grey-50 inline-flex items-center gap-1.5 text-xs italic", children: [_jsx(LoaderCircle, { strokeWidth: 1, className: "h-3 w-3 animate-spin" }), "Starting..."] })), run.status === "thinking" && (_jsxs("span", { className: "text-neutral-grey-50 inline-flex items-center gap-1.5 text-xs italic", children: [_jsx(LoaderCircle, { strokeWidth: 1, className: "h-3 w-3 animate-spin" }), "Thinking..."] })), run.status === "streaming" &&
                                                            (() => {
                                                                const preview = extractStreamingPreview(run.rawContent ?? "");
                                                                return preview ? (_jsx("div", { className: "font-mono text-sm leading-7 whitespace-pre-wrap", children: renderTextWithContext(preview, false) })) : (_jsxs("span", { className: "text-neutral-grey-50 inline-flex items-center gap-1.5 text-xs italic", children: [_jsx(LoaderCircle, { strokeWidth: 1, className: "h-3 w-3 animate-spin" }), "Waiting for response..."] }));
                                                            })(), run.status === "done" &&
                                                            replacementTexts.length > 0 && (_jsx("div", { className: "flex flex-col gap-4", children: replacementTexts.map((replacementText, index) => (_jsxs("div", { className: "border-border-default flex flex-col gap-3 border-b pb-4 last:border-b-0 last:pb-0", children: [replacementTexts.length > 1 && (_jsxs("div", { className: "text-neutral-grey-50 text-[11px] font-medium", children: ["Suggestion ", index + 1] })), renderSuggestionPreview(replacementText), _jsxs(Button, { size: "sm", onClick: () => handleUseRunResult(replacementText), className: "bg-neutral-grey-10 hover:bg-neutral-grey-15 text-neutral-grey-100 self-start rounded-[4px] px-4 py-2 text-sm font-medium shadow-none", children: [_jsx(Check, { strokeWidth: 1, className: "mr-1.5 h-4 w-4" }), "Apply"] })] }, `${run.agentId}-${index}`))) })), run.status === "error" && (_jsx("div", { className: "text-feedback-red text-sm", children: run.error || "Something went wrong." }))] })] }, run.agentId));
                                    }) }))), _jsx(InstructionComposer, { inputRef: inputRef, value: instruction, onChange: setInstruction, onSubmit: () => {
                                    if (instruction.trim()) {
                                        executeAiModification(instruction.trim());
                                        setInstruction("");
                                    }
                                }, onKeyDown: handleTextareaKeyDown, placeholder: "Not quite right? Ask for a change...", minHeightClass: "min-h-[92px]", submitTitle: "Refine (Enter)", canSubmit: !!instruction.trim() && selectedModels.length > 0, models: availableModels, hasMultipleModels: hasMultipleModels, modelPopoverOpen: modelPopoverOpen, onModelPopoverOpenChange: setModelPopoverOpen, selectedModelIds: selectedModelIds, selectedModelsCount: selectedModels.length, selectedModelSummary: selectedModelSummary, onToggleModel: toggleModelSelection, onFocusChange: setPromptFocused })] }))] })] }));
}
export default InlineAiDialog;
//# sourceMappingURL=InlineAiDialog.js.map