import * as Express from 'express';
import { InputExecutionResult, InputError } from '..';
import { BaseContext } from '../api/context';
import { PathParams } from 'express-serve-static-core';
export interface RequestHandler<C extends BaseContext, T extends Application<C>> {
    (req: Request<C, T>, res: Response<C, T>, next: Express.NextFunction): any;
}
export declare type ErrorRequestHandler<C extends BaseContext, T extends Application<C>> = (err: any, req: Request<C, T>, res: Response<C, T>, next: Express.NextFunction) => any;
export declare type RequestHandlerParams<C extends BaseContext, T extends Application<C>> = RequestHandler<C, T> | ErrorRequestHandler<C, T> | (RequestHandler<C, T> | ErrorRequestHandler<C, T>)[];
export interface IRouterMatcher<C extends BaseContext, T extends Application<C>> {
    <C extends BaseContext = C, T extends Application<C> = Application<C>>(path: PathParams, ...handlers: RequestHandler<C, Application<C>>[]): T;
    <C extends BaseContext = C, T extends Application<C> = Application<C>>(path: PathParams, ...handlers: RequestHandlerParams<C, Application<C>>[]): T;
}
export interface IRouterHandler<C extends BaseContext, T extends Application<C>> {
    <C extends BaseContext = C, T extends Application<C> = Application<C>>(...handlers: RequestHandler<C, Application<C>>[]): T;
    <C extends BaseContext = C, T extends Application<C> = Application<C>>(...handlers: RequestHandlerParams<C, Application<C>>[]): T;
}
export declare type ApplicationRequestHandler<C extends BaseContext, T extends Application<C>> = IRouterHandler<C, T> & IRouterMatcher<C, T> & ((...handlers: RequestHandlerParams<C, T>[]) => T);
export interface Request<C extends BaseContext = BaseContext, T extends Application<C> = Application<C>> extends Express.Request {
    context: C;
    app: T;
}
export interface Response<C extends BaseContext = BaseContext, T extends Application<C> = Application<C>> extends Express.Response {
    context: C;
    app: T;
    sendResult(result: InputExecutionResult): this;
    sendData(data: {
        [name: string]: any;
    }): this;
    sendErrors(errors: InputError[]): this;
}
export interface Application<C extends BaseContext = BaseContext> extends Express.Application {
    all: IRouterMatcher<C, this>;
    get: IRouterMatcher<C, this>;
    post: IRouterMatcher<C, this>;
    put: IRouterMatcher<C, this>;
    delete: IRouterMatcher<C, this>;
    patch: IRouterMatcher<C, this>;
    options: IRouterMatcher<C, this>;
    head: IRouterMatcher<C, this>;
    checkout: IRouterMatcher<C, this>;
    connect: IRouterMatcher<C, this>;
    copy: IRouterMatcher<C, this>;
    lock: IRouterMatcher<C, this>;
    merge: IRouterMatcher<C, this>;
    mkactivity: IRouterMatcher<C, this>;
    mkcol: IRouterMatcher<C, this>;
    move: IRouterMatcher<C, this>;
    "m-search": IRouterMatcher<C, this>;
    notify: IRouterMatcher<C, this>;
    propfind: IRouterMatcher<C, this>;
    proppatch: IRouterMatcher<C, this>;
    purge: IRouterMatcher<C, this>;
    report: IRouterMatcher<C, this>;
    search: IRouterMatcher<C, this>;
    subscribe: IRouterMatcher<C, this>;
    trace: IRouterMatcher<C, this>;
    unlock: IRouterMatcher<C, this>;
    unsubscribe: IRouterMatcher<C, this>;
    use: IRouterHandler<C, this> & IRouterMatcher<C, this>;
}
