/**
 * Error Classes for NeuroLink Client SDK
 *
 * Provides comprehensive error classification and handling for API errors,
 * network errors, validation errors, and more.
 *
 * @module @neurolink/client/errors
 */
// =============================================================================
// Error Codes
// =============================================================================
/**
 * Standard error codes for NeuroLink API errors
 */
export const ErrorCode = {
    // Client Errors (4xx)
    BAD_REQUEST: "BAD_REQUEST",
    UNAUTHORIZED: "UNAUTHORIZED",
    FORBIDDEN: "FORBIDDEN",
    NOT_FOUND: "NOT_FOUND",
    METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED",
    CONFLICT: "CONFLICT",
    PAYLOAD_TOO_LARGE: "PAYLOAD_TOO_LARGE",
    RATE_LIMITED: "RATE_LIMITED",
    INVALID_REQUEST: "INVALID_REQUEST",
    VALIDATION_ERROR: "VALIDATION_ERROR",
    // Server Errors (5xx)
    INTERNAL_ERROR: "INTERNAL_ERROR",
    SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE",
    GATEWAY_TIMEOUT: "GATEWAY_TIMEOUT",
    BAD_GATEWAY: "BAD_GATEWAY",
    // Network Errors
    NETWORK_ERROR: "NETWORK_ERROR",
    TIMEOUT: "TIMEOUT",
    CONNECTION_REFUSED: "CONNECTION_REFUSED",
    DNS_ERROR: "DNS_ERROR",
    // Client-Side Errors
    CONFIGURATION_ERROR: "CONFIGURATION_ERROR",
    SERIALIZATION_ERROR: "SERIALIZATION_ERROR",
    STREAM_ERROR: "STREAM_ERROR",
    ABORT_ERROR: "ABORT_ERROR",
    // Provider Errors
    PROVIDER_ERROR: "PROVIDER_ERROR",
    MODEL_NOT_FOUND: "MODEL_NOT_FOUND",
    CONTEXT_LENGTH_EXCEEDED: "CONTEXT_LENGTH_EXCEEDED",
    CONTENT_FILTERED: "CONTENT_FILTERED",
    // Unknown
    UNKNOWN: "UNKNOWN",
};
// =============================================================================
// Base Error Class
// =============================================================================
/**
 * Base error class for all NeuroLink client errors
 *
 * Provides consistent error structure with error codes, status codes,
 * and additional metadata.
 */
export class NeuroLinkError extends Error {
    /** Error code for programmatic handling */
    code;
    /** HTTP status code (if applicable) */
    status;
    /** Additional error details */
    details;
    /** Whether the error is retryable */
    retryable;
    /** Request ID for error tracking */
    requestId;
    constructor(message, code = ErrorCode.UNKNOWN, options) {
        super(message, { cause: options?.cause });
        this.name = "NeuroLinkError";
        this.code = code;
        this.status = options?.status;
        this.details = options?.details;
        this.retryable = options?.retryable ?? false;
        this.requestId = options?.requestId;
    }
    /**
     * Convert error to API error format
     */
    toApiError() {
        return {
            code: this.code,
            message: this.message,
            status: this.status ?? 500,
            details: this.details,
            retryable: this.retryable,
            requestId: this.requestId,
        };
    }
    /**
     * Convert error to JSON
     */
    toJSON() {
        return {
            name: this.name,
            code: this.code,
            message: this.message,
            status: this.status,
            details: this.details,
            retryable: this.retryable,
            requestId: this.requestId,
            stack: this.stack,
        };
    }
}
// =============================================================================
// HTTP Error Classes
// =============================================================================
/**
 * Error for HTTP-related failures
 */
export class HttpError extends NeuroLinkError {
    /** HTTP response headers */
    headers;
    /** HTTP response body */
    body;
    constructor(message, status, options) {
        const code = options?.code ?? mapStatusToErrorCode(status);
        const retryable = isRetryableStatus(status);
        super(message, code, {
            status,
            details: options?.details,
            retryable,
            requestId: options?.requestId,
        });
        this.name = "HttpError";
        this.headers = options?.headers;
        this.body = options?.body;
    }
}
/**
 * Error for rate limiting (429)
 */
export class ClientRateLimitError extends HttpError {
    /** Retry-After value in seconds (if provided) */
    retryAfter;
    /** Rate limit reset time */
    resetAt;
    constructor(message = "Rate limit exceeded", options) {
        super(message, 429, {
            code: ErrorCode.RATE_LIMITED,
            details: options?.details,
            requestId: options?.requestId,
        });
        this.name = "ClientRateLimitError";
        this.retryAfter = options?.retryAfter;
        this.resetAt = options?.resetAt;
    }
}
/**
 * Error for validation failures (400)
 */
export class ClientValidationError extends HttpError {
    /** Field-level validation errors */
    fieldErrors;
    constructor(message = "Validation failed", options) {
        super(message, 400, {
            code: ErrorCode.VALIDATION_ERROR,
            details: {
                ...options?.details,
                ...(options?.fieldErrors && {
                    fieldErrors: options.fieldErrors,
                }),
            },
            requestId: options?.requestId,
        });
        this.name = "ClientValidationError";
        this.fieldErrors = options?.fieldErrors;
    }
}
/**
 * Error for authentication failures (401)
 */
