/*
Type definitions for flows. Sync with mitmproxy/tools/web/app.py.
 */
interface _Flow {
    id: string;
    intercepted: boolean;
    is_replay: "request" | "response" | undefined;
    type: string;
    modified: boolean;
    marked: string;
    comment: string;
    timestamp_created: number;
    client_conn: Client;
    server_conn?: Server;
    error?: Error;
}

export type Flow = HTTPFlow | TCPFlow | UDPFlow | DNSFlow;

export interface HTTPFlow extends _Flow {
    type: "http";
    request: HTTPRequest;
    response?: HTTPResponse;
    websocket?: WebSocketData;
}

export interface TCPFlow extends _Flow {
    type: "tcp";
    messages_meta: MessagesMeta;
}

export interface UDPFlow extends _Flow {
    type: "udp";
    messages_meta: MessagesMeta;
}

export interface Error {
    msg: string;
    timestamp: number;
}

// IPv6 has flowinfo and scope_id (currently not correctly typed on the Python side)
export type Address = [string, number] | [string, number, number, number];

export interface Connection {
    id: string;
    peername?: Address;
    sockname?: Address;

    tls_established: boolean;
    cert?: Certificate;
    sni?: string | boolean;
    cipher?: string;
    alpn?: string;
    tls_version?: string;

    timestamp_start?: number;
    timestamp_tls_setup?: number;
    timestamp_end?: number;
}

export interface Client extends Connection {
    peername: Address;
    sockname: Address;
    timestamp_start: number;
}

export interface Server extends Connection {
    address?: Address;
    timestamp_tcp_setup?: number;
}

export interface Certificate {
    keyinfo: [string, number];
    sha256: string;
    notbefore: number;
    notafter: number;
    serial: string;
    subject: [string, string][];
    issuer: [string, string][];
    altnames: string[];
}

export type HTTPHeader = [name: string, value: string];
export type HTTPHeaders = HTTPHeader[];

export interface HTTPMessage {
    http_version: string;
    headers: HTTPHeaders;
    trailers?: HTTPHeaders;
    contentLength?: number;
    contentHash?: string;
    timestamp_start: number;
    timestamp_end?: number;
}

export interface HTTPRequest extends HTTPMessage {
    method: string;
    scheme: string;
    host: string;
    port: number;
    path: string;
    pretty_host: string;
}

export interface HTTPResponse extends HTTPMessage {
    status_code: number;
    reason: string;
}

export interface MessagesMeta {
    contentLength: number;
    count: number;
    timestamp_last?: number;
}

export interface WebSocketData {
    messages_meta: MessagesMeta;
    closed_by_client?: boolean;
    close_code?: number;
    close_reason?: string;
    timestamp_end?: number;
}

export interface DNSQuestion {
    name: string;
    type: string;
    class: string;
}

export interface DNSResourceRecord {
    name: string;
    type: string;
    class: string;
    ttl: number;
    data: string | { [key: string | number]: string };
}

export interface DNSMessage {
    id: number;
    query: boolean;
    op_code: string;
    authoritative_answer: boolean;
    truncation: boolean;
    recursion_desired: boolean;
    recursion_available: boolean;
    response_code: string;
    status_code: number;
    questions: DNSQuestion[];
    answers: DNSResourceRecord[];
    authorities: DNSResourceRecord[];
    additionals: DNSResourceRecord[];
    size: number;
    timestamp?: number;
}

export interface DNSFlow extends _Flow {
    type: "dns";
    request: DNSMessage;
    response?: DNSMessage;
}
