import { AuthScheme } from "./auth";
import { EndpointV2 } from "./endpoint";
import { Logger } from "./logger";
import { UserAgent } from "./util";
export interface InitializeHandlerArguments<Input extends object> {
  input: Input;
}
export interface InitializeHandlerOutput<Output extends object>
  extends DeserializeHandlerOutput<Output> {
  output: Output;
}
export interface SerializeHandlerArguments<Input extends object>
  extends InitializeHandlerArguments<Input> {
  request?: unknown;
}
export interface SerializeHandlerOutput<Output extends object>
  extends InitializeHandlerOutput<Output> {}
export interface BuildHandlerArguments<Input extends object>
  extends FinalizeHandlerArguments<Input> {}
export interface BuildHandlerOutput<Output extends object>
  extends InitializeHandlerOutput<Output> {}
export interface FinalizeHandlerArguments<Input extends object>
  extends SerializeHandlerArguments<Input> {
  request: unknown;
}
export interface FinalizeHandlerOutput<Output extends object>
  extends InitializeHandlerOutput<Output> {}
export interface DeserializeHandlerArguments<Input extends object>
  extends FinalizeHandlerArguments<Input> {}
export interface DeserializeHandlerOutput<Output extends object> {
  response: unknown;
  output?: Output;
}
export interface InitializeHandler<
  Input extends object,
  Output extends object
> {
  (args: InitializeHandlerArguments<Input>): Promise<
    InitializeHandlerOutput<Output>
  >;
}
export declare type Handler<
  Input extends object,
  Output extends object
> = InitializeHandler<Input, Output>;
export interface SerializeHandler<Input extends object, Output extends object> {
  (args: SerializeHandlerArguments<Input>): Promise<
    SerializeHandlerOutput<Output>
  >;
}
export interface FinalizeHandler<Input extends object, Output extends object> {
  (args: FinalizeHandlerArguments<Input>): Promise<
    FinalizeHandlerOutput<Output>
  >;
}
export interface BuildHandler<Input extends object, Output extends object> {
  (args: BuildHandlerArguments<Input>): Promise<BuildHandlerOutput<Output>>;
}
export interface DeserializeHandler<
  Input extends object,
  Output extends object
> {
  (args: DeserializeHandlerArguments<Input>): Promise<
    DeserializeHandlerOutput<Output>
  >;
}
export interface InitializeMiddleware<
  Input extends object,
  Output extends object
> {
  (
    next: InitializeHandler<Input, Output>,
    context: HandlerExecutionContext
  ): InitializeHandler<Input, Output>;
}
export interface SerializeMiddleware<
  Input extends object,
  Output extends object
> {
  (
    next: SerializeHandler<Input, Output>,
    context: HandlerExecutionContext
  ): SerializeHandler<Input, Output>;
}
export interface FinalizeRequestMiddleware<
  Input extends object,
  Output extends object
> {
  (
    next: FinalizeHandler<Input, Output>,
    context: HandlerExecutionContext
  ): FinalizeHandler<Input, Output>;
}
export interface BuildMiddleware<Input extends object, Output extends object> {
  (
    next: BuildHandler<Input, Output>,
    context: HandlerExecutionContext
  ): BuildHandler<Input, Output>;
}
export interface DeserializeMiddleware<
  Input extends object,
  Output extends object
> {
  (
    next: DeserializeHandler<Input, Output>,
    context: HandlerExecutionContext
  ): DeserializeHandler<Input, Output>;
}
export declare type MiddlewareType<
  Input extends object,
  Output extends object
> =
  | InitializeMiddleware<Input, Output>
  | SerializeMiddleware<Input, Output>
  | BuildMiddleware<Input, Output>
  | FinalizeRequestMiddleware<Input, Output>
  | DeserializeMiddleware<Input, Output>;
export interface Terminalware {
  <Input extends object, Output extends object>(
    context: HandlerExecutionContext
  ): DeserializeHandler<Input, Output>;
}
export declare type Step =
  | "initialize"
  | "serialize"
  | "build"
  | "finalizeRequest"
  | "deserialize";
export declare type Priority = "high" | "normal" | "low";
export interface HandlerOptions {
  step?: Step;
  tags?: Array<string>;
  name?: string;
  override?: boolean;
}
export interface AbsoluteLocation {
  priority?: Priority;
}
export declare type Relation = "before" | "after";
export interface RelativeLocation {
  relation: Relation;
  toMiddleware: string;
}
export declare type RelativeMiddlewareOptions = RelativeLocation &
  Pick<HandlerOptions, Exclude<keyof HandlerOptions, "step">>;
export interface InitializeHandlerOptions extends HandlerOptions {
  step?: "initialize";
}
export interface SerializeHandlerOptions extends HandlerOptions {
  step: "serialize";
}
export interface BuildHandlerOptions extends HandlerOptions {
  step: "build";
}
export interface FinalizeRequestHandlerOptions extends HandlerOptions {
  step: "finalizeRequest";
}
export interface DeserializeHandlerOptions extends HandlerOptions {
  step: "deserialize";
}
export interface MiddlewareStack<Input extends object, Output extends object>
  extends Pluggable<Input, Output> {
  add(
    middleware: InitializeMiddleware<Input, Output>,
    options?: InitializeHandlerOptions & AbsoluteLocation
  ): void;
  add(
    middleware: SerializeMiddleware<Input, Output>,
    options: SerializeHandlerOptions & AbsoluteLocation
  ): void;
  add(
    middleware: BuildMiddleware<Input, Output>,
    options: BuildHandlerOptions & AbsoluteLocation
  ): void;
  add(
    middleware: FinalizeRequestMiddleware<Input, Output>,
    options: FinalizeRequestHandlerOptions & AbsoluteLocation
  ): void;
  add(
    middleware: DeserializeMiddleware<Input, Output>,
    options: DeserializeHandlerOptions & AbsoluteLocation
  ): void;
  addRelativeTo(
    middleware: MiddlewareType<Input, Output>,
    options: RelativeMiddlewareOptions
  ): void;
  use(pluggable: Pluggable<Input, Output>): void;
  clone(): MiddlewareStack<Input, Output>;
  remove(toRemove: MiddlewareType<Input, Output> | string): boolean;
  removeByTag(toRemove: string): boolean;
  concat<InputType extends Input, OutputType extends Output>(
    from: MiddlewareStack<InputType, OutputType>
  ): MiddlewareStack<InputType, OutputType>;
  identify(): string[];
  resolve<InputType extends Input, OutputType extends Output>(
    handler: DeserializeHandler<InputType, OutputType>,
    context: HandlerExecutionContext
  ): InitializeHandler<InputType, OutputType>;
}
export interface HandlerExecutionContext {
  logger?: Logger;
  userAgent?: UserAgent;
  endpointV2?: EndpointV2;
  authSchemes?: AuthScheme[];
  [key: string]: any;
}
export interface Pluggable<Input extends object, Output extends object> {
  applyToStack: (stack: MiddlewareStack<Input, Output>) => void;
}