export class ClientAuthenticationError extends HttpError {
    constructor(message = "Authentication required", options) {
        super(message, 401, {
            code: ErrorCode.UNAUTHORIZED,
            details: options?.details,
            requestId: options?.requestId,
        });
        this.name = "ClientAuthenticationError";
    }
}
/**
 * Error for authorization failures (403)
 */
export class ClientAuthorizationError extends HttpError {
    constructor(message = "Access forbidden", options) {
        super(message, 403, {
            code: ErrorCode.FORBIDDEN,
            details: options?.details,
            requestId: options?.requestId,
        });
        this.name = "ClientAuthorizationError";
    }
}
/**
 * Error for not found (404)
 */
export class NotFoundError extends HttpError {
    /** Resource type that was not found */
    resourceType;
    /** Resource ID that was not found */
    resourceId;
    constructor(message = "Resource not found", options) {
        super(message, 404, {
            code: ErrorCode.NOT_FOUND,
            details: {
                ...options?.details,
                ...(options?.resourceType && { resourceType: options.resourceType }),
                ...(options?.resourceId && { resourceId: options.resourceId }),
            },
            requestId: options?.requestId,
        });
        this.name = "NotFoundError";
        this.resourceType = options?.resourceType;
        this.resourceId = options?.resourceId;
    }
}
// =============================================================================
// Network Error Classes
// =============================================================================
/**
 * Error for network-related failures
 */
export class ClientNetworkError extends NeuroLinkError {
    constructor(message = "Network error occurred", options) {
        super(message, options?.code ?? ErrorCode.NETWORK_ERROR, {
            details: options?.details,
            retryable: true,
            cause: options?.cause,
            requestId: options?.requestId,
        });
        this.name = "ClientNetworkError";
    }
}
/**
 * Error for request timeout
 */
export class ClientTimeoutError extends ClientNetworkError {
    /** Timeout duration in milliseconds */
    timeoutMs;
    constructor(timeoutMs, message, options) {
        super(message ?? `Request timed out after ${timeoutMs}ms`, {
            code: ErrorCode.TIMEOUT,
            details: {
                ...options?.details,
                timeoutMs,
            },
            requestId: options?.requestId,
        });
        this.name = "ClientTimeoutError";
        this.timeoutMs = timeoutMs;
    }
}
/**
 * Error for connection refused
 */
export class ClientConnectionError extends ClientNetworkError {
    /** Target host */
    host;
    /** Target port */
    port;
    constructor(message = "Connection refused", options) {
        super(message, {
            code: ErrorCode.CONNECTION_REFUSED,
            details: {
                ...options?.details,
                ...(options?.host && { host: options.host }),
                ...(options?.port !== undefined && { port: options.port }),
            },
            cause: options?.cause,
            requestId: options?.requestId,
        });
        this.name = "ClientConnectionError";
        this.host = options?.host;
        this.port = options?.port;
    }
}
// =============================================================================
// Client-Side Error Classes
// =============================================================================
/**
 * Error for request cancellation
 */
export class AbortError extends NeuroLinkError {
    constructor(message = "Request was aborted", options) {
        super(message, ErrorCode.ABORT_ERROR, {
            retryable: false,
            requestId: options?.requestId,
        });
        this.name = "AbortError";
    }
}
/**
 * Error for configuration issues
 */
export class ClientConfigurationError extends NeuroLinkError {
    /** Configuration field with issue */
    field;
    constructor(message, options) {
        super(message, ErrorCode.CONFIGURATION_ERROR, {
            details: {
                ...options?.details,
                ...(options?.field && { field: options.field }),
            },
            retryable: false,
        });
        this.name = "ClientConfigurationError";
        this.field = options?.field;
    }
}
/**
 * Error for stream processing failures
 */
export class StreamError extends NeuroLinkError {
    constructor(message = "Stream processing failed", options) {
        super(message, ErrorCode.STREAM_ERROR, {
            details: options?.details,
            retryable: false,
            cause: options?.cause,
            requestId: options?.requestId,
        });
        this.name = "StreamError";
    }
}
// =============================================================================
// Provider Error Classes
// =============================================================================
/**
 * Error from AI provider
 */
export class ClientProviderError extends NeuroLinkError {
    /** Provider name */
    provider;
    /** Model name */
    model;
    /** Original provider error */
    providerError;
    constructor(message, options) {
        super(message, ErrorCode.PROVIDER_ERROR, {
            status: options?.status,
            details: {
                ...options?.details,
                ...(options?.provider && { provider: options.provider }),
                ...(options?.model && { model: options.model }),
            },
            retryable: options?.retryable ?? false,
            requestId: options?.requestId,
        });
        this.name = "ClientProviderError";
        this.provider = options?.provider;
        this.model = options?.model;
        this.providerError = options?.providerError;
    }
}
/**
 * Error for context length exceeded
 */
