import { TSchema, TObject, Static } from '@sinclair/typebox';
import { OpenAPIV3_1 } from 'openapi-types';

type HTTPMethods = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS" | "HEAD" | "TRACE";
type RequestOptions = Omit<RequestInit, "headers"> & {
    headers: Headers;
};
declare namespace Hooks {
    type BeforeRequest = (data: {
        request: RequestOptions;
        data: any;
        url: string;
        event: string;
        webhook: Webhook;
        custom: Record<string, any>;
    }) => any;
    type AfterResponse = (data: {
        response: Response;
        request: RequestOptions;
        url: string;
        body: any;
        data: any;
        event: string;
        webhook: Webhook;
        custom: Record<string, any>;
    }) => any;
    type SendError = (data: {
        request: RequestOptions;
        data: any;
        url: string;
        event: string;
        webhook: Webhook;
        error: Error;
    }) => any;
    interface Store {
        beforeRequest: BeforeRequest[];
        afterResponse: AfterResponse[];
        sendError: SendError[];
    }
}
type MaybePromise<T> = Promise<T> | T;
type MimeTypeHelpers = Record<string, {
    serialization: (data: any) => MaybePromise<BodyInit>;
    deserialization: (response: Response) => MaybePromise<any>;
}>;

declare class WebhookEvent<Body extends TSchema | null = null, Response extends TSchema | null = null> {
    openapi: OpenAPIV3_1.PathItemObject | OpenAPIV3_1.ReferenceObject;
    _: {
        method: Lowercase<HTTPMethods>;
        body: TSchema | null;
        bodyHeaders: TObject | null;
        response: TSchema | null;
    };
    bodyHeaders<Schema extends TObject>(schema: Schema): this;
    body<Schema extends TSchema>(schema: Schema): WebhookEvent<Schema>;
    body<Schema extends TSchema>(contentType: string, schema: Schema): WebhookEvent<Schema, Response>;
    response<Schema extends TSchema>(schema: Schema, options?: OpenAPIV3_1.ResponseObject): WebhookEvent<Body, Schema>;
}

declare class Webhook<Events extends Record<string, {
    body: TSchema;
    response: TSchema;
}> = {}> {
    openapi: Omit<OpenAPIV3_1.Document, "webhooks"> & {
        webhooks: NonNullable<OpenAPIV3_1.Document["webhooks"]>;
    };
    private mimeTypes;
    private hooks;
    constructor();
    extend<WebhookPlugin extends Webhook<any>>(webhook: WebhookPlugin): Webhook<Events & (WebhookPlugin extends Webhook<infer E> ? E : never)>;
    private runHooks;
    private runMutationHooks;
    onBeforeRequest(hook: Hooks.BeforeRequest): this;
    onAfterResponse(hook: Hooks.AfterResponse): this;
    onSendError(hook: Hooks.SendError): this;
    mimeType(mimeType: string, options: MimeTypeHelpers[string]): this;
    event<Name extends string, Event extends WebhookEvent>(name: Name, event: (event: WebhookEvent) => Event, params?: Omit<OpenAPIV3_1.PathItemObject, OpenAPIV3_1.HttpMethods>): Webhook<Events & { [K in Name]: Event extends WebhookEvent<infer Body, infer Response> ? {
        body: Body;
        response: Response;
    } : never; }>;
    call<Event extends keyof Events & string>(url: string, event: Event, params: Static<Events[Event]["body"]>, requestOptions?: Partial<RequestOptions> & {
        custom?: Record<string, any>;
        mimeType?: string;
    }): Promise<null>;
}

export { type HTTPMethods as H, Webhook as W, WebhookEvent as a };
