import { TestBed, waitForAsync } from '@angular/core/testing';
import {HttpClient, HttpHeaders, HttpClientModule} from '@angular/common/http';
import { CookieService } from 'ngx-cookie';
import { base64 } from "rfc4648";
import { CookieModule } from 'ngx-cookie';

import msgpack from "msgpack-lite";

import { AccountConfigLoadArgs, AccountConfigDumpArgs } from "../crypto/context/account/args";
import { AccountConfigV1 } from "../crypto/context/account/v1";
import { AccountRoomKeyConfigV1 } from "../crypto/context/account_key/room/v1";
import { SelfAccountKeyring } from "../crypto/keyring/account_self";
import { AbstractSelfAccountKeyring } from './keyring/account_base';
import { AbstractKeyring } from './keyring/base';
import { AbstractPrivateKeyring, PrivateKeyringV1 } from './keyring/private';
import { AbstractRoomKeyring } from './keyring/room_base';
import { AbstractPeerAccountKeyring } from './keyring/account_base';
import { AccountMasterDeriveKeyV1 } from './context/common';
import { RoomKeyring } from "./keyring/room";
import { AccountTrustConfigDumpArgs, AccountTrustConfigLoadArgs } from './context/account_trust/args';
import { AccountRoomKeyConfigDumpArgs, AccountRoomKeyConfigLoadArgs } from './context/account_key/room/args';
import { AccountRootKeyConfigDumpArgs, AccountRootKeyConfigLoadArgs } from './context/account_key/root/args';
import { AccountRootKeyConfigV1 } from './context/account_key/root/v1';
import { AccountSignatureConfigDumpArgs, AccountSignatureConfigLoadArgs } from './context/account_signature/args';
import { AccountSignatureConfigV1 } from './context/account_signature/v1';
import { AccountTrustConfigV1 } from './context/account_trust/v1';
import { DialogueConfigDumpArgs, DialogueConfigLoadArgs } from './context/dialogue/args';
import { DialogueConfigV1 } from './context/dialogue/v1';
import { TimestampWindowCalculator } from './context/timestamp';
import { NanoConfigDumpArgs, NanoConfigLoadArgs } from './context/nano/args';
import { NanoConfigV1 } from './context/nano/v1';
import { NanoDataConfigDumpArgs, NanoDataConfigLoadArgs } from './context/nano_data/args';
import { NanoDataConfigV1 } from './context/nano_data/v1';
import { NanoOwnConfigDumpArgs, NanoOwnConfigLoadArgs } from './context/nano_own/args';
import { NanoOwnConfigV1 } from './context/nano_own/v1';
import { PrivateKeyConfigDumpArgs, PrivateKeyConfigLoadArgs } from './context/private_key/args';
import { PrivateKeyConfigV1 } from './context/private_key/v1';
import { RoomConfigDumpArgs, RoomConfigLoadArgs } from './context/room/args';
import { RoomConfigV1 } from './context/room/v1';
import { RoomKeyConfigDumpArgs, RoomKeyConfigLoadArgs } from './context/room_key/args';
import { RoomKeyConfigV1 } from './context/room_key/v1';
import { environment } from "./../../../environments/environment";
import { AESCipherSIVNonce96 } from './base/cipher/aes';

// only for test keyrings ------------------------------------------------
let TYPE_MARKER_KEY = "AmIAKeyring?"
let TYPE_MARKER_VALUE = "Yes!"

function find_dump_raw_keyrings(a: any){
    if (Array.isArray(a)){
        for (let i = 0; i < a.length; i++){
            if (a[i] instanceof AbstractKeyring){
                a[i] = dump_raw_keyring(a[i]);
            }
            else{
                find_dump_raw_keyrings(a[i]);
            }
        }
    }
    else if(a.constructor == Object){
        for(let k in a){
            if (a[k] instanceof AbstractKeyring){
                a[k] = dump_raw_keyring(a[k]);
            }
            else{
                find_dump_raw_keyrings(a[k]);
            }
        }
    }
}

export function dump_raw_keyring(a: AbstractKeyring): Object{
    let kr;

    if (a instanceof AbstractPrivateKeyring){
        kr = {enc: a.enc_key, auth: a.auth_key};
    }
    else if(a instanceof AbstractRoomKeyring){
        kr = {id: new TextDecoder().decode(a.id), key: a.get_key(AbstractRoomKeyring.PINNED)}
    }
    else if(a instanceof AbstractPeerAccountKeyring){
        kr = {
            id: new TextDecoder().decode(a.id),
            pub: {},
            t: a.trusted,
            tofu: a.tofu_fingerprints
        }
        kr.pub[AbstractSelfAccountKeyring.CURVE25519] = a.get_public_key(AbstractSelfAccountKeyring.CURVE25519)
        kr.pub[AbstractSelfAccountKeyring.ED25519] = a.get_public_key(AbstractSelfAccountKeyring.ED25519)
    }
    else if (a instanceof AbstractSelfAccountKeyring){

        kr = {
            id: new TextDecoder().decode(a.id),
            pub: {},
            sec: {},
            t: a.trusted
        }


        kr.pub[AbstractSelfAccountKeyring.CURVE25519] = a.get_public_key(AbstractSelfAccountKeyring.CURVE25519);
        kr.pub[AbstractSelfAccountKeyring.ED25519] = a.get_public_key(AbstractSelfAccountKeyring.ED25519);

        kr.sec[AbstractSelfAccountKeyring.MASTER] = a.get_secret_key(AbstractSelfAccountKeyring.MASTER);
        kr.sec[AbstractSelfAccountKeyring.CURVE25519] = a.get_secret_key(AbstractSelfAccountKeyring.CURVE25519);
        kr.sec[AbstractSelfAccountKeyring.ED25519] = new Uint8Array(a.get_secret_key(AbstractSelfAccountKeyring.ED25519)) // remove the 64 byte part, use only the seed for test or storage

    }
    else{
        throw "invalid raw keyring input for dump";
    }

    kr[TYPE_MARKER_KEY] = TYPE_MARKER_VALUE;

    return kr;
}

/**
 *
 * THIS FILE IS TESTING THE BOTTOM/NATIVE LAYER OF OUR CRYPTO FUNCIONALITY
 * WE MADE A HANDY INTERFACE FOR THIS TO USE: global-crypto.ts
 *
 */

describe('Cryptography context test', () => {

    let cookie;
    let conf:any = {};

    let options = {
        headers: new HttpHeaders({"Content-type": "application/msgpack"}),
        responseType: 'arraybuffer' as 'arraybuffer'
    };


    let http: HttpClient;
    let apiUrl = environment.url_api+"/";

    let expectedList = {
        "account": [
            {
                "version": 1,
                "never_dump": false
            }
        ],
        "account_room_key": [
            {
                "version": 1,
                "never_dump": false
            }
        ],
        "account_root_key": [
            {
                "version": 1,
                "never_dump": false
            }
        ],
        "account_signature": [
            {
                "version": 1,
                "never_dump": false
            }
        ],
        "account_trust": [
            {
                "version": 1,
                "never_dump": false
            }
        ],
        "dialogue": [
            {
                "version": 1,
                "never_dump": false
            }
        ],
        "nano": [
            {
                "version": 1,
                "never_dump": false
            }
        ],
        "nano_data": [
            {
                "version": 1,
                "never_dump": false
            }
        ],
        "nano_own": [
            {
                "version": 1,
                "never_dump": false
            }
        ],
        "private_key": [
            {
                "version": 1,
                "never_dump": false
            }
        ],
        "room": [
            {
                "version": 1,
                "never_dump": false
            }
        ],
        "room_key": [
            {
                "version": 1,
                "never_dump": false
            }
        ]
    };

    let csrfToken = "";



    
    beforeAll(waitForAsync(()=>{
        TestBed.configureTestingModule({
            imports : [HttpClientModule, CookieModule.forRoot()],
            providers: [CookieService]
        });

        http = TestBed.inject(HttpClient);
        cookie = TestBed.inject(CookieService);



        http.get(apiUrl+'debug/crypto/context/configs', options).subscribe(
            (res)=>{
                conf = msgpack.decode(new Uint8Array(res))
                console.log(conf)
            }
        );

        // set the cookie
        http.get(apiUrl+'r/csrf', options).subscribe(
            (res)=>{
                csrfToken = cookie.get("__Secure-csrf");
                options = {
                    headers: new HttpHeaders({
                        "Content-type": "application/msgpack",
                        "pcsrf": csrfToken
                    }),
                    responseType: 'arraybuffer' as 'arraybuffer'
                };
            }
        );


    }));
    
    // check if we can get the conf list from server
    it('should get server conf', () => {
        console.log(conf)
        expect(conf).toBeTruthy();
    });
    
    // if this arr is changed, we should write more tests for the new elements
    it('check the conf values', (done) => {
        for (let key in expectedList) {

            expect(key in conf && conf[key].length == expectedList[key].length).toBeTrue();

            for(let i = 0; i < expectedList[key].length; i++){
                expect(conf[key][i].version == expectedList[key][i].version && conf[key][i].never_dump == expectedList[key][i].never_dump).toBeTrue();
            }

        }

        for (let key in conf) {

            expect(key in expectedList && conf[key].length == expectedList[key].length).toBeTrue();

            for(let i = 0; i < conf[key].length; i++){
                expect(conf[key][i].version == expectedList[key][i].version && conf[key][i].never_dump == expectedList[key][i].never_dump).toBeTrue();
            }

        }

        done();
    });
    
    it('master derive key', (done)=>{
        AccountMasterDeriveKeyV1.derive_key(
            new SelfAccountKeyring(
                "Asdf",
                [],
                {
                    3:new Uint8Array([103, 159, 7, 65, 91, 224, 211, 136, 200, 174, 216, 54, 34, 171, 217, 188, 10, 219, 162, 103, 132, 161, 150, 36, 138, 175, 27, 253, 80, 149, 212, 222])
                }
            ), new Uint8Array([120, 121])
            ).then((res)=>{

            expect(base64.stringify(res)==base64.stringify(new Uint8Array([199, 153, 224, 11, 134, 19, 93, 1, 253, 191, 83, 170, 105, 114, 44, 103, 158, 213, 186, 65, 154, 178, 26, 99, 245, 37, 224, 164, 105, 217, 2, 166, 97, 186, 221, 194, 212, 15, 129, 213, 58, 203, 22, 15, 171, 10, 141, 210, 137, 135, 184, 93, 218, 145, 217, 33, 245, 3, 71, 84, 218, 46, 169, 144]))).toBeTrue();
            done();
        })
    })

    
    // account
    it('check account - server dump -> server load', (done)=>{

        let cipher = window.crypto.getRandomValues(new Uint8Array(512));

        let self_kr = SelfAccountKeyring.generate('id');

        let param = msgpack.encode({
            name: "account",
            version: 1,
            args: [cipher, dump_raw_keyring(self_kr)]
        });


        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "account",
                version: 1,
                args: [expectedDump, dump_raw_keyring(self_kr)]
            });
            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(cipher) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });

        });


    })


    it('check account - client dump -> server load', (done)=>{

        let cipher = window.crypto.getRandomValues(new Uint8Array(512));

        let self_kr = SelfAccountKeyring.generate('id');

        let dumpArgs = new AccountConfigDumpArgs(cipher, self_kr);

        let crypto = new AccountConfigV1();


        crypto.dump(dumpArgs).then((dump)=>{

            let param = msgpack.encode({
                name: "account",
                version: 1,
                args: [dump, dump_raw_keyring(self_kr)]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(cipher) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });

        });



    })

    it('check account - server dump -> client load', (done)=>{

        let cipher = window.crypto.getRandomValues(new Uint8Array(512));

        let self_kr = SelfAccountKeyring.generate('id');

        let param = msgpack.encode({
            name: "account",
            version: 1,
            args: [cipher, dump_raw_keyring(self_kr)]
        });

        let crypto = new AccountConfigV1();



        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let loadArgs = new AccountConfigLoadArgs(expectedDump, self_kr);

            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(cipher) == base64.stringify(load)).toBeTrue();
                done();
            })

        });



    })

    it('check account - client dump -> client load', (done)=>{

        let cipher = window.crypto.getRandomValues(new Uint8Array(512));

        let self_kr = SelfAccountKeyring.generate('id');

        let dumpArgs = new AccountConfigDumpArgs(cipher, self_kr);

        let crypto = new AccountConfigV1();


        crypto.dump(dumpArgs).then((dump)=>{

            let loadArgs = new AccountConfigLoadArgs(dump, self_kr);

            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(cipher) == base64.stringify(load)).toBeTrue();
                done();
            })

        });


    })








    // account_room_key
    it('check account_room_key - [deterministic]', (done)=>{


        let self_kr = SelfAccountKeyring.generate('id');
        let room_kr = RoomKeyring.generate('id');

        let param = msgpack.encode({
            name: "account_room_key",
            version: 1,
            args: [dump_raw_keyring(self_kr), "1", dump_raw_keyring(room_kr)]
        });



        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "account_room_key",
                version: 1,
                args: [expectedDump, dump_raw_keyring(self_kr), "1", dump_raw_keyring(room_kr)]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                let dumpArgs = new AccountRoomKeyConfigDumpArgs(self_kr, "1", room_kr);
                let loadArgs = new AccountRoomKeyConfigLoadArgs(expectedDump, self_kr, "1", room_kr);

                let crypto = new AccountRoomKeyConfigV1();

                crypto.dump(dumpArgs).then((dump)=>{

                    expect(base64.stringify(dump) == base64.stringify(expectedDump)).toBeTruthy();

                    crypto.load(loadArgs).then((load)=>{

                        expect(base64.stringify(load) == base64.stringify(expectedLoad)).toBeTruthy();

                        done();
                    })
                })

            });

        });



    })












    // account_room_key
    it('check account_root_key - [deterministic]', (done)=>{


        let self_kr = SelfAccountKeyring.generate('id');

        let param = msgpack.encode({
            name: "account_root_key",
            version: 1,
            args: [dump_raw_keyring(self_kr), "1"]
        });



        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "account_root_key",
                version: 1,
                args: [expectedDump, dump_raw_keyring(self_kr), "1"]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                let dumpArgs = new AccountRootKeyConfigDumpArgs(self_kr, "1");
                let loadArgs = new AccountRootKeyConfigLoadArgs(expectedDump, self_kr, "1");

                let crypto = new AccountRootKeyConfigV1();

                crypto.dump(dumpArgs).then((dump)=>{

                    expect(base64.stringify(dump) == base64.stringify(expectedDump)).toBeTruthy();

                    crypto.load(loadArgs).then((load)=>{
                        expect(base64.stringify(load) == base64.stringify(expectedLoad)).toBeTruthy();

                        done();
                    })
                })

            });

        });



    })



















    // account
    it('account_signature - server dump -> server load', (done)=>{

        let cipher = window.crypto.getRandomValues(new Uint8Array(32));

        let self_kr = SelfAccountKeyring.generate("id");



        let param = msgpack.encode({
            name: "account_signature",
            version: 1,
            args: [cipher, dump_raw_keyring(self_kr)]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "account_signature",
                version: 1,
                args: [expectedDump, dump_raw_keyring(self_kr), cipher]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(cipher) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });

        });



    })


    it('account_signature - client dump -> server load', (done)=>{

        let cipher = window.crypto.getRandomValues(new Uint8Array(32));

        let self_kr = SelfAccountKeyring.generate("id");

        let dumpArgs = new AccountSignatureConfigDumpArgs(cipher, self_kr);

        let crypto = new AccountSignatureConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{

            let param = msgpack.encode({
                name: "account_signature",
                version: 1,
                args: [dump, dump_raw_keyring(self_kr), cipher]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(cipher) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });

        })



    })




    it('account_signature - server dump -> client load', (done)=>{

        let cipher = window.crypto.getRandomValues(new Uint8Array(32));

        let self_kr = SelfAccountKeyring.generate("id");



        let param = msgpack.encode({
            name: "account_signature",
            version: 1,
            args: [cipher, dump_raw_keyring(self_kr)]
        });

        let crypto = new AccountSignatureConfigV1();


        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let loadArgs = new AccountSignatureConfigLoadArgs(expectedDump, self_kr, cipher);

            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(cipher) == base64.stringify(load)).toBeTrue();
                done();
            })
        });



    })


    it('account_signature - client dump -> client load', (done)=>{

        let cipher = window.crypto.getRandomValues(new Uint8Array(32));

        let self_kr = SelfAccountKeyring.generate("id");

        let dumpArgs = new AccountSignatureConfigDumpArgs(cipher, self_kr);

        let crypto = new AccountSignatureConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{

            let loadArgs = new AccountSignatureConfigLoadArgs(dump, self_kr, cipher);

            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(cipher) == base64.stringify(load)).toBeTrue();
                done();
            })

        })



    })


















    it('account_trust [deterministic]', (done)=>{

        let cipher = window.crypto.getRandomValues(new Uint8Array(32));

        let self_kr = SelfAccountKeyring.generate("id");
        let peer_kr = SelfAccountKeyring.generate("peer");



        let param = msgpack.encode({
            name: "account_trust",
            version: 1,
            args: [dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), AbstractSelfAccountKeyring.ED25519]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "account_trust",
                version: 1,
                args: [expectedDump, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr)]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                let dumpArgs = new AccountTrustConfigDumpArgs(self_kr, peer_kr, AbstractSelfAccountKeyring.ED25519);

                let crypto = new AccountTrustConfigV1();

                crypto.dump(dumpArgs).then((dump)=>{

                    expect(base64.stringify(dump) == base64.stringify(expectedDump)).toBeTruthy();


                    let loadArgs = new AccountTrustConfigLoadArgs(dump, self_kr, peer_kr);

                    crypto.load(loadArgs).then((load)=>{
                        expect(base64.stringify(load) == base64.stringify(expectedLoad)).toBeTruthy();

                        done();
                    })
                })


            });

        });



    })


    it('timestamp', (done)=>{

        try{
            new TimestampWindowCalculator(10, 8)
            expect(false).toBeTrue();
        }
        catch(e){
            expect(true).toBeTrue();
        }

        let twc = new TimestampWindowCalculator(10, 2)

        let enc = new TextEncoder();

        [
            [1618658928, enc.encode("1618658920"), [enc.encode("1618658920")]],
            [1618658929, enc.encode("1618658920"), [enc.encode("1618658920"), enc.encode("1618658930")]],
            [1618658930, enc.encode("1618658930"), [enc.encode("1618658930"), enc.encode("1618658920")]],
            [1618658931, enc.encode("1618658930"), [enc.encode("1618658930"), enc.encode("1618658920")]],
            [1618658932, enc.encode("1618658930"), [enc.encode("1618658930")]],
            [1618658933, enc.encode("1618658930"), [enc.encode("1618658930")]],
            [1618658934, enc.encode("1618658930"), [enc.encode("1618658930")]],
            [1618658935, enc.encode("1618658930"), [enc.encode("1618658930")]],
            [1618658936, enc.encode("1618658930"), [enc.encode("1618658930")]],
            [1618658937, enc.encode("1618658930"), [enc.encode("1618658930")]],
            [1618658938, enc.encode("1618658930"), [enc.encode("1618658930")]],
            [1618658939, enc.encode("1618658930"), [enc.encode("1618658930"), enc.encode("1618658940")]],
            [1618658940, enc.encode("1618658940"), [enc.encode("1618658940"), enc.encode("1618658930")]],
            [1618658941, enc.encode("1618658940"), [enc.encode("1618658940"), enc.encode("1618658930")]],
            [1618658942, enc.encode("1618658940"), [enc.encode("1618658940")]],
            [1618658943, enc.encode("1618658940"), [enc.encode("1618658940")]],
            [1618658944, enc.encode("1618658940"), [enc.encode("1618658940")]],
            [1618658945, enc.encode("1618658940"), [enc.encode("1618658940")]],
            [1618658946, enc.encode("1618658940"), [enc.encode("1618658940")]],
            [1618658947, enc.encode("1618658940"), [enc.encode("1618658940")]],
            [1618658948, enc.encode("1618658940"), [enc.encode("1618658940")]],
            [1618658949, enc.encode("1618658940"), [enc.encode("1618658940"), enc.encode("1618658950")]],
            [1618658950, enc.encode("1618658950"), [enc.encode("1618658950"), enc.encode("1618658940")]],
            [1618658951, enc.encode("1618658950"), [enc.encode("1618658950"), enc.encode("1618658940")]],
            [1618658952, enc.encode("1618658950"), [enc.encode("1618658950")]],
        ].forEach((el)=>{

            expect(base64.stringify(twc.window(<number>el[0])) == base64.stringify(<Uint8Array>el[1])).toBeTrue();

            let arr = twc.windows(<number>el[0])

            expect(arr.length == (<Uint8Array[]>el[2]).length).toBeTrue();

            for(let i = 0; i < arr.length; i++){
                expect(base64.stringify(arr[i]) == base64.stringify(<Uint8Array>el[2][i])).toBeTrue();
            }

        })

        expect(true).toBeTrue();
        done();
    })




    it('dialog - server dump -> server load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let peer_kr = SelfAccountKeyring.generate("peer");
        let timestamp = 1000;



        let param = msgpack.encode({
            name: "dialogue",
            version: 1,
            args: [plain, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), timestamp]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "dialogue",
                version: 1,
                args: [expectedDump, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), timestamp]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(plain) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });

        });



    })



    it('dialog - client dump -> server load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let peer_kr = SelfAccountKeyring.generate("peer");
        let timestamp = 1000;



        let dumpArgs = new DialogueConfigDumpArgs(plain, self_kr, <any>peer_kr, timestamp);

        let crypto = new DialogueConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{
            let param = msgpack.encode({
                name: "dialogue",
                version: 1,
                args: [dump, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), timestamp]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(plain) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });
        })



    })







    it('dialog - server dump -> client load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let peer_kr = SelfAccountKeyring.generate("peer");
        let timestamp = 1000;



        let param = msgpack.encode({
            name: "dialogue",
            version: 1,
            args: [plain, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), timestamp]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let loadArgs = new DialogueConfigLoadArgs(expectedDump, self_kr, <any>peer_kr, timestamp);

            let crypto = new DialogueConfigV1();

            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(plain) == base64.stringify(load)).toBeTrue();
                done();
            })

        });



    })

    it('dialog - client dump -> client load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let peer_kr = SelfAccountKeyring.generate("peer");
        let timestamp = 1000;

        let dumpArgs = new DialogueConfigDumpArgs(plain, self_kr, <any>peer_kr, timestamp);

        let crypto = new DialogueConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{

            let loadArgs = new DialogueConfigLoadArgs(dump, self_kr, <any>peer_kr, timestamp);


            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(plain) == base64.stringify(load)).toBeTrue();
                done();
            })
        })



    })











    it('dialog - server dump -> server load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let peer_kr = SelfAccountKeyring.generate("peer");
        let timestamp = 1000;



        let param = msgpack.encode({
            name: "dialogue",
            version: 1,
            args: [plain, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), timestamp]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "dialogue",
                version: 1,
                args: [expectedDump, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), timestamp]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(plain) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });

        });



    })







    it('nano - server dump -> server load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let peer_kr = SelfAccountKeyring.generate("peer");
        let room_kr = RoomKeyring.generate("room");
        let timestamp = 1000;



        let param = msgpack.encode({
            name: "nano",
            version: 1,
            args: [plain, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr),  dump_raw_keyring(room_kr), timestamp]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "nano",
                version: 1,
                args: [expectedDump, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), dump_raw_keyring(room_kr), timestamp]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(plain) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });

        });



    })



    it('nano - client dump -> server load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let peer_kr = SelfAccountKeyring.generate("peer");
        let room_kr = RoomKeyring.generate("room");
        let timestamp = 1000;


        let dumpArgs = new NanoConfigDumpArgs(plain, self_kr, <any>peer_kr, room_kr, timestamp);

        let crypto = new NanoConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{
            let param = msgpack.encode({
                name: "nano",
                version: 1,
                args: [dump, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), dump_raw_keyring(room_kr), timestamp]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(plain) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });
        })



    })




    it('nano - server dump -> client load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let peer_kr = SelfAccountKeyring.generate("peer");
        let room_kr = RoomKeyring.generate("room");
        let timestamp = 1000;



        let param = msgpack.encode({
            name: "nano",
            version: 1,
            args: [plain, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), dump_raw_keyring(room_kr), timestamp]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let loadArgs = new NanoConfigLoadArgs(expectedDump, self_kr, <any>peer_kr, room_kr, timestamp);

            let crypto = new NanoConfigV1();

            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(plain) == base64.stringify(load)).toBeTrue();
                done();
            })

        });



    })

    it('nano - client dump -> client load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let peer_kr = SelfAccountKeyring.generate("peer");
        let room_kr = RoomKeyring.generate("room");
        let timestamp = 1000;

        let dumpArgs = new NanoConfigDumpArgs(plain, self_kr, <any>peer_kr, room_kr, timestamp);

        let crypto = new NanoConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{

            let loadArgs = new NanoConfigLoadArgs(dump, self_kr, <any>peer_kr, room_kr, timestamp);


            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(plain) == base64.stringify(load)).toBeTrue();
                done();
            })
        })



    })



















    it('nano_data - server dump -> server load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let key = window.crypto.getRandomValues(new Uint8Array(32));


        let param = msgpack.encode({
            name: "nano_data",
            version: 1,
            args: [plain, key]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "nano_data",
                version: 1,
                args: [expectedDump, key]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(plain) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });

        });



    })



    it('nano_data - client dump -> server load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let key = window.crypto.getRandomValues(new Uint8Array(32));

        let dumpArgs = new NanoDataConfigDumpArgs(plain, key);

        let crypto = new NanoDataConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{
            let param = msgpack.encode({
                name: "nano_data",
                version: 1,
                args: [dump, key]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(plain) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });
        })



    })




    it('nano_data - server dump -> client load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let key = window.crypto.getRandomValues(new Uint8Array(32));



        let param = msgpack.encode({
            name: "nano_data",
            version: 1,
            args: [plain, key]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let loadArgs = new NanoDataConfigLoadArgs(expectedDump, key);

            let crypto = new NanoDataConfigV1();

            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(plain) == base64.stringify(load)).toBeTrue();
                done();
            })

        });



    })

    it('nano_data - client dump -> client load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let key = window.crypto.getRandomValues(new Uint8Array(32));


        let dumpArgs = new NanoDataConfigDumpArgs(plain, key);

        let crypto = new NanoDataConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{

            let loadArgs = new NanoDataConfigLoadArgs(dump, key);


            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(plain) == base64.stringify(load)).toBeTrue();
                done();
            })
        })



    })








    it('nano_own - server dump -> server load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let timestamp = 1000;


        let param = msgpack.encode({
            name: "nano_own",
            version: 1,
            args: [plain, dump_raw_keyring(self_kr), timestamp]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "nano_own",
                version: 1,
                args: [expectedDump, dump_raw_keyring(self_kr), timestamp]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(plain) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });

        });



    })



    it('nano_own - client dump -> server load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let timestamp = 1000;


        let dumpArgs = new NanoOwnConfigDumpArgs(plain, self_kr, timestamp);

        let crypto = new NanoOwnConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{
            let param = msgpack.encode({
                name: "nano_own",
                version: 1,
                args: [dump, dump_raw_keyring(self_kr), timestamp]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(plain) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });
        })


    })


    it('nano_own - server dump -> client load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let timestamp = 1000;


        let param = msgpack.encode({
            name: "nano_own",
            version: 1,
            args: [plain, dump_raw_keyring(self_kr), timestamp]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let loadArgs = new NanoOwnConfigLoadArgs(expectedDump, self_kr, timestamp);

            let crypto = new NanoOwnConfigV1();

            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(plain) == base64.stringify(load)).toBeTrue();
                done();
            })

        });


    })


    it('nano_own - client dump -> client load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let self_kr = SelfAccountKeyring.generate("id");
        let timestamp = 1000;


        let dumpArgs = new NanoOwnConfigDumpArgs(plain, self_kr, timestamp);

        let crypto = new NanoOwnConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{
            let loadArgs = new NanoOwnConfigLoadArgs(dump, self_kr, timestamp);

            let crypto = new NanoOwnConfigV1();

            crypto.load(loadArgs).then((load)=>{
                expect(base64.stringify(plain) == base64.stringify(load)).toBeTrue();
                done();
            })
        })


    })








    it('private_key - [deterministic]', (done)=>{


        let self_kr = SelfAccountKeyring.generate("id");
        PrivateKeyringV1.load(new TextEncoder().encode("password"), window.crypto.getRandomValues(new Uint8Array(32))).then((private_kr)=>{


            let key_version = "1";


            let param = msgpack.encode({
                name: "private_key",
                version: 1,
                args: [dump_raw_keyring(self_kr), dump_raw_keyring(private_kr), key_version]
            });



            http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedDump = msgpack.decode(new Uint8Array(res)).data;

                let param = msgpack.encode({
                    name: "private_key",
                    version: 1,
                    args: [expectedDump, dump_raw_keyring(private_kr), key_version]
                });

                http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                    let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;


                    let dumpArgs = new PrivateKeyConfigDumpArgs(self_kr, private_kr, key_version);
                    let loadArgs = new PrivateKeyConfigLoadArgs(expectedDump, private_kr, key_version);

                    let crypto = new PrivateKeyConfigV1();

                    crypto.dump(dumpArgs).then((dump)=>{

                        expect(base64.stringify(dump) == base64.stringify(expectedDump)).toBeTruthy();

                        crypto.load(loadArgs).then((load)=>{

                            expect(base64.stringify(load) == base64.stringify(expectedLoad)).toBeTruthy();

                            done();
                        })
                    })

                });

            });

        });



    })









    it('room - server dump -> server load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let room_kr = RoomKeyring.generate("room");
        let timestamp = 1000;


        let param = msgpack.encode({
            name: "room",
            version: 1,
            args: [plain, dump_raw_keyring(room_kr), timestamp]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "room",
                version: 1,
                args: [expectedDump, dump_raw_keyring(room_kr), timestamp]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(plain) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });

        });

    })




    it('room - client dump -> server load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let room_kr = RoomKeyring.generate("room");
        let timestamp = 1000;


        let dumpArgs = new RoomConfigDumpArgs(plain, room_kr, timestamp);

        let crypto = new RoomConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{
            let param = msgpack.encode({
                name: "room",
                version: 1,
                args: [dump, dump_raw_keyring(room_kr), timestamp]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;

                expect(base64.stringify(plain) == base64.stringify(expectedLoad)).toBeTrue();
                done();

            });

        });

    })


    it('room - server dump -> client load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let room_kr = RoomKeyring.generate("room");
        let timestamp = 1000;


        let param = msgpack.encode({
            name: "room",
            version: 1,
            args: [plain, dump_raw_keyring(room_kr), timestamp]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let loadArgs = new RoomConfigLoadArgs(expectedDump, room_kr, timestamp);

            let crypto = new RoomConfigV1();

            crypto.load(loadArgs).then((load)=>{

                expect(base64.stringify(plain) == base64.stringify(load)).toBeTrue();
                done();

            });

        });

    })



    it('room - client dump -> client load', (done)=>{


        let plain = window.crypto.getRandomValues(new Uint8Array(512));
        let room_kr = RoomKeyring.generate("room");
        let timestamp = 1000;


        let dumpArgs = new RoomConfigDumpArgs(plain, room_kr, timestamp);

        let crypto = new RoomConfigV1();

        crypto.dump(dumpArgs).then((dump)=>{

            let loadArgs = new RoomConfigLoadArgs(dump, room_kr, timestamp);

            let crypto = new RoomConfigV1();

            crypto.load(loadArgs).then((load)=>{

                expect(base64.stringify(plain) == base64.stringify(load)).toBeTrue();
                done();

            });

        });

    })






    it('room_key - [deterministic]', (done)=>{



        let self_kr = SelfAccountKeyring.generate("id");
        let peer_kr = SelfAccountKeyring.generate("peer");
        let room_kr = RoomKeyring.generate("room");
        let key_version = "1";


        let param = msgpack.encode({
            name: "room_key",
            version: 1,
            args: [dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), dump_raw_keyring(room_kr), key_version]
        });




        http.post(apiUrl+'debug/crypto/context/dump', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
            let expectedDump = msgpack.decode(new Uint8Array(res)).data;

            let param = msgpack.encode({
                name: "room_key",
                version: 1,
                args: [expectedDump, dump_raw_keyring(self_kr), dump_raw_keyring(peer_kr), dump_raw_keyring(room_kr), key_version]
            });

            http.post(apiUrl+'debug/crypto/context/load', new Uint8Array(param).buffer, options).toPromise().then((res)=>{
                let expectedLoad = msgpack.decode(new Uint8Array(res)).plain;


                let dumpArgs = new RoomKeyConfigDumpArgs(self_kr, peer_kr, room_kr, key_version);
                let loadArgs = new RoomKeyConfigLoadArgs(expectedDump, self_kr, peer_kr, room_kr, key_version);

                let crypto = new RoomKeyConfigV1();

                crypto.dump(dumpArgs).then((dump)=>{

                    expect(base64.stringify(dump) == base64.stringify(expectedDump)).toBeTruthy();
                    done();
                    crypto.load(loadArgs).then((load)=>{

                        expect(base64.stringify(load) == base64.stringify(expectedLoad)).toBeTruthy();

                        done();
                    })
                })

            });

        });

    })

    it('local storage dump - load', (done)=>{

        let self_kr = SelfAccountKeyring.generate("accId");

        let key = window.crypto.getRandomValues(new Uint8Array(64));

        self_kr.dump_local_storage(key).then((skr)=>{
            SelfAccountKeyring.load_local_storage(skr, key).then((self_kr3)=>{

                expect(base64.stringify(self_kr.id) == base64.stringify(self_kr3.id)).toBeTrue();
                expect(base64.stringify(self_kr._public_keys[SelfAccountKeyring.CURVE25519]) == base64.stringify(self_kr3._public_keys[SelfAccountKeyring.CURVE25519])).toBeTrue();
                expect(base64.stringify(self_kr._public_keys[SelfAccountKeyring.ED25519]) == base64.stringify(self_kr3._public_keys[SelfAccountKeyring.ED25519])).toBeTrue();
                expect(base64.stringify(self_kr._secret_keys[SelfAccountKeyring.CURVE25519]) == base64.stringify(self_kr3._secret_keys[SelfAccountKeyring.CURVE25519])).toBeTrue();
                expect(base64.stringify(self_kr._secret_keys[SelfAccountKeyring.ED25519]) == base64.stringify(self_kr3._secret_keys[SelfAccountKeyring.ED25519])).toBeTrue();
                expect(base64.stringify(self_kr._secret_keys[SelfAccountKeyring.MASTER]) == base64.stringify(self_kr3._secret_keys[SelfAccountKeyring.MASTER])).toBeTrue();
                done();
            })
        })

    })




});