export class ContextLengthError extends ClientProviderError {
    /** Maximum allowed tokens */
    maxTokens;
    /** Requested tokens */
    requestedTokens;
    constructor(message = "Context length exceeded", options) {
        super(message, {
            provider: options?.provider,
            model: options?.model,
            details: {
                ...(options?.maxTokens !== undefined && {
                    maxTokens: options.maxTokens,
                }),
                ...(options?.requestedTokens !== undefined && {
                    requestedTokens: options.requestedTokens,
                }),
            },
            retryable: false,
            requestId: options?.requestId,
        });
        this.name = "ContextLengthError";
        this.maxTokens = options?.maxTokens;
        this.requestedTokens = options?.requestedTokens;
    }
}
/**
 * Error for content filtering
 */
export class ContentFilterError extends ClientProviderError {
    /** Filter category that triggered */
    category;
    constructor(message = "Content was filtered", options) {
        super(message, {
            provider: options?.provider,
            model: options?.model,
            details: {
                ...(options?.category && { category: options.category }),
            },
            retryable: false,
            requestId: options?.requestId,
        });
        this.name = "ContentFilterError";
        this.category = options?.category;
    }
}
// =============================================================================
// Error Factory Functions
// =============================================================================
/**
 * Create an error from an API error response
 */
export function createErrorFromResponse(apiError, options) {
    const { code, message, status, details, retryable } = apiError;
    // Map to specific error class based on status
    if (status === 401) {
        return new ClientAuthenticationError(message, {
            details,
            requestId: options?.requestId,
        });
    }
    if (status === 403) {
        return new ClientAuthorizationError(message, {
            details,
            requestId: options?.requestId,
        });
    }
    if (status === 404) {
        return new NotFoundError(message, {
            details,
            requestId: options?.requestId,
        });
    }
    if (status === 429) {
        return new ClientRateLimitError(message, {
            details,
            requestId: options?.requestId,
        });
    }
    if (status === 400 && code === "VALIDATION_ERROR") {
        return new ClientValidationError(message, {
            details,
            requestId: options?.requestId,
        });
    }
    // Generic HTTP error
    if (status) {
        return new HttpError(message, status, {
            code: code,
            details,
            requestId: options?.requestId,
        });
    }
    // Generic error
    return new NeuroLinkError(message, code, {
        details,
        retryable: retryable ?? false,
        requestId: options?.requestId,
    });
}
/**
 * Create an error from a native Error object
 */
export function createErrorFromNative(error, options) {
    // Handle AbortError
    if (error.name === "AbortError") {
        return new AbortError(error.message, { requestId: options?.requestId });
    }
    // Handle timeout
    if (error.message.includes("timeout") || error.name === "TimeoutError") {
        return new ClientTimeoutError(0, error.message, {
            requestId: options?.requestId,
        });
    }
    // Handle network errors
    if (error.message.includes("network") ||
        error.message.includes("ECONNREFUSED") ||
        error.message.includes("ENOTFOUND")) {
        return new ClientNetworkError(error.message, {
            cause: error,
            requestId: options?.requestId,
        });
    }
    // Generic error
    return new NeuroLinkError(error.message, ErrorCode.UNKNOWN, {
        cause: error,
        requestId: options?.requestId,
    });
}
// =============================================================================
// Utility Functions
// =============================================================================
/**
 * Map HTTP status code to error code
 */
export function mapStatusToErrorCode(status) {
    const mapping = {
        400: ErrorCode.BAD_REQUEST,
        401: ErrorCode.UNAUTHORIZED,
        403: ErrorCode.FORBIDDEN,
        404: ErrorCode.NOT_FOUND,
        405: ErrorCode.METHOD_NOT_ALLOWED,
        409: ErrorCode.CONFLICT,
        413: ErrorCode.PAYLOAD_TOO_LARGE,
        429: ErrorCode.RATE_LIMITED,
        500: ErrorCode.INTERNAL_ERROR,
        502: ErrorCode.BAD_GATEWAY,
        503: ErrorCode.SERVICE_UNAVAILABLE,
        504: ErrorCode.GATEWAY_TIMEOUT,
    };
    return (mapping[status] ??
        (status >= 500 ? ErrorCode.INTERNAL_ERROR : ErrorCode.UNKNOWN));
}
/**
 * Check if a status code is retryable
 */
export function isRetryableStatus(status) {
    return [408, 429, 500, 502, 503, 504].includes(status);
}
/**
 * Check if an error is retryable
 */
export function isRetryableError(error) {
    if (error instanceof NeuroLinkError) {
        return error.retryable;
    }
    if (error instanceof Error) {
        // Network errors are generally retryable
        if (error.message.includes("network") ||
            error.message.includes("ECONNREFUSED") ||
            error.message.includes("ETIMEDOUT")) {
            return true;
        }
    }
    return false;
}
/**
 * Type guard for NeuroLinkError
 */
export function isNeuroLinkError(error) {
    return error instanceof NeuroLinkError;
}
/**
 * Type guard for ApiError
 */
export function isApiError(error) {
    if (typeof error !== "object" || error === null) {
        return false;
    }
    const obj = error;
    return typeof obj.code === "string" && typeof obj.message === "string";
}
//# sourceMappingURL=errors.js.map