/**
 * ToolExecutionComponent — the TUI component for a single tool call.
 *
 * Manages the lifecycle of a tool call from argument streaming through result display.
 * Handles syntax highlighting (write), diff preview (edit), image rendering,
 * expanded/collapsed state, and a blinking progress indicator.
 */
import { computeEditDiff } from '../../../app/tools/edit-diff.js';
import { convertToPng } from '../../../shared/images/convert.js';
import { Box, Container, getCapabilities, Image, Spacer, Text } from '../../../tui/index.js';
import { PREFIX_WIDTH, prefixLines, toolPrefix } from '../../layout.js';
import { theme } from '../../theme/runtime.js';
import { getToolPresentation } from '../presentation/index.js';
import { reportShellRenderError } from '../../render-errors.js';
import { getToolExecutionImageBlocks, getToolExecutionTextOutput, resolveRenderableToolImage } from './tool-execution-images.js';
import { coerceToolString } from './tool-execution-types.js';
import { buildWriteHighlightCache, updateWriteHighlightCacheIncrementally } from './tool-execution-write-highlight.js';
export class ToolExecutionComponent extends Container {
    contentBox;
    contentText;
    imageComponents = [];
    imageSpacers = [];
    toolName;
    args;
    expanded = false;
    showImages;
    isPartial = true;
    toolDefinition;
    ui;
    cwd;
    result;
    editDiffPreview;
    editDiffArgsKey;
    convertedImages = new Map();
    writeHighlightCache;
    hideComponent = false;
    summaryText;
    grouped = false;
    blinkOn = true;
    blinkTimer;
    onGroupUpdate;
    constructor(toolName, args, options = {}, toolDefinition, ui, cwd = process.cwd()) {
        super();
        this.toolName = toolName;
        this.args = args;
        this.showImages = options.showImages ?? true;
        this.toolDefinition = toolDefinition;
        this.ui = ui;
        this.cwd = cwd;
        this.addChild(new Spacer(1));
        this.contentBox = new Box(0, 0);
        this.contentText = new Text('', 0, 0);
        if (this.getPresentation()) {
            this.addChild(this.contentBox);
        }
        else {
            this.addChild(this.contentText);
        }
        this.startBlink();
        this.updateDisplay();
    }
    startBlink() {
        if (this.grouped || !this.isPartial || this.blinkTimer) {
            return;
        }
        this.blinkTimer = setInterval(() => {
            this.blinkOn = !this.blinkOn;
            this.ui.requestRender();
        }, 500);
    }
    getPresentation() {
        return getToolPresentation(this.toolName, this.toolDefinition);
    }
    getRenderState() {
        return {
            writeHighlightCache: this.writeHighlightCache,
            editDiffPreview: this.editDiffPreview,
            firstChangedLine: (this.editDiffPreview && 'firstChangedLine' in this.editDiffPreview
                ? this.editDiffPreview.firstChangedLine
                : undefined) ||
                (this.result && !this.result.isError ? this.result.details?.firstChangedLine : undefined)
        };
    }
    formatGenericFallback() {
        let text = theme.fg('toolTitle', theme.bold(this.toolName));
        text += `\n\n${JSON.stringify(this.args, null, 2)}`;
        const output = this.getTextOutput();
        if (output) {
            text += `\n${output}`;
        }
        return text;
    }
    updateArgs(args) {
        this.args = args;
        if (this.toolName === 'write' && this.isPartial) {
            this.writeHighlightCache = this.getIncrementalWriteHighlightCache();
        }
        this.updateDisplay();
        this.onGroupUpdate?.();
    }
    setArgsComplete() {
        if (this.toolName === 'write') {
            this.writeHighlightCache = this.getFullWriteHighlightCache();
        }
        this.maybeComputeEditDiff();
    }
    maybeComputeEditDiff() {
        if (this.toolName !== 'edit') {
            return;
        }
        const path = this.args?.path;
        const oldText = this.args?.oldText;
        const newText = this.args?.newText;
        if (!path || oldText === undefined || newText === undefined) {
            return;
        }
        const argsKey = JSON.stringify({ path, oldText, newText });
        if (this.editDiffArgsKey === argsKey) {
            return;
        }
        this.editDiffArgsKey = argsKey;
        computeEditDiff(path, oldText, newText, this.cwd).then((result) => {
            if (this.editDiffArgsKey === argsKey) {
                this.editDiffPreview = result;
                this.updateDisplay();
                this.ui.requestRender();
            }
        });
    }
    updateResult(result, isPartial = false) {
        this.result = result;
        this.isPartial = isPartial;
        if (this.isPartial) {
            this.startBlink();
        }
        else {
            this.stopBlink();
        }
        if (this.toolName === 'write' && !isPartial) {
            this.writeHighlightCache = this.getFullWriteHighlightCache();
        }
        this.updateDisplay();
        this.maybeConvertImagesForKitty();
        this.onGroupUpdate?.();
    }
    setSummary(summary) {
        this.summaryText = summary;
        this.updateDisplay();
    }
    maybeConvertImagesForKitty() {
        const capabilities = getCapabilities();
        if (capabilities.images !== 'kitty' || !this.result) {
            return;
        }
        const imageBlocks = getToolExecutionImageBlocks(this.result);
        for (let index = 0; index < imageBlocks.length; index++) {
            const imageBlock = imageBlocks[index];
            if (!imageBlock.data || !imageBlock.mimeType) {
                continue;
            }
            if (imageBlock.mimeType === 'image/png' || this.convertedImages.has(index)) {
                continue;
            }
            convertToPng(imageBlock.data, imageBlock.mimeType).then((converted) => {
                if (converted) {
                    this.convertedImages.set(index, converted);
                    this.updateDisplay();
                    this.ui.requestRender();
                }
            });
        }
    }
    setGrouped(grouped) {
        this.grouped = grouped;
        if (grouped) {
            this.stopBlink();
        }
        else if (this.isPartial) {
            this.startBlink();
        }
    }
    getArgs() {
        return this.args;
    }
    getResult() {
        return this.result;
    }
    getIsPartial() {
        return this.isPartial;
    }
    setExpanded(expanded) {
        this.expanded = expanded;
        this.updateDisplay();
    }
    setShowImages(show) {
        this.showImages = show;
        this.updateDisplay();
    }
    invalidate() {
        super.invalidate();
        this.updateDisplay();
    }
    render(width) {
        if (this.hideComponent || this.grouped) {
            return [];
        }
        const prefix = toolPrefix(this.isPartial, this.result?.isError ?? false, this.blinkOn);
        return prefixLines(super.render(width - PREFIX_WIDTH), prefix);
    }
    stopBlink() {
        if (this.blinkTimer) {
            clearInterval(this.blinkTimer);
            this.blinkTimer = undefined;
            this.blinkOn = true;
        }
    }
    dispose() {
        this.stopBlink();
        this.clearImageChildren();
    }
    updateDisplay() {
        const presentation = this.getPresentation();
        let customRendererHasContent = false;
        this.hideComponent = false;
        if (presentation) {
            this.contentBox.clear();
            if (presentation?.renderCall) {
                try {
                    const callComponent = presentation.renderCall(this.args, {
                        args: this.args,
                        expanded: this.expanded,
                        isPartial: this.isPartial,
                        textOutput: this.getTextOutput(),
                        terminalColumns: this.ui.terminal.columns,
                        preview: this.getRenderState()
                    }, theme);
                    if (callComponent !== undefined) {
                        this.contentBox.addChild(callComponent);
                        customRendererHasContent = true;
                    }
                }
                catch (error) {
                    reportShellRenderError(`tool-call:${this.toolName}`, error);
                    this.contentBox.addChild(new Text(theme.fg('toolTitle', theme.bold(this.toolName)), 0, 0));
                    customRendererHasContent = true;
                }
            }
            else {
                this.contentBox.addChild(new Text(theme.fg('toolTitle', theme.bold(this.toolName)), 0, 0));
                customRendererHasContent = true;
            }
            if (this.result && presentation?.renderResult) {
                try {
                    const resultComponent = presentation.renderResult({
                        content: this.result.content,
                        details: this.result.details,
                        isError: this.result.isError
                    }, {
                        args: this.args,
                        expanded: this.expanded,
                        isPartial: this.isPartial,
                        textOutput: this.getTextOutput(),
                        terminalColumns: this.ui.terminal.columns,
                        preview: this.getRenderState()
                    }, theme);
                    if (resultComponent !== undefined) {
                        this.contentBox.addChild(resultComponent);
                        customRendererHasContent = true;
                    }
                }
                catch (error) {
                    reportShellRenderError(`tool-result:${this.toolName}`, error);
                    const output = this.getTextOutput();
                    if (output) {
                        this.contentBox.addChild(new Text(theme.fg('toolOutput', output), 0, 0));
                        customRendererHasContent = true;
                    }
                }
            }
            else if (this.result) {
                const output = this.getTextOutput();
                if (output) {
                    this.contentBox.addChild(new Text(theme.fg('toolOutput', output), 0, 0));
                    customRendererHasContent = true;
                }
            }
        }
        else {
            let fallbackText = this.formatGenericFallback();
            if (this.summaryText) {
                fallbackText += `\n${theme.fg('dim', `  ↳ ${this.summaryText}`)}`;
            }
            this.contentText.setText(fallbackText);
        }
        // Append summary line if available (presentation path)
        if (this.summaryText && presentation) {
            this.contentBox.addChild(new Text(theme.fg('dim', `  ↳ ${this.summaryText}`), 0, 0));
        }
        this.clearImageChildren();
        if (this.result) {
            const capabilities = getCapabilities();
            const imageBlocks = getToolExecutionImageBlocks(this.result);
            for (let index = 0; index < imageBlocks.length; index++) {
                const imageData = resolveRenderableToolImage(imageBlocks[index], this.convertedImages.get(index), capabilities, this.showImages);
                if (!imageData) {
                    continue;
                }
                const spacer = new Spacer(1);
                this.addChild(spacer);
                this.imageSpacers.push(spacer);
                const imageComponent = new Image(imageData.data, imageData.mimeType, { fallbackColor: (text) => theme.fg('toolOutput', text) }, { maxWidthCells: 60 });
                this.imageComponents.push(imageComponent);
                this.addChild(imageComponent);
            }
        }
        if (presentation) {
            this.hideComponent = !customRendererHasContent && this.imageComponents.length === 0;
        }
    }
    clearImageChildren() {
        for (const image of this.imageComponents) {
            this.removeChild(image);
        }
        this.imageComponents = [];
        for (const spacer of this.imageSpacers) {
            this.removeChild(spacer);
        }
        this.imageSpacers = [];
    }
    getTextOutput() {
        return getToolExecutionTextOutput(this.result, { showImages: this.showImages });
    }
    getFullWriteHighlightCache() {
        const rawPath = coerceToolString(this.args?.file_path ?? this.args?.path);
        const fileContent = coerceToolString(this.args?.content);
        if (rawPath === null || fileContent === null) {
            return undefined;
        }
        return buildWriteHighlightCache(rawPath, fileContent);
    }
    getIncrementalWriteHighlightCache() {
        const rawPath = coerceToolString(this.args?.file_path ?? this.args?.path);
        const fileContent = coerceToolString(this.args?.content);
        if (rawPath === null || fileContent === null) {
            return undefined;
        }
        return updateWriteHighlightCacheIncrementally(this.writeHighlightCache, rawPath, fileContent);
    }
}
//# sourceMappingURL=tool-execution.js.map