/*
 * Copyright (c) 2022.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */

import {AuthContact} from "@chamesu/common/domains/auth/contact";
import localforage from "localforage";
import {getters, mutations} from "~/modules/security/store";
import {
    createSymmetricEncryptionKey,
    decryptMessageSymmetric,
    encryptMessageSymmetric
} from "~/modules/security/encryption/utils";
import {addContactData} from "~/domains/contact-data/api";
import {encodeContactMessage} from "~/domains/contact/encryption";
import {getRoomMemberContacts} from "~/domains/chat-room/api";
import {ContactDataSecretType} from "~/domains/contact-data/utils";


export function encodeChatRoomMessage(message: string, roomId: string) {
    const symmetricKey : string | undefined = getters.roomKey(roomId);

    if(typeof symmetricKey === 'undefined') {
        throw new Error('Die benötigte symmetrische Schlüssel existiert nicht...');
    }

    return encryptMessageSymmetric(message, symmetricKey);
}

export function decodeChatRoomMessage(message: string, roomId: string) {
    const symmetricKey : string | undefined = getters.roomKey(roomId);

    if(typeof symmetricKey === 'undefined') {
        throw new Error('Die benötigte symmetrische Schlüssel existiert nicht...');
    }

    return decryptMessageSymmetric(message, symmetricKey);
}

//

export async function createAndSaveChatRoomKey(roomId: string) {
    const key = createSymmetricEncryptionKey();

    await saveChatRoomKey(roomId, key);

    return key;
}

export async function saveChatRoomKey(roomId: string, key: string) {
    await (await useChatRoomKeyStorage()).setItem(roomId, key);

    mutations.setChatRoomKey(roomId, key);
}

export async function dropChatRoomKey(roomId: string) {
    await (await useChatRoomKeyStorage()).removeItem(roomId);
}

export async function getChatRoomKey(roomId: string) : Promise<string|undefined> {
    const key = await (await useChatRoomKeyStorage())
        .getItem<string>(roomId);

    if(!key) {
        return undefined;
    }

    return key;
}

//-------------------------------------------------------------------

/**
 * Share chat room key with specific contact
 *
 * @param contactId
 * @param roomId
 * @param key
 */
export async function shareChatRoomKey(contactId: string, roomId: string, key?: string) {
    key = typeof key === 'undefined' ? await getChatRoomKey(roomId) : key;

    const data = {
        roomId,
        key: key
    };

    try {
        const content = encodeContactMessage(JSON.stringify(data), contactId);
        await addContactData({
            type: ContactDataSecretType.ROOM,
            content: content,
            encrypted: true,
            contactId: contactId
        });
    } catch (e) {
        await addContactData({
            type: ContactDataSecretType.ROOM,
            content: data,
            encrypted: false,
            contactId: contactId
        });
    }
}

/**
 * Share a chat secret key request with a specific contact.
 *
 * @param contactId
 * @param roomId
 */
export async function shareChatRoomKeyRequest(contactId: string, roomId: string) {
    await addContactData({
        type: ContactDataSecretType.ROOM_REQUEST,
        content: {
            roomId
        },
        encrypted: false,
        contactId: contactId
    });
}

//-------------------------------------------------------------------


export async function createAndShareRoomKeyToContacts(roomId: string) {
    const response = await getRoomMemberContacts(roomId);
    const key = await createAndSaveChatRoomKey(roomId);

    for(let i=0; i<response.data.length; i++) {
        await shareChatRoomKey(response.data[i].id, roomId, key);
    }
}

export async function searchAndShareChatRoomKeyRequest(roomId: string) {
    const response = await getRoomMemberContacts(roomId, {
        page: {
            limit: 1
        }
    });

    if(response.data.length !== 1) {
        return;
    }

    const contact : AuthContact = response.data.pop() as AuthContact;

    await shareChatRoomKeyRequest(contact.id, roomId);
}

let chatRoomKeyStorage : undefined | LocalForage;

export async function useChatRoomKeyStorage() : Promise<LocalForage> {
    if(typeof chatRoomKeyStorage !== 'undefined') {
        return chatRoomKeyStorage;
    }

    chatRoomKeyStorage = localforage.createInstance({
        driver: localforage.INDEXEDDB,
        name: 'app',
        storeName: 'chatRoomKeys'
    });

    initChatRoomKeys(chatRoomKeyStorage)
        .then(r => r);

    return chatRoomKeyStorage;
}

async function initChatRoomKeys(storage: LocalForage) {
    const keys : string[] = await storage.keys();
    for(let i=0; i<keys.length; i++) {
        const key : string = keys[i];
        const secret = <string> await storage.getItem(key);

        mutations.setChatRoomKey(key, secret);
    }
}
