import { DocumentType } from '../../../shared/enums.js';
import { hashStringToInt } from '../../../shared/helpers/index.js';
import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js';
import { AnthropicProvider } from '../../app-providers/anthropic.js';
import { CloudinaryProvider } from '../../app-providers/cloudinary.js';
const toBase64 = async (file) => {
    const base64string = Buffer.from(await file.arrayBuffer()).toString('base64');
    return 'data:' + file.type + ';base64,' + base64string;
};
export const uploadToCloudinary = async (injector, file) => {
    const base64string = await toBase64(file).catch(err => {
        throw new Error(`Failed to convert file to base64: ${err.message}`);
    });
    try {
        return injector.get(CloudinaryProvider).uploadInvoiceToCloudinary(base64string);
    }
    catch (e) {
        const message = 'Error on uploading file to cloudinary';
        console.error(`${message}: ${e}`);
        throw new Error(message, { cause: e });
    }
};
export async function getOcrData(injector, file, isSensitive = true) {
    const validateNumber = (value) => {
        return typeof value === 'number' && !Number.isNaN(value) ? value : undefined;
    };
    const validateDate = (value) => {
        if (!value)
            return undefined;
        const date = new Date(value);
        return Number.isNaN(date.getTime()) ? undefined : date;
    };
    if (isSensitive) {
        return {
            documentType: DocumentType.Unprocessed,
        };
    }
    const draft = await injector.get(AnthropicProvider).extractInvoiceDetails(file);
    if (!draft) {
        throw new Error('No data returned from Anthropic OCR');
    }
    let isOwnerIssuer = undefined;
    if (draft.recipient?.toLocaleLowerCase().includes('the guild')) {
        isOwnerIssuer = false;
    }
    if (draft.issuer?.toLocaleLowerCase().includes('the guild')) {
        isOwnerIssuer = true;
    }
    return {
        isOwnerIssuer,
        documentType: draft.type ?? DocumentType.Unprocessed,
        serial: draft.referenceCode ?? undefined,
        date: validateDate(draft.date ?? undefined),
        amount: validateNumber(draft.fullAmount),
        currency: draft.currency,
        vat: validateNumber(draft.vatAmount),
        allocationNumber: draft.allocationNumber ?? undefined,
        description: draft.description ?? undefined,
        remarks: draft.issuer,
    };
}
async function getHashFromFile(file) {
    return hashStringToInt(await file.text());
}
function figureOutSides(documentType, ownerId, isOwnerIssuer, counterPartyId) {
    if (documentType === DocumentType.Unprocessed || documentType === DocumentType.Other) {
        return {};
    }
    let res = {
        creditorId: counterPartyId,
        debtorId: ownerId,
    };
    if (isOwnerIssuer === true) {
        res = {
            creditorId: res.debtorId,
            debtorId: res.creditorId,
        };
    }
    if (documentType === DocumentType.CreditInvoice) {
        res = {
            creditorId: res.debtorId,
            debtorId: res.creditorId,
        };
    }
    return res;
}
export function getDocumentFromUrlsAndOcrData(fileUrl, imageUrl, ocrData, adminBusinessId, chargeId, fileHash) {
    const sides = figureOutSides(ocrData.documentType, adminBusinessId, ocrData.isOwnerIssuer, ocrData.counterpartyId);
    const newDocument = {
        ownerId: adminBusinessId,
        image: imageUrl ?? null,
        file: fileUrl ?? null,
        documentType: ocrData.documentType,
        serialNumber: ocrData.serial ?? null,
        date: ocrData.date ?? null,
        amount: ocrData.amount ?? null,
        currencyCode: ocrData.currency ?? null,
        vat: ocrData.vat ?? null,
        chargeId: chargeId ?? null,
        vatReportDateOverride: null,
        noVatAmount: null,
        allocationNumber: ocrData.allocationNumber ?? null,
        exchangeRateOverride: null,
        fileHash: fileHash?.toString() ?? null,
        description: ocrData.description ?? null,
        remarks: ocrData.remarks ?? null,
        creditorId: sides.creditorId ?? null,
        debtorId: sides.debtorId ?? null,
    };
    return newDocument;
}
export async function getDocumentFromFile(injector, file, chargeId, isSensitive, counterPartyId, hash) {
    try {
        const { ownerId } = await injector.get(AdminContextProvider).getVerifiedAdminContext();
        // Buffer the file to allow multiple reads from a stream
        const buffer = await file.arrayBuffer();
        const multiReadableFile = new Blob([buffer], { type: file.type });
        const [{ fileUrl, imageUrl }, ocrData, fileHash] = await Promise.all([
            uploadToCloudinary(injector, multiReadableFile),
            getOcrData(injector, multiReadableFile, isSensitive),
            hash ? Promise.resolve(hash) : getHashFromFile(multiReadableFile),
        ]);
        if (!ocrData) {
            throw new Error('No data returned from Green Invoice');
        }
        if (counterPartyId) {
            ocrData.counterpartyId = counterPartyId;
        }
        return getDocumentFromUrlsAndOcrData(fileUrl, imageUrl, ocrData, ownerId, chargeId, fileHash);
    }
    catch (e) {
        const message = 'Error extracting document data from file';
        console.error(`${message}: ${e}`);
        throw new Error(message, { cause: e });
    }
}
//# sourceMappingURL=upload.helper.js.map