import type { Pipe, Strings, Tuples } from 'hotscript';
import type { FromSchema as FromSchemaOriginal, JSONSchema as JSONSchemaOrBoolean } from 'json-schema-to-ts';
import type { ErrorHandler, FetchAPI, ServerAdapter, ServerAdapterOptions, ServerAdapterPlugin, ServerAdapterRequestHandler } from '@whatwg-node/server';
import type { ClientTypedResponsePromise } from './client/clientResponse.js';
import type { ClientRequestInit } from './client/types.js';
import type { SwaggerUIOpts } from './plugins/openapi.js';
import type { HTTPMethod, StatusCode, TypedRequest, TypedResponse, TypedResponseWithJSONStatusMap } from './typed-fetch.js';
export { TypedRequest as RouterRequest };
export type Simplify<T> = {
    [KeyType in keyof T]: Simplify<T[KeyType]>;
} & {};
export type JSONSerializer = (obj: any) => string;
export type JSONSchema = Exclude<JSONSchemaOrBoolean, boolean>;
export interface OpenAPIInfo {
    title?: string;
    description?: string;
    version?: string;
    license?: {
        name?: string;
        url?: string;
    };
    termsOfService?: string;
    contact?: {
        name?: string;
        url?: string;
        email?: string;
    };
}
export type OpenAPIPathObject = Record<string, OpenAPIOperationObject> & {
    parameters?: OpenAPIParameterObject[];
};
export interface OpenAPIParameterObject {
    name: string;
    in: 'path' | 'query' | 'header' | 'cookie';
    required?: boolean;
    schema?: any;
}
export interface OpenAPIRequestBodyObject {
    content?: Record<string, OpenAPIMediaTypeObject>;
}
export interface OpenAPIOperationObject {
    operationId?: string;
    description?: string;
    tags?: string[];
    parameters?: OpenAPIParameterObject[];
    requestBody?: OpenAPIRequestBodyObject;
    responses?: Record<string | number, OpenAPIResponseObject>;
    security?: any[];
}
export interface OpenAPIResponseObject {
    description?: string;
    content?: Record<string, OpenAPIMediaTypeObject>;
}
export interface OpenAPIMediaTypeObject {
    schema?: any;
}
export type OpenAPIDocument = {
    openapi?: string;
    info?: OpenAPIInfo;
    servers?: {
        url: string;
    }[] | string[];
    paths?: Record<string, OpenAPIPathObject>;
    components?: unknown;
};
export interface RouterOpenAPIOptions<TComponents extends RouterComponentsBase> extends OpenAPIDocument {
    endpoint?: string | false;
    components?: TComponents;
    includeValidationErrors?: boolean;
}
export interface RouterSwaggerUIOptions extends SwaggerUIOpts {
    endpoint?: string | false;
}
export interface RouterOptions<TServerContext, TComponents extends RouterComponentsBase> extends ServerAdapterOptions<TServerContext> {
    base?: string;
    plugins?: RouterPlugin<TServerContext, TComponents>[];
    openAPI?: RouterOpenAPIOptions<TComponents>;
    swaggerUI?: RouterSwaggerUIOptions;
    landingPage?: boolean;
    onError?: ErrorHandler<TServerContext>;
}
export type RouterComponentsBase = {
    schemas?: Record<string, JSONSchema>;
    securitySchemes?: Record<string, SecurityScheme>;
};
export type BasicAuthSecurityScheme = {
    type: 'http';
    scheme: 'basic';
};
export type BearerAuthSecurityScheme = {
    type: 'http';
    scheme: 'bearer';
};
export type ApiKeySecurityScheme = {
    type: 'apiKey';
    name: string;
    in: 'header' | 'query' | 'cookie';
};
export type SecurityScheme = BasicAuthSecurityScheme | BearerAuthSecurityScheme | ApiKeySecurityScheme;
export type Circular<TJSONSchema extends JSONSchema> = TJSONSchema extends {
    properties: {
        [key: string]: JSONSchema;
    };
} ? TJSONSchema extends PropertyValue<TJSONSchema, Property<TJSONSchema>> ? true : [Extract<PropertyValue<TJSONSchema, Property<TJSONSchema>>, {
    $id: string;
}>] extends [never] ? [ArrayItemValue<PropertyValue<TJSONSchema, Property<TJSONSchema>>>] extends [never] ? Circular<PropertyValue<TJSONSchema, Property<TJSONSchema>>> : ArrayItemValue<PropertyValue<TJSONSchema, Property<TJSONSchema>>> extends TJSONSchema ? true : Circular<PropertyValue<TJSONSchema, Property<TJSONSchema>>> : true : false;
export type Property<TJSONSchema extends JSONSchema> = keyof TJSONSchema['properties'];
export type PropertyValue<TJSONSchema extends JSONSchema, TProperty extends keyof TJSONSchema['properties']> = TJSONSchema['properties'][TProperty];
export type ArrayItemValue<TJSONSchema extends JSONSchema> = TJSONSchema extends {
    items: infer TItems extends JSONSchema;
} ? TItems : never;
export type FromSchema<T> = T extends {
    static: infer U;
} ? U : T extends JSONSchema ? FromSchemaOriginal<T, {
    deserialize: Circular<T> extends false ? [
        {
            pattern: {
                type: 'string';
                format: 'binary';
            };
            output: File;
        },
        {
            pattern: {
                type: 'number';
                format: 'int64';
            };
            output: bigint | number;
        },
        {
            pattern: {
                type: 'integer';
                format: 'int64';
            };
            output: bigint | number;
        }
    ] : false;
}> : never;
export type FromRouterComponentSchema<TRouter extends Router<any, any, any>, TName extends string> = TRouter extends Router<any, infer TComponents, any> ? TComponents extends Required<RouterComponentsBase> ? FromSchema<TComponents['schemas'][TName]> : never : never;
export type PromiseOrValue<T> = T | Promise<T>;
export type StatusCodeMap<T> = {
    [TKey in StatusCode]?: T;
};
export interface RouterBaseObject<TServerContext, TComponents extends RouterComponentsBase, TRouterSDK extends RouterSDK<string, TypedRequest, TypedResponse>> {
    openAPIDocument: OpenAPIDocument;
    handle: ServerAdapterRequestHandler<TServerContext>;
    route<const TRouteSchemas extends RouteSchemas, TMethod extends HTTPMethod, TPath extends string, TTypedRequest extends TypedRequestFromRouteSchemas<TComponents, TRouteSchemas, TMethod, TPath>, TTypedResponse extends TypedResponseFromRouteSchemas<TComponents, TRouteSchemas>>(opts: RouteWithSchemasOpts<TServerContext, TComponents, TRouteSchemas, TMethod, TPath, TTypedRequest, TTypedResponse>): Router<TServerContext, TComponents, TRouterSDK & RouterSDK<TPath, TTypedRequest, TTypedResponse>>;
    route<TMethod extends HTTPMethod, TPath extends string, TTypedRequest extends TypedRequest<any, Record<string, FormDataEntryValue | undefined>, Record<string, string | undefined>, TMethod, any, Record<ExtractPathParamsWithPattern<TPath>, string>>, TTypedResponse extends TypedResponse>(opts: RouteWithTypesOpts<TServerContext, TMethod, TPath, TTypedRequest, TTypedResponse>): Router<TServerContext, TComponents, TRouterSDK & RouterSDK<TPath, TTypedRequest, TTypedResponse>>;
    use<TSubServerContext, TSubComponents extends RouterComponentsBase, TSubRouterSDK extends RouterSDK<string, TypedRequest, TypedResponse>>(subRouter: Router<TSubServerContext, TSubComponents, TSubRouterSDK>): Router<TServerContext, TComponents, TRouterSDK & TSubRouterSDK>;
    use<const TPrefix extends string, TSubServerContext, TSubComponents extends RouterComponentsBase, TSubRouterSDK extends RouterSDK<string, TypedRequest, TypedResponse>>(prefix: TPrefix, subRouter: Router<TSubServerContext, TSubComponents, TSubRouterSDK>): Router<TServerContext, TComponents, TRouterSDK & {
        [TKey in keyof TSubRouterSDK as TKey extends string ? `${TPrefix}${TKey}` : TKey]: TSubRouterSDK[TKey];
    }>;
    __client: TRouterSDK;
    __onRouterInitHooks: OnRouterInitHook<TServerContext>[];
    __routes: RouteWithSchemasOpts<any, RouterComponentsBase, RouteSchemas, HTTPMethod, string, TypedRequest, TypedResponse>[];
    __base: string;
}
export type Router<TServerContext, TComponents extends RouterComponentsBase, TRouterSDK extends RouterSDK<string, TypedRequest, TypedResponse>> = ServerAdapter<TServerContext, RouterBaseObject<TServerContext, TComponents, TRouterSDK>>;
export type OnRouteHook<TServerContext> = (payload: OnRouteHookPayload<TServerContext>) => void;
export type OnRouteHandleHook<TServerContext, TComponents extends RouterComponentsBase> = (payload: OnRouteHandleHookPayload<TServerContext, TComponents>) => void;
export interface OnRouteHandleHookPayload<TServerContext, TComponents extends RouterComponentsBase> {
    request: TypedRequest;
    route: RouteWithSchemasOpts<TServerContext, TComponents, RouteSchemas, HTTPMethod, string, TypedRequest, TypedResponse>;
}
export type RouteHandler<TServerContext = {}, TTypedRequest extends TypedRequest = TypedRequest, TTypedResponse extends TypedResponse = TypedResponse> = (
/**
 * The request object represents the incoming HTTP request.
 * This object implements [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) interface.
 */
request: TTypedRequest, context: TServerContext) => PromiseOrValue<TTypedResponse>;
export type OnRouteHookPayload<TServerContext> = {
    basePath: string;
    openAPIDocument: OpenAPIDocument;
    routeByPatternByMethod: Map<HTTPMethod, Map<URLPattern, RouteWithSchemasOpts<any, RouterComponentsBase, RouteSchemas, HTTPMethod, string, TypedRequest, TypedResponse>>>;
    routeByPathByMethod: Map<HTTPMethod, Map<string, RouteWithSchemasOpts<any, RouterComponentsBase, RouteSchemas, HTTPMethod, string, TypedRequest, TypedResponse>>>;
    route: RouteWithSchemasOpts<TServerContext, RouterComponentsBase, RouteSchemas, HTTPMethod, string, TypedRequest, TypedResponse>;
    fetchAPI: FetchAPI;
};
export type OnRouterInitHook<TServerContext> = (router: Router<TServerContext, any, any>) => void;
export type RouterPlugin<TServerContext, TComponents extends RouterComponentsBase> = ServerAdapterPlugin<TServerContext> & {
    onRouterInit?: OnRouterInitHook<TServerContext>;
    onRoute?: OnRouteHook<TServerContext>;
    onRouteHandle?: OnRouteHandleHook<TServerContext, TComponents>;
};
type ObjectSchemaWithPrimitiveProperties = JSONSchema & {
    type: 'object';
    properties: Record<string, {
        type: 'string' | 'number' | 'integer' | 'boolean' | 'null';
    }>;
};
type ObjectSchema = JSONSchema & {
    type: 'object';
};
export type RouteSchemas = {
    request?: {
        headers?: ObjectSchemaWithPrimitiveProperties;
        params?: ObjectSchemaWithPrimitiveProperties;
        query?: ObjectSchema;
        json?: JSONSchema;
        formData?: ObjectSchema;
    };
    responses?: StatusCodeMap<JSONSchema>;
};
export type RouterSDKOpts<TTypedRequest extends TypedRequest = TypedRequest, TMethod extends HTTPMethod = HTTPMethod> = TTypedRequest extends TypedRequest<infer TJSONBody, infer TFormData, infer THeaders, TMethod, infer TQueryParams, infer TPathParam> ? Simplify<(Partial<TJSONBody> extends TJSONBody ? {
    json?: TJSONBody;
} : {
    json: TJSONBody;
}) & (Partial<THeaders> extends THeaders ? {
    headers?: THeaders;
} : {
    headers: THeaders;
}) & (Partial<TQueryParams> extends TQueryParams ? {
    query?: TQueryParams;
} : {
    query: TQueryParams;
}) & (Partial<TPathParam> extends TPathParam ? {
    params?: TPathParam;
} : {
    params: TPathParam;
})> & (Partial<TFormData> extends TFormData ? {
    formData?: TFormData;
} : {
    formData: TFormData;
}) : never;
export type RouterSDK<TPath extends string = string, TTypedRequest extends TypedRequest = TypedRequest, TTypedResponse extends TypedResponse = TypedResponse> = {
    [TPathKey in TPath]: {
        [TMethod in Lowercase<TTypedRequest['method']>]: Partial<RouterSDKOpts<TTypedRequest, TTypedRequest['method']>> extends RouterSDKOpts<TTypedRequest, TTypedRequest['method']> ? (opts?: RouterSDKOpts<TTypedRequest, TTypedRequest['method']> & ClientRequestInit) => ClientTypedResponsePromise<Exclude<TTypedResponse, undefined>> : (opts: RouterSDKOpts<TTypedRequest, TTypedRequest['method']> & ClientRequestInit) => ClientTypedResponsePromise<Exclude<TTypedResponse, undefined>>;
    };
};
export type FromSchemaWithComponents<TComponents, TSchema extends JSONSchema> = TComponents extends {
    schemas: Record<string, JSONSchema>;
} ? FromSchema<{
    components: TComponents;
} & TSchema> : FromSchema<TSchema>;
export type TypedRequestFromRouteSchemas<TComponents extends RouterComponentsBase, TRouteSchemas extends RouteSchemas, TMethod extends HTTPMethod, TPath extends string> = TRouteSchemas extends {
    request: Required<RouteSchemas>['request'];
} ? TypedRequest<TRouteSchemas['request'] extends {
    json: JSONSchema;
} ? FromSchemaWithComponents<TComponents, TRouteSchemas['request']['json']> : {}, TRouteSchemas['request'] extends {
    formData: JSONSchema;
} ? FromSchemaWithComponents<TComponents, TRouteSchemas['request']['formData']> extends Record<string, FormDataEntryValue | undefined> ? FromSchemaWithComponents<TComponents, TRouteSchemas['request']['formData']> : never : {}, TRouteSchemas['request'] extends {
    headers: JSONSchema;
} ? FromSchemaWithComponents<TComponents, TRouteSchemas['request']['headers']> extends Record<string, string> ? FromSchemaWithComponents<TComponents, TRouteSchemas['request']['headers']> : never : {}, TMethod, TRouteSchemas['request'] extends {
    query: JSONSchema;
} ? FromSchemaWithComponents<TComponents, TRouteSchemas['request']['query']> : {}, TRouteSchemas['request'] extends {
    params: JSONSchema;
} ? FromSchemaWithComponents<TComponents, TRouteSchemas['request']['params']> extends Record<string, any> ? FromSchemaWithComponents<TComponents, TRouteSchemas['request']['params']> : never : Record<ExtractPathParamsWithPattern<TPath>, string>> : TypedRequest<any, Partial<Record<string, FormDataEntryValue>>, Partial<Record<string, string>>, TMethod, any, Record<ExtractPathParamsWithPattern<TPath>, string>>;
export type TypedResponseFromRouteSchemas<TComponents extends RouterComponentsBase, TRouteSchemas extends RouteSchemas> = TRouteSchemas extends {
    responses: StatusCodeMap<JSONSchema>;
} ? TypedResponseWithJSONStatusMap<{
    [TStatusCode in keyof TRouteSchemas['responses']]: TRouteSchemas['responses'][TStatusCode] extends JSONSchema ? FromSchemaWithComponents<TComponents, TRouteSchemas['responses'][TStatusCode]> : never;
}> : TypedResponse;
export type RouteWithSchemasOpts<TServerContext, TComponents extends RouterComponentsBase, TRouteSchemas extends RouteSchemas, TMethod extends HTTPMethod, TPath extends string, TTypedRequest extends TypedRequestFromRouteSchemas<TComponents, TRouteSchemas, TMethod, TPath>, TTypedResponse extends TypedResponseFromRouteSchemas<TComponents, TRouteSchemas>> = {
    schemas: TRouteSchemas;
    security?: SecuritySchemeRefsFromComponents<TComponents>[];
} & RouteWithTypesOpts<TServerContext, TMethod, TPath, TTypedRequest, TTypedResponse>;
export type SecuritySchemeRefsFromComponents<TComponents extends RouterComponentsBase> = TComponents extends {
    securitySchemes: Record<string, SecurityScheme>;
} ? Record<keyof TComponents['securitySchemes'], any> : never;
export type RouteWithTypesOpts<TServerContext, TMethod extends HTTPMethod, TPath extends string, TTypedRequest extends TypedRequest<any, Record<string, FormDataEntryValue | undefined>, Record<string, string | undefined>, TMethod, any, Record<ExtractPathParamsWithPattern<TPath>, string>>, TTypedResponse extends TypedResponse> = {
    operationId?: string;
    description?: string;
    method?: TMethod;
    tags?: string[];
    internal?: boolean;
    path: TPath;
    handler: RouteHandler<TServerContext, TTypedRequest, TTypedResponse>;
};
export type RouteInput<TRouter extends Router<any, any, {}>, TPath extends string, TMethod extends Lowercase<HTTPMethod> = 'post', TParamType extends keyof RouterSDKOpts = 'json'> = TRouter extends Router<any, any, infer TRouterSDK> ? TRouterSDK[TPath][TMethod] extends (requestParams?: infer TRequestParams) => any ? TRequestParams extends {
    [TParamTypeKey in TParamType]?: infer TParamTypeValue;
} ? TParamTypeValue : never : never : never;
export type RouteOutput<TRouter extends Router<any, any, {}>, TPath extends string, TMethod extends Lowercase<HTTPMethod> = 'post', TStatusCode extends StatusCode = 200> = TRouter extends Router<any, any, infer TRouterSDK> ? TRouterSDK extends RouterSDK ? TRouterSDK[TPath][TMethod] extends (...args: any[]) => Promise<infer TTypedResponse> ? TTypedResponse extends TypedResponse<infer TJSONBody, any, TStatusCode> ? TJSONBody : never : never : never : never;
export type RouterClient<TRouter extends Router<any, any, any>> = TRouter['__client'];
export type RouterInput<TRouter extends Router<any, any, any>> = {
    [TPath in keyof RouterClient<TRouter>]: {
        [TMethod in keyof RouterClient<TRouter>[TPath]]: RouterClient<TRouter>[TPath][TMethod] extends (requestParams?: infer TRequestParams) => any ? Required<TRequestParams> : never;
    };
};
export type RouterJsonPostInput<TRouter extends Router<any, any, any>> = {
    [TPath in keyof RouterClient<TRouter>]: {
        [TMethod in keyof RouterClient<TRouter>[TPath]]: RouterInput<TRouter>[TPath][TMethod] extends {
            json: infer TJSON;
        } ? TJSON : never;
    }['post'];
};
export type RouterJsonPostSuccessOutput<TRouter extends Router<any, any, any>> = {
    [TPath in keyof RouterClient<TRouter>]: {
        [TMethod in keyof RouterClient<TRouter>[TPath]]: RouterOutput<TRouter>[TPath][TMethod][200];
    }['post'];
};
export type RouterOutput<TRouter extends Router<any, any, any>> = {
    [TPath in keyof RouterClient<TRouter>]: {
        [TMethod in keyof RouterClient<TRouter>[TPath]]: RouterClient<TRouter>[TPath][TMethod] extends (requestParams?: any) => Promise<infer TTypedResponse> ? {
            [TStatusCode in StatusCode]: TTypedResponse extends TypedResponse<infer TJSONBody, any, TStatusCode> ? TJSONBody : never;
        } : never;
    };
};
export type RouterComponentSchema<TRouter extends Router<any, any, any>, TName extends string> = TRouter extends Router<any, infer TComponents, any> ? TComponents extends {
    schemas: Record<string, JSONSchema>;
} ? FromSchema<TComponents['schemas'][TName]> : never : never;
type SplitByDelimiter<T extends string, D extends string> = T extends `${infer P}${D}${infer Q}` ? [P, ...SplitByDelimiter<Q, D>] : [T];
type IsPathParameter<T extends string> = T extends `{${infer U}}` ? U : never;
type ExtractPathParametersFromSegment<T extends string> = IsPathParameter<T>;
type ExtractPathParameters<T extends any[]> = {
    [K in keyof T]: ExtractPathParametersFromSegment<T[K]>;
};
type TupleToUnion<T> = T extends any[] ? T[number] : never;
type ExtractSegments<TPath extends string> = SplitByDelimiter<TPath, '/'>;
type ExtractSubSegments<T extends any[]> = {
    [K in keyof T]: SplitByDelimiter<T[K], ';'>;
};
export type ExtractPathParamsWithBrackets<TPath extends string> = TupleToUnion<ExtractPathParameters<ExtractSubSegments<ExtractSegments<TPath>>[number]>>;
export type ExtractPathParamsWithPattern<TPath extends string> = Pipe<TPath, [
    Strings.Split<'/'>,
    Tuples.Filter<Strings.StartsWith<':'>>,
    Tuples.Map<Strings.Trim<':'>>,
    Tuples.ToUnion
]>;
