import { fetchEventSource } from '@microsoft/fetch-event-source';


export interface ResponseE {
    e: string,
    o: null
}
interface ResponseO<T> {
    e: null,
    o: T
}
export type Response<T> = ResponseE | ResponseO<T>;

export interface LoginResponse {
    otp_needed: boolean;
    token: (string|null);
}

export interface Session {
    name: string;
    tfa_enabled: boolean;
    admin: boolean;
    sudo: boolean;
}

export interface UserInfo {
    id: number;
    name: string;
    tfa: boolean;
    admin: boolean;
    enabled: boolean;
}

export interface Node {
    id: number;
    name: string;
    file: boolean;
    preview: boolean;
    parent: (number|null);
    size: (number|null);
    children: (Node[]|null);
}

export interface CreateNodeInfo {
    id: number;
    exists: boolean;
    file: boolean;
}

export interface ZipInfo {
    done: boolean;
    progress: number;
    total: number;
}

export interface PathSegment {
    name: string;
    id: (number|null);
}


export class MRPCConnector {
    url: string;

    private __create_msg(service: string, method: string, data: any) {
        return {service, method, data};
    }

    public constructor(url: string) {
        this.url = url;
    }

 
    public Auth_signup(username: string, password: string): Promise<(string|null)> {
        const __msg = this.__create_msg('Auth', 'signup', {username,password});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Auth_login(username: string, password: string, otp: (string|null)): Promise<Response<LoginResponse>> {
        const __msg = this.__create_msg('Auth', 'login', {username,password,otp});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Auth_send_recovery_key(username: string): Promise<void> {
        const __msg = this.__create_msg('Auth', 'send_recovery_key', {username});
        return fetch(this.url, {method: 'POST', body: JSON.stringify(__msg)}).then(__r => {});
    }

    public Auth_reset_password(key: string, password: string): Promise<(string|null)> {
        const __msg = this.__create_msg('Auth', 'reset_password', {key,password});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Auth_change_password(token: string, old_pw: string, new_pw: string): Promise<(string|null)> {
        const __msg = this.__create_msg('Auth', 'change_password', {token,old_pw,new_pw});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Auth_logout(token: string): Promise<void> {
        const __msg = this.__create_msg('Auth', 'logout', {token});
        return fetch(this.url, {method: 'POST', body: JSON.stringify(__msg)}).then(__r => {});
    }

    public Auth_logout_all(token: string): Promise<(string|null)> {
        const __msg = this.__create_msg('Auth', 'logout_all', {token});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Auth_tfa_setup_mail(token: string): Promise<(string|null)> {
        const __msg = this.__create_msg('Auth', 'tfa_setup_mail', {token});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Auth_tfa_setup_totp(token: string): Promise<Response<string>> {
        const __msg = this.__create_msg('Auth', 'tfa_setup_totp', {token});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Auth_tfa_complete(token: string, otp: string): Promise<(string|null)> {
        const __msg = this.__create_msg('Auth', 'tfa_complete', {token,otp});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Auth_tfa_disable(token: string): Promise<(string|null)> {
        const __msg = this.__create_msg('Auth', 'tfa_disable', {token});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Auth_delete_user(token: string): Promise<(string|null)> {
        const __msg = this.__create_msg('Auth', 'delete_user', {token});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Auth_session_info(token: string): Promise<Response<Session>> {
        const __msg = this.__create_msg('Auth', 'session_info', {token});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }
 
    public Admin_list_users(token: string): Promise<Response<UserInfo[]>> {
        const __msg = this.__create_msg('Admin', 'list_users', {token});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Admin_delete_user(token: string, user: number): Promise<(string|null)> {
        const __msg = this.__create_msg('Admin', 'delete_user', {token,user});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Admin_logout(token: string, user: number): Promise<(string|null)> {
        const __msg = this.__create_msg('Admin', 'logout', {token,user});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Admin_disable_tfa(token: string, user: number): Promise<(string|null)> {
        const __msg = this.__create_msg('Admin', 'disable_tfa', {token,user});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Admin_set_admin(token: string, user: number, admin: boolean): Promise<(string|null)> {
        const __msg = this.__create_msg('Admin', 'set_admin', {token,user,admin});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Admin_set_enabled(token: string, user: number, enabled: boolean): Promise<(string|null)> {
        const __msg = this.__create_msg('Admin', 'set_enabled', {token,user,enabled});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Admin_sudo(token: string, user: number): Promise<(string|null)> {
        const __msg = this.__create_msg('Admin', 'sudo', {token,user});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Admin_unsudo(token: string): Promise<(string|null)> {
        const __msg = this.__create_msg('Admin', 'unsudo', {token});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public Admin_shutdown(token: string): Promise<(string|null)> {
        const __msg = this.__create_msg('Admin', 'shutdown', {token});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }
 
    public FS_get_node(token: string, node: number): Promise<Response<Node>> {
        const __msg = this.__create_msg('FS', 'get_node', {token,node});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public FS_get_path(token: string, node: number): Promise<Response<PathSegment[]>> {
        const __msg = this.__create_msg('FS', 'get_path', {token,node});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public FS_get_nodes_size(token: string, nodes: number[]): Promise<Response<number>> {
        const __msg = this.__create_msg('FS', 'get_nodes_size', {token,nodes});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public FS_create_node(token: string, file: boolean, parent: number, name: string): Promise<Response<CreateNodeInfo>> {
        const __msg = this.__create_msg('FS', 'create_node', {token,file,parent,name});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public FS_move_nodes(token: string, nodes: number[], parent: number): Promise<(string|null)> {
        const __msg = this.__create_msg('FS', 'move_nodes', {token,nodes,parent});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public FS_delete_nodes(token: string, nodes: number[], __cbk: (v: string|null) => void) {
        const __msg = this.__create_msg('FS', 'delete_nodes', {token,nodes});
        fetchEventSource(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg),
            onmessage: __e => __cbk(JSON.parse(__e.data)),
            onerror: __e => {throw __e;},
            onclose: () => __cbk(null)
        });
    }

    public FS_download_preview(token: string, node: number): Promise<Response<string>> {
        const __msg = this.__create_msg('FS', 'download_preview', {token,node});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

    public FS_get_mime(token: string, node: number): Promise<Response<string>> {
        const __msg = this.__create_msg('FS', 'get_mime', {token,node});
        return fetch(this.url, {
            method: 'POST',
            body: JSON.stringify(__msg)
        }).then((__r) => __r.json());
    }

}
