/**
 * Tool Error Boundary Component
 *
 * Specialized error boundary for catching and handling tool execution errors.
 * Provides detailed error information and retry capabilities for tool failures.
 */
import React, { Component } from 'react';
import { Box, Text } from 'ink';
import { logger } from '../../../utils/logger.js';
/**
 * Error types specific to tool execution
 */
export var ToolErrorType;
(function (ToolErrorType) {
    ToolErrorType["EXECUTION_FAILED"] = "EXECUTION_FAILED";
    ToolErrorType["INVALID_PARAMETERS"] = "INVALID_PARAMETERS";
    ToolErrorType["TIMEOUT"] = "TIMEOUT";
    ToolErrorType["PERMISSION_DENIED"] = "PERMISSION_DENIED";
    ToolErrorType["RESOURCE_NOT_FOUND"] = "RESOURCE_NOT_FOUND";
    ToolErrorType["UNKNOWN"] = "UNKNOWN";
})(ToolErrorType || (ToolErrorType = {}));
/**
 * Detects the type of tool error based on error message and properties
 */
function detectToolErrorType(error) {
    const message = error.message.toLowerCase();
    if (message.includes('timeout') || message.includes('timed out')) {
        return ToolErrorType.TIMEOUT;
    }
    if (message.includes('permission') || message.includes('eacces')) {
        return ToolErrorType.PERMISSION_DENIED;
    }
    if (message.includes('not found') || message.includes('enoent')) {
        return ToolErrorType.RESOURCE_NOT_FOUND;
    }
    if (message.includes('invalid') || message.includes('parameter')) {
        return ToolErrorType.INVALID_PARAMETERS;
    }
    if (message.includes('failed') || message.includes('error')) {
        return ToolErrorType.EXECUTION_FAILED;
    }
    return ToolErrorType.UNKNOWN;
}
/**
 * Tool Error Boundary for handling tool execution errors
 */
export class ToolErrorBoundary extends Component {
    retryTimeout = null;
    constructor(props) {
        super(props);
        this.state = {
            hasError: false,
            error: null,
            errorInfo: null,
            retryCount: 0,
            isRetrying: false,
        };
    }
    static getDerivedStateFromError(error) {
        return { hasError: true, error };
    }
    componentDidCatch(error, errorInfo) {
        this.setState({ errorInfo });
        // Log error details
        const toolName = this.props.toolName || 'Unknown Tool';
        const errorType = detectToolErrorType(error);
        logger.error(`[ToolErrorBoundary] Tool execution error in ${toolName}`, error, {
            toolName,
            errorType,
            componentStack: errorInfo.componentStack
        });
        // Call custom error handler if provided
        if (this.props.onError) {
            this.props.onError(error, errorInfo);
        }
    }
    componentWillUnmount() {
        if (this.retryTimeout) {
            clearTimeout(this.retryTimeout);
        }
    }
    handleRetry = () => {
        const maxRetries = this.props.maxRetries || 3;
        if (this.state.retryCount >= maxRetries) {
            return;
        }
        this.setState({ isRetrying: true });
        // Exponential backoff: 1s, 2s, 4s
        const delay = Math.pow(2, this.state.retryCount) * 1000;
        this.retryTimeout = setTimeout(() => {
            this.setState((prev) => ({
                hasError: false,
                error: null,
                errorInfo: null,
                retryCount: prev.retryCount + 1,
                isRetrying: false,
            }));
            // Call retry callback if provided
            if (this.props.onRetry) {
                this.props.onRetry();
            }
        }, delay);
    };
    getErrorMessage() {
        if (!this.state.error) {
            return 'An unexpected error occurred';
        }
        const errorType = detectToolErrorType(this.state.error);
        const toolName = this.props.toolName || 'tool';
        switch (errorType) {
            case ToolErrorType.TIMEOUT:
                return `Tool execution timed out. The ${toolName} took too long to complete.`;
            case ToolErrorType.PERMISSION_DENIED:
                return `Permission denied. The ${toolName} does not have the necessary permissions.`;
            case ToolErrorType.RESOURCE_NOT_FOUND:
                return `Resource not found. The ${toolName} could not find the required resource.`;
            case ToolErrorType.INVALID_PARAMETERS:
                return `Invalid parameters. The ${toolName} received invalid input.`;
            case ToolErrorType.EXECUTION_FAILED:
                return `Execution failed. The ${toolName} encountered an error: ${this.state.error.message}`;
            default:
                return `The ${toolName} encountered an error: ${this.state.error.message}`;
        }
    }
    render() {
        if (this.state.hasError && this.state.error) {
            const maxRetries = this.props.maxRetries || 3;
            const canRetry = this.state.retryCount < maxRetries && this.props.onRetry;
            const errorType = detectToolErrorType(this.state.error);
            return (React.createElement(Box, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "red" },
                React.createElement(Box, { marginBottom: 1 },
                    React.createElement(Text, { color: "red", bold: true }, "Tool Execution Error"),
                    this.props.toolName && (React.createElement(Text, { color: "gray" },
                        " (",
                        this.props.toolName,
                        ")"))),
                React.createElement(Box, { marginBottom: 1 },
                    React.createElement(Text, { color: "yellow" }, this.getErrorMessage())),
                this.props.showDetails && (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
                    React.createElement(Text, { color: "gray", dimColor: true },
                        "Error Type: ",
                        errorType),
                    React.createElement(Text, { color: "gray", dimColor: true },
                        "Error Name: ",
                        this.state.error.name),
                    this.state.error.stack && (React.createElement(Text, { color: "gray", dimColor: true },
                        this.state.error.stack.slice(0, 200),
                        "...")))),
                canRetry && (React.createElement(Box, { flexDirection: "column", marginTop: 1 }, this.state.isRetrying ? (React.createElement(Text, { color: "cyan" }, "Retrying...")) : (React.createElement(Box, null,
                    React.createElement(Text, { color: "green" },
                        "Retry available (",
                        this.state.retryCount,
                        "/",
                        maxRetries,
                        ")"),
                    React.createElement(Text, { color: "gray" },
                        " - Will auto-retry in ",
                        Math.pow(2, this.state.retryCount),
                        "s"))))),
                !canRetry && this.state.retryCount >= maxRetries && (React.createElement(Box, { marginTop: 1 },
                    React.createElement(Text, { color: "red" }, "Maximum retry attempts reached. Please check the error and try again manually."))),
                React.createElement(Box, { marginTop: 1 },
                    React.createElement(Text, { color: "gray", dimColor: true }, "Press Ctrl+C to exit"))));
        }
        return this.props.children;
    }
}
export function withToolErrorBoundary(WrappedComponent, options = {}) {
    const WithToolErrorBoundaryComponent = (props) => (React.createElement(ToolErrorBoundary, { toolName: options.toolName, onRetry: options.onRetry, onError: options.onError, maxRetries: options.maxRetries, showDetails: options.showDetails },
        React.createElement(WrappedComponent, { ...props })));
    WithToolErrorBoundaryComponent.displayName = `WithToolErrorBoundary(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
    return WithToolErrorBoundaryComponent;
}
export default ToolErrorBoundary;
//# sourceMappingURL=tool-error-boundary.js.map