import { postData, verifyLogin } from "./client.js";

verifyLogin();
const token = window.localStorage.getItem("token");

const infoForm = document.getElementById("infoForm");

const error = document.querySelector(".error");
const errorMessage = document.querySelector(".error p");
const success = document.querySelector(".success");
const successMessage = document.querySelector(".success p");

openKeyDB();
const encryptionKey = await getEncryptionKey()

//console.log(`Encryption Key:`);
//console.log(encryptionKey);

async function handlePasswordSubmission(e) {
    console.log(await verifyLogin());
    e.preventDefault();
    const formData = {
        name: document.getElementById("name").value,
        password: document.getElementById("password").value,
    }
    const set = document.getElementById("set").checked;

    console.log(set);

    if (set) {
        //console.log("formdata SET so SETTING");
        setPassword(formData.name, formData.password);
    } else {
        //console.log("formdata GET so GETTING");
        getPassword(formData.name);
    }
}

infoForm.onsubmit = handlePasswordSubmission;

async function setPassword(name, password) {
    const encoder = new TextEncoder();
    const encodedData = encoder.encode(password);

    const iv = window.crypto.getRandomValues(new Uint8Array(12));

    const cyphertextBuffer = await window.crypto.subtle.encrypt(
        {
            name: "AES-GCM",
            iv: iv
        },
        encryptionKey,
        encodedData
    );

    const data = {
        name: name,
        iv: bufferToBase64(iv),
        password: bufferToBase64(cyphertextBuffer)
    }

    var resultObject = await postData("/setPassword", data, token);

    if (resultObject.message.includes("UNIQUE")) {
        resultObject = await postData("/updatePassword", data, token);
    }

    if (resultObject.success) {
        error.style.display = "none";
        success.style.display = "flex";
        successMessage.innerHTML = `Password for "${name}" successfully set to "${password}"`
    } else {
        errorMessage.innerHTML = resultObject.message;
        success.style.display = "none";
        error.style.display = "flex";
    }
}

async function getPassword(name) {
    const data = {
        name: name
    }
    const resultObject = await postData("/getPassword", data, token);

    if (resultObject.success) {
        error.style.display = "none";
        success.style.display = "flex";
    } else {
        errorMessage.innerHTML = resultObject.message;
        success.style.display = "none";
        error.style.display = "flex";
        return;
    }

    const ivBuffer = base64ToBuffer(resultObject.iv);
    const cyphertextBuffer = base64ToBuffer(resultObject.password);

    const decryptedBuffer = await window.crypto.subtle.decrypt(
        {
            name: "AES-GCM",
            iv: ivBuffer
        },
        encryptionKey,
        cyphertextBuffer
    );
    
    const decoder = new TextDecoder();
    const pw = decoder.decode(decryptedBuffer);
    document.getElementById("password").value = pw;
    //console.log("Password: " + pw);

    //console.log(resultObject);

    successMessage.innerHTML = `Password for "${name}" is "${pw}"`
}




function openKeyDB() {
    return new Promise((resolve, reject) => {
        const request = indexedDB.open("PasswordManagerVault", 1);
        
        request.onupgradeneeded = (event) => {
            const db = event.target.result;
            if (!db.objectStoreNames.contains("cryptoKeys")) {
                db.createObjectStore("cryptoKeys");
            }
        };
        
        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(request.error);
    });
}

async function saveEncryptionKey(cryptoKeyObject) {
    const db = await openKeyDB();
    return new Promise((resolve, reject) => {
        const transaction = db.transaction(["cryptoKeys"], "readwrite");
        const store = transaction.objectStore("cryptoKeys");
        
        // We store the object under the label "masterEncryptionKey"
        const request = store.put(cryptoKeyObject, "masterEncryptionKey");
        
        request.onsuccess = () => resolve(true);
        request.onerror = () => reject(request.error);
    });
}

async function getEncryptionKey() {
    const db = await openKeyDB();
    return new Promise((resolve, reject) => {
        const transaction = db.transaction(["cryptoKeys"], "readonly");
        const store = transaction.objectStore("cryptoKeys");
        
        const request = store.get("masterEncryptionKey");
        
        request.onsuccess = () => {
            if (request.result) {
                resolve(request.result);
            } else {
                resolve(null);
            }
        };
        request.onerror = () => reject(request.error);
    });
}

function bufferToBase64(buffer) {
    const bytes = new Uint8Array(buffer);
    let binary = '';
    for (let i = 0; i < bytes.byteLength; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    return window.btoa(binary);
}

function base64ToBuffer(base64) {
    const binaryString = window.atob(base64);
    const bytes = new Uint8Array(binaryString.length);
    for (let i = 0; i < binaryString.length; i++) {
        bytes[i] = binaryString.charCodeAt(i);
    }
    return bytes;
}
