export type HttpMethod
    = 'GET'
    | 'HEAD'
    | 'POST'
    | 'PUT'
    | 'DELETE'
    | 'CONNECT'
    | 'OPTIONS'
    | 'TRACE'
    | 'PATCH'
    ;
export type HttpStatusCode = { readonly value: number };
export type ReadonlyHeaderValue = string | undefined;
export type HeaderValue = number | ReadonlyHeaderValue;
export type ReadonlyHeaderValues = (readonly string[]) | ReadonlyHeaderValue
export type HeaderValues = (readonly string[]) | HeaderValue

export interface HttpHeaders {
    get(name: string): HeaderValues
    list(name: string): string[]
    one(name: string): HeaderValue
    has(name: string): boolean
    keys(): IteratorObject<string>
}

export interface ReadonlyHttpHeaders extends HttpHeaders {
    get(name: string): ReadonlyHeaderValues
    one(name: string): string | undefined
}

export interface MutableHttpHeaders extends HttpHeaders {
    get(name: string): HeaderValues
    one(name: string): HeaderValue
    set(name: string, value: HeaderValues): this
    add(name: string, value: string | (readonly string[])): this
}

export type HttpMessage<Headers = HttpHeaders> = {
    readonly headers: Headers
}

export type HttpInputMessage<Headers = HttpHeaders> = HttpMessage<Headers> & {
    readonly body?: ReadableStream<BodyChunk>
    blob(): Promise<Blob>
}
export type BodyChunk = BlobPart;
export type HttpOutputMessage<Headers = HttpHeaders> = HttpMessage<Headers> & {
    body(body: ReadableStream<BodyChunk> | Promise<BodyChunk | void> | BodyChunk): Promise<boolean>
    // alias for body(Promise.resolve())
    end(): Promise<boolean>
}

export type HttpRequest<Headers = HttpHeaders> = HttpMessage<Headers> & {
    readonly method: HttpMethod
    readonly URL: URL
    readonly cookies: HttpCookie[]
}

export type HttpResponse<Headers = HttpHeaders> = HttpMessage<Headers> & {
    readonly statusCode: HttpStatusCode
    readonly cookies: ResponseCookie[]
}

export type HttpCookie = {
    readonly name: string,
    readonly value: string
}

export type ResponseCookie = HttpCookie & {
    readonly domain?: string,
    readonly httpOnly?: boolean,
    readonly maxAge: number,
    readonly path?: string,
    readonly sameSite?: 'strict' | 'lax' | 'none',
    readonly secure?: boolean
}
