import type { APIGatewayEvent } from 'aws-lambda';
import type { AxiosError } from 'axios';
import type { ErrorRequestHandler } from 'express';
import type { HonoRequest } from 'hono';
import type { MiddlewareHandler } from 'hono';
import type { MiddlewareObj } from '@middy/core';
import type { Request as Request_2 } from 'express';
import type { RequestHandler } from 'express';

/**
 * Adds context details to try-catch-cloud error.
 * If you call it multiple times, it collects all details,
 * but details with the same name will be overwritten with the latest value.
 *
 * @example
 * addContext(req, { username: 'hugo_reyes8' }); // Context: { username: 'hugo_reyes8' }
 * addContext(req, { age: 29 }); // Context: { username: 'hugo_reyes8', age: 29 }
 * addContext(req, { age: 32 }); // Context: { username: 'hugo_reyes8', age: 32 }
 *
 * @param req - Express request
 * @param details - Context details
 */
export declare const addContext: (req: Request_2, details: Record<string, unknown>) => void;

export declare function addContext_alias_1(ctx: ErrorContext_alias_1): void;

export declare type APIGatewayEventCommon = Partial<Pick<APIGatewayEvent, "httpMethod" | "path" | "queryStringParameters" | "body" | "headers">>;

export declare type AxiosErrorRequest = ErrorRequest<{
    url: string | null;
    query: Record<string, string | string[] | undefined> | null;
    params: unknown | null;
    method: string | null;
    statusCode: number;
    requestBody: unknown | null;
    responseBody: unknown | null;
}>;

export declare abstract class BaseErrorUtility<TRequest> implements ErrorUtilityMethods<TRequest> {
    protected readonly projectName: string;
    protected readonly apiKey: string;
    protected readonly debug?: boolean | undefined;
    constructor(projectName: string, apiKey: string, debug?: boolean | undefined);
    protected abstract mapRequest(request: TRequest): Promise<MappedHttpRequest> | MappedHttpRequest;
    sendError(error: Error | unknown, userContext?: Record<string, unknown>): Promise<{
        id: string;
    } | undefined>;
    /**
     * Sends error and request details to try-catch-cloud service.
     * You can manually map details from your route to request object.
     *
     * ```
     *  errorTrack.sendErrorFromEndpoint(
     *      error,
     *      {
     *          url: req.originalUrl.split("?")[0],
     *          method: req.method,
     *          headers: req.headers,
     *          query: req.query,
     *          body,
     *      },
     *      { ...context }
     *  );
     * ```
     */
    sendErrorFromEndPoint(error: Error | unknown, request: TRequest, userContext?: Record<string, unknown>): Promise<{
        id: string;
    } | undefined>;
    protected send(payload: ErrorRequest): Promise<{
        id: string;
    }>;
    /**
     * It has to return Promise to be compatible with different implementations
     * e.g. Hono returns Promise when accessing req.json()
     */
    protected mapErrorRequestPayload(error: Error | unknown, request?: TRequest, context?: Record<string, unknown>): Promise<ErrorRequest>;
    protected mapAxiosRequestBody(error: AxiosError): any;
    protected mapAxiosError(error: AxiosError, request?: TRequest, context?: ErrorRequestContext): Promise<AxiosErrorRequest>;
    protected sanitizeValue(value: unknown, level?: number): unknown;
}

declare type BaseHandlerContext<TErrorUtility extends ExpressErrorUtility> = {
    instance: TErrorUtility;
};

export declare interface BasicMiddlewareOptions {
    projectName: string;
    apiKey: string;
}

declare class CloudflareErrorUtility extends BaseErrorUtility<HttpRequest> {
    protected mapRequest(req: HttpRequest): Promise<MappedHttpRequest>;
}
export { CloudflareErrorUtility }
export { CloudflareErrorUtility as CloudflareErrorUtility_alias_1 }

export declare type ErrorContext = Record<string, unknown>;

export declare type ErrorContext_alias_1 = Record<string, unknown>;

export declare type ErrorDetails<T extends Record<string, unknown> = Record<string, unknown>> = {
    name: string;
    message: string;
} & T;

export declare interface ErrorRequest<TDetails extends Record<string, unknown> = Record<string, unknown>> {
    errorName: string;
    errorDetails: ErrorDetails<TDetails>;
    stack: string | null;
    context: ErrorRequestContext;
    user: string;
    projectName: string;
}

export declare type ErrorRequestContext = Record<string, unknown> | null;

/**
 * Implements universal request mapping, you can map details from your request object manually.
 * See `sendErrorFromEndPoint` method.
 */
declare class ErrorUtility extends BaseErrorUtility<HttpRequest> {
    protected mapRequest<TRequest extends HttpRequest = HttpRequest>(req: TRequest): MappedHttpRequest;
    sendErrorFromEndPoint(error: unknown, request: HttpRequest, userContext?: Record<string, unknown> | undefined): Promise<SendErrorResponse>;
}
export { ErrorUtility }
export { ErrorUtility as ErrorUtility_alias_1 }
export { ErrorUtility as ErrorUtility_alias_2 }

export declare interface ErrorUtilityMethods<TRequest> {
    sendError(error: Error | unknown, userContext?: Record<string, unknown>): Promise<SendErrorResponse>;
    sendErrorFromEndPoint(error: Error | unknown, request: TRequest, userContext?: Record<string, unknown>): Promise<SendErrorResponse>;
}

export declare namespace express {
    export {
        ExpressErrorUtility,
        setupTryCatch,
        addContext
    }
}

/**
 * Implements request mapping for Express.
 * See `sendErrorFromEndPoint` method.
 */
