import { BlobRow } from "@triliumnext/commons";
import becca from "../becca/becca.js";
import { NotFoundError } from "../errors";
import protectedSessionService from "./protected_session.js";
import { decodeUtf8 } from "./utils/binary.js";
import { hash } from "./utils/index.js";

function getBlobPojo(entityName: string, entityId: string, opts?: { preview: boolean }) {
    // TODO: Unused opts.
    const entity = becca.getEntity(entityName, entityId);
    if (!entity) {
        throw new NotFoundError(`Entity ${entityName} '${entityId}' was not found.`);
    }

    const blob = becca.getBlob(entity);
    if (!blob) {
        throw new NotFoundError(`Blob ${entity.blobId} for ${entityName} '${entityId}' was not found.`);
    }

    const pojo = blob.getPojo();

    if (!entity.hasStringContent()) {
        pojo.content = null;
    } else {
        pojo.content = processContent(pojo.content, !!entity.isProtected, true) as string | Uint8Array;
    }

    return pojo;
}

function processContent(content: Uint8Array | string | null, isProtected: boolean, isStringContent: boolean) {
    if (isProtected) {
        if (protectedSessionService.isProtectedSessionAvailable()) {
            content = content === null ? null : protectedSessionService.decrypt(content as Uint8Array);
        } else {
            content = "";
        }
    }

    if (isStringContent) {
        if (content === null) return "";
        return decodeUtf8(content);
    }
    // see https://github.com/zadam/trilium/issues/3523
    // IIRC a zero-sized buffer can be returned as null from the database
    if (content === null) {
        // this will force de/encryption
        content = new Uint8Array(0);
    }

    return content;
}

function calculateContentHash({ blobId, content, textRepresentation }: Pick<BlobRow, "blobId" | "content" | "textRepresentation">) {
    return hash(`${blobId}|${content.toString()}|${textRepresentation ?? ""}`);
}

export default {
    getBlobPojo,
    processContent,
    calculateContentHash
};
