import type { EventEmitter } from 'events';

import type { TinyRaftEvents } from './tinyraft';

export type AntiEtcdEvents = {
    raftchange: TinyRaftEvents['change'],
};

export class AntiEtcd extends EventEmitter<AntiEtcdEvents>
{
    constructor(cfg: object);
    start(): Promise<void>;
    stop(): Promise<void>;
    api(path: 'kv_txn'|'kv_range'|'kv_put'|'kv_deleterange'|'lease_grant'|'lease_revoke'|'lease_keepalive', params: object): Promise<object>;
    txn(params: TxnRequest): Promise<TxnResponse>;
    range(params: RangeRequest): Promise<RangeResponse>;
    put(params: PutRequest): Promise<PutResponse>;
    deleterange(params: DeleteRangeRequest): Promise<DeleteRangeResponse>;
    lease_grant(params: LeaseGrantRequest): Promise<LeaseGrantResponse>;
    lease_revoke(params: LeaseRevokeRequest): Promise<LeaseRevokeResponse>;
    lease_keepalive(params: LeaseKeepaliveRequest): Promise<LeaseKeepaliveResponse>;
    create_watch(params: WatchCreateRequest, callback: (ServerMessage) => void): Promise<string|number>;
    cancel_watch(watch_id: string|number): Promise<void>;
}

export type TxnRequest = {
    compare?: (
        { key: string, target: "MOD", mod_revision: number, result?: "LESS" }
        | { key: string, target: "CREATE", create_revision: number, result?: "LESS" }
        | { key: string, target: "VERSION", version: number, result?: "LESS" }
        | { key: string, target: "LEASE", lease: string, result?: "LESS" }
        | { key: string, target: "VALUE", value: string }
    )[],
    success?: (
        { request_put: PutRequest }
        | { request_range: RangeRequest }
        | { request_delete_range: DeleteRangeRequest }
    )[],
    failure?: (
        { request_put: PutRequest }
        | { request_range: RangeRequest }
        | { request_delete_range: DeleteRangeRequest }
    )[],
    serializable?: boolean,
};

export type TxnResponse = {
    header: { revision: number },
    succeeded: boolean,
    responses: (
        { response_put: PutResponse }
        | { response_range: RangeResponse }
        | { response_delete_range: DeleteRangeResponse }
    )[],
};

export type PutRequest = {
    key: string,
    value: string,
    lease?: string,
};

export type PutResponse = {
    header: { revision: number },
};

export type RangeRequest = {
    key: string,
    range_end?: string,
    keys_only?: boolean,
    serializable?: boolean,
};

export type RangeResponse = {
    header: { revision: number },
    kvs: { key: string }[] | {
        key: string,
        value: string,
        lease?: string,
        mod_revision: number,
    }[],
};

export type DeleteRangeRequest = {
    key: string,
    range_end?: string,
};

export type DeleteRangeResponse = {
    header: { revision: number },
    // number of deleted keys
    deleted: number,
};

export type LeaseGrantRequest = {
    ID?: string,
    TTL: number,
};

export type LeaseGrantResponse = {
    header: { revision: number },
    ID: string,
    TTL: number,
};

export type LeaseKeepaliveRequest = {
    ID: string,
};

export type LeaseKeepaliveResponse = {
    result: {
        header: { revision: number },
        ID: string,
        TTL: number,
    }
};

export type LeaseRevokeRequest = {
    ID: string,
};

export type LeaseRevokeResponse = {
    header: { revision: number },
};

export type WatchCreateRequest = {
    key: string,
    range_end?: string,
    start_revision?: number,
    watch_id?: string|number,
}

export type ClientMessage =
    { create_request: WatchCreateRequest }
    | { cancel_request: { watch_id: string } }
    | { progress_request: {} };

export type ServerMessage = {
    result: {
        header: { revision: number },
        watch_id: string|number,
        created?: boolean,
        canceled?: boolean,
        compact_revision?: number,
        events?: {
            type: 'PUT'|'DELETE',
            kv: {
                key: string,
                value: string,
                lease?: string,
                mod_revision: number,
            },
        }[],
    }
} | { error: 'bad-json' } | { error: 'empty-message' };