declare class ExpressErrorUtility extends BaseErrorUtility<Request_2> {
    protected mapRequest(req: Request_2): MappedHttpRequest;
    /**
     * Sends error and Express request details to try-catch-cloud service.
     * ```
     * app.use((error, req, res, next) => {
     *  errorUtility.sendErrorFromEndPoint(error, req)
     *     .catch((e) => { ... });
     *
     *   res.status(500).json({ message: "Internal server error" });
     * });
     * ```
     */
    sendErrorFromEndPoint(error: unknown, request: Request_2, userContext?: Record<string, unknown> | undefined): Promise<SendErrorResponse>;
}
export { ExpressErrorUtility }
export { ExpressErrorUtility as ExpressErrorUtility_alias_1 }

export declare type ExpressMiddlewareSetup<TMiddlewareOptions extends BasicMiddlewareOptions> = (opts: TMiddlewareOptions) => {
    initialize: RequestHandler;
    onError: ErrorRequestHandler;
};

export declare type ExtendedRequest = Request_2 & {
    tryCatchContext: Record<string, unknown>;
};

declare interface FactoryContext<TInstance extends HonoErrorUtility> {
    instance: TInstance;
}

export declare namespace hono {
    export {
        HonoErrorUtility,
        tryCatch
    }
}

/**
 * Implements request mapping for Hono.
 * See `sendErrorFromEndPoint` method.
 */
declare class HonoErrorUtility extends BaseErrorUtility<HonoRequest> {
    protected mapRequest<TRequest extends HonoRequest = HonoRequest>(req: TRequest): Promise<MappedHttpRequest>;
    /**
     * Sends error and Hono request details to try-catch-cloud service.
     * ```
     * app.onError(async (err, ctx) => {
     *     errorUtility.sendErrorFromEndPoint(err, ctx.req, { ...errorContext })
     *         .catch((e) => { ... });
     *
     *     return ctx.json({ message: 'Internal server error' }, 500);
     * });
     * ```
     */
    sendErrorFromEndPoint(error: unknown, request: HonoRequest, userContext?: Record<string, unknown> | undefined): Promise<SendErrorResponse>;
}
export { HonoErrorUtility }
export { HonoErrorUtility as HonoErrorUtility_alias_1 }

export declare type HonoMiddlewareSetup<TMiddlewareOptions extends MiddlewareOptions = MiddlewareOptions> = (options: TMiddlewareOptions) => MiddlewareHandler;

export declare interface HttpRequest {
    url?: string;
    method?: string;
    path?: string;
    body?: unknown;
    query?: Record<string, unknown>;
    headers?: Record<string, unknown>;
}

export declare function isAxiosError(e: unknown): e is AxiosError;

export declare namespace lambda {
    export {
        tryCatch_alias_1 as tryCatch,
        addContext_alias_1 as addContext,
        LambdaErrorUtility
    }
}

declare class LambdaErrorUtility extends BaseErrorUtility<APIGatewayEventCommon> {
    protected mapRequest(request: APIGatewayEventCommon): MappedHttpRequest | Promise<MappedHttpRequest>;
    sendErrorFromEndPoint: (error: unknown, request: APIGatewayEventCommon, userContext?: Record<string, unknown> | undefined) => Promise<SendErrorResponse>;
}
export { LambdaErrorUtility }
export { LambdaErrorUtility as LambdaErrorUtility_alias_1 }

export declare interface MappedHttpRequest {
    method: string | null;
    url: string | null;
    requestBody: unknown | null;
    query: Record<string, unknown> | null;
    headers: Record<string, unknown> | null;
}

export declare interface MiddlewareOptions {
    projectName: string;
    apiKey: string;
    debug?: boolean;
}

export declare interface MiddlewareOptions_alias_1 {
    projectName: string;
    apiKey: string;
}

export declare type SendErrorResponse = {
    id: string;
} | undefined;

/**
 * It returns two handlers - `initialize` and `onError`.
 * Add `initialize` to your app using `app.use` before all route handlers.
 * Add `onError` after all route handlers and before other error handlers.
 *
 * @param MiddlewareOptions - pass project name and your API key here.
 */
export declare const setupTryCatch: ExpressMiddlewareSetup<BasicMiddlewareOptions>;

export declare const setupTryCatchFactory: <TErrorUtility extends ExpressErrorUtility, THandlerContext extends BaseHandlerContext<TErrorUtility>, TMiddlewareOptions extends BasicMiddlewareOptions = BasicMiddlewareOptions>(factoryOptions: {
    createContext: (options: TMiddlewareOptions) => THandlerContext;
    handlers: {
        initialize: (context: THandlerContext) => RequestHandler;
        onError: (context: THandlerContext) => ErrorRequestHandler;
    };
}) => ExpressMiddlewareSetup<TMiddlewareOptions>;

export declare const tryCatch: HonoMiddlewareSetup<MiddlewareOptions>;

export declare function tryCatch_alias_1({ projectName, apiKey, }: MiddlewareOptions_alias_1): MiddlewareObj<APIGatewayEventCommon>;

export declare interface TryCatchContext {
    addContext: (errorContext: ErrorContext) => void;
}

export declare const tryCatchFactory: <TInstance extends HonoErrorUtility, TFactoryContext extends FactoryContext<TInstance>>(factoryOptions: {
    createContext: (options: MiddlewareOptions) => TFactoryContext;
    handler: (context: TFactoryContext) => MiddlewareHandler;
}) => HonoMiddlewareSetup;

export declare class WrappedError extends Error {
    readonly value: unknown;
    constructor(message: string, value: unknown);
}

export { }
