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

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

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

openKeyDB();

if (loginForm) loginForm.onsubmit = async e => {
    e.preventDefault();

    let saltObject = await postData("/getSalt", {
        username: document.getElementById("logUser").value
    });

    if (saltObject.message == "User not found") {
        errorMessage.innerHTML = saltObject.message;
        error.style.display = "flex";
        return;
    }

    const { authenticationKeyString, encryptionKeyObject } = await generateKeys(document.getElementById("logPass").value, hexToUint8Array(saltObject.salt));

    saveEncryptionKey(encryptionKeyObject);

    let resultObject = await postData("/login", {
        username: document.getElementById("logUser").value,
        password: authenticationKeyString
    });
    if (resultObject.message.includes("success")) {
        error.style.display = "none";
        success.style.display = "flex";
    } else {
        errorMessage.innerHTML = resultObject.message;
        error.style.display = "flex";
    }
    if (resultObject.success) {
        window.location.href = "/home"
        localStorage.setItem("token", resultObject.token);
    }
};

async function generateKeys(password, salt) {
    const encoder = new TextEncoder();

    const base = await window.crypto.subtle.importKey(
        "raw",
        encoder.encode(password),
        "PBKDF2",
        false,
        ["deriveBits", "deriveKey"]
    );

    const authSalt = new Uint8Array([...salt, ...encoder.encode("auth")]);
    const authKeyBits = await window.crypto.subtle.deriveBits(
        {
            name: "PBKDF2",
            salt: authSalt,
            iterations: 100000,
            hash: "SHA-256"
        },
        base,
        256
    );

    const encryptionSalt = new Uint8Array([...salt, ...encoder.encode("enc")]);
    const encryptionKey = await window.crypto.subtle.deriveKey(
        {
            name: "PBKDF2",
            salt: encryptionSalt,
            iterations: 100000,
            hash: "SHA-256"
        },
        base,
        { name: "AES-GCM", length: 256 },
        false,
        ["encrypt", "decrypt"]
    );

    console.log(convertBufferToHex(authKeyBits));
    console.log(encryptionKey);

    return {
        authenticationKeyString: convertBufferToHex(authKeyBits),
        encryptionKeyObject: encryptionKey
    };
}

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);
    });
}

function convertBufferToHex(buffer) {
    const bytes = new Uint8Array(buffer);

    return Array.from(bytes)
        .map(byte => byte.toString(16).padStart(2, "0"))
        .join("");
}

function hexToUint8Array(hexString) {
    if (hexString.length % 2 !== 0) {
        throw new Error("Invalid hex string");
    }
  
    const array = new Uint8Array(hexString.length / 2);
  
    for (let i = 0; i < hexString.length; i += 2) {
        array[i / 2] = parseInt(hexString.substring(i, i + 2), 16);
    }
  
    return array;
}

