"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFilenameFromMimeType = getFilenameFromMimeType;
exports.downloadFile = downloadFile;
exports.uploadFile = uploadFile;
exports.transferFile = transferFile;
exports.createFileSearchStore = createFileSearchStore;
exports.uploadToFileSearchStore = uploadToFileSearchStore;
exports.listFileSearchStores = listFileSearchStores;
exports.deleteFileSearchStore = deleteFileSearchStore;
const axios_1 = __importDefault(require("axios"));
const mime_types_1 = require("mime-types");
const n8n_workflow_1 = require("n8n-workflow");
const node_stream_1 = require("node:stream");
const transport_1 = require("../transport");
const OPERATION_CHECK_INTERVAL = 1000;
const CHUNK_SIZE = 256 * 1024;
function getFilenameFromMimeType(mimeType, baseName, fallbackExtension) {
    if (!mimeType) {
        return `${baseName}.${fallbackExtension}`;
    }
    return `${baseName}.${(0, mime_types_1.extension)(mimeType) || fallbackExtension}`;
}
async function downloadFile(url, fallbackMimeType, qs) {
    const downloadResponse = (await this.helpers.httpRequest({
        method: 'GET',
        url,
        qs,
        returnFullResponse: true,
        encoding: 'arraybuffer',
    }));
    const mimeType = downloadResponse.headers?.['content-type']?.split(';')?.[0] ?? fallbackMimeType;
    const fileContent = Buffer.from(downloadResponse.body);
    return {
        fileContent,
        mimeType,
    };
}
async function uploadFile(fileContent, mimeType) {
    const numBytes = fileContent.length.toString();
    const uploadInitResponse = (await transport_1.apiRequest.call(this, 'POST', '/upload/v1beta/files', {
        headers: {
            'X-Goog-Upload-Protocol': 'resumable',
            'X-Goog-Upload-Command': 'start',
            'X-Goog-Upload-Header-Content-Length': numBytes,
            'X-Goog-Upload-Header-Content-Type': mimeType,
            'Content-Type': 'application/json',
        },
        option: {
            returnFullResponse: true,
        },
    }));
    const uploadUrl = uploadInitResponse.headers['x-goog-upload-url'];
    const uploadResponse = (await this.helpers.httpRequest({
        method: 'POST',
        url: uploadUrl,
        headers: {
            'Content-Length': numBytes,
            'X-Goog-Upload-Offset': '0',
            'X-Goog-Upload-Command': 'upload, finalize',
        },
        body: fileContent,
    }));
    while (uploadResponse.file.state !== 'ACTIVE' && uploadResponse.file.state !== 'FAILED') {
        await new Promise((resolve) => setTimeout(resolve, OPERATION_CHECK_INTERVAL));
        uploadResponse.file = (await transport_1.apiRequest.call(this, 'GET', `/v1beta/${uploadResponse.file.name}`));
    }
    if (uploadResponse.file.state === 'FAILED') {
        throw new n8n_workflow_1.NodeOperationError(this.getNode(), uploadResponse.file.error?.message ?? 'Unknown error', {
            description: 'Error uploading file',
        });
    }
    return { fileUri: uploadResponse.file.uri, mimeType: uploadResponse.file.mimeType };
}
async function getFileStreamFromUrlOrBinary(i, downloadUrl, fallbackMimeType, qs) {
    if (downloadUrl) {
        const downloadResponse = await axios_1.default.get(downloadUrl, {
            params: qs,
            responseType: 'stream',
        });
        const contentType = downloadResponse.headers['content-type'];
        const mimeType = contentType?.split(';')?.[0] ?? fallbackMimeType ?? 'application/octet-stream';
        return {
            stream: downloadResponse.data,
            mimeType,
        };
    }
    const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i, 'data');
    if (!binaryPropertyName) {
        throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Binary property name or download URL is required', {
            description: 'Error uploading file',
        });
    }
    const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
    if (!binaryData.id) {
        const buffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
        return {
            buffer,
            mimeType: binaryData.mimeType,
        };
    }
    return {
        stream: await this.helpers.getBinaryStream(binaryData.id, CHUNK_SIZE),
        mimeType: binaryData.mimeType,
    };
}
async function uploadStream(stream, config) {
    const { endpoint, mimeType, body } = config;
    const uploadInitResponse = (await transport_1.apiRequest.call(this, 'POST', endpoint, {
        headers: {
            'X-Goog-Upload-Protocol': 'resumable',
            'X-Goog-Upload-Command': 'start',
            'X-Goog-Upload-Header-Content-Type': mimeType,
            'Content-Type': 'application/json',
        },
        body,
        option: { returnFullResponse: true },
    }));
    const uploadUrl = uploadInitResponse.headers['x-goog-upload-url'];
    if (!uploadUrl) {
        throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Failed to get upload URL');
    }
    return (await this.helpers.httpRequest({
        method: 'POST',
        url: uploadUrl,
        headers: {
            'X-Goog-Upload-Offset': '0',
            'X-Goog-Upload-Command': 'upload, finalize',
            'Content-Type': mimeType,
        },
        body: stream,
        returnFullResponse: true,
    }));
}
async function transferFile(i, downloadUrl, fallbackMimeType, qs) {
    const fileData = await getFileStreamFromUrlOrBinary.call(this, i, downloadUrl, fallbackMimeType, qs);
    if ('buffer' in fileData) {
        return await uploadFile.call(this, fileData.buffer, fileData.mimeType);
    }
    const { stream, mimeType } = fileData;
    const uploadResponse = (await uploadStream.call(this, stream, {
        endpoint: '/upload/v1beta/files',
        mimeType,
    }));
    let file = uploadResponse.body.file;
    while (file.state !== 'ACTIVE' && file.state !== 'FAILED') {
        await new Promise((resolve) => setTimeout(resolve, OPERATION_CHECK_INTERVAL));
        file = (await transport_1.apiRequest.call(this, 'GET', `/v1beta/${file.name}`));
    }
    if (file.state === 'FAILED') {
        throw new n8n_workflow_1.NodeOperationError(this.getNode(), file.error?.message ?? 'Unknown error', {
            description: 'Error uploading file',
        });
    }
    return { fileUri: file.uri, mimeType: file.mimeType };
}
async function createFileSearchStore(displayName) {
    return (await transport_1.apiRequest.call(this, 'POST', '/v1beta/fileSearchStores', {
        body: { displayName },
    }));
}
async function uploadToFileSearchStore(i, fileSearchStoreName, displayName, downloadUrl, fallbackMimeType, qs) {
    const fileData = await getFileStreamFromUrlOrBinary.call(this, i, downloadUrl, fallbackMimeType, qs);
    let stream;
    let mimeType;
    if ('buffer' in fileData) {
        stream = node_stream_1.Readable.from(fileData.buffer);
        mimeType = fileData.mimeType;
    }
    else {
        stream = fileData.stream;
        mimeType = fileData.mimeType;
    }
    const uploadResponse = (await uploadStream.call(this, stream, {
        endpoint: `/upload/v1beta/${fileSearchStoreName}:uploadToFileSearchStore`,
        mimeType,
        body: { displayName, mimeType },
    }));
    const operationName = uploadResponse.body.name;
    let operation = (await transport_1.apiRequest.call(this, 'GET', `/v1beta/${operationName}`));
    while (!operation.done) {
        await new Promise((resolve) => setTimeout(resolve, OPERATION_CHECK_INTERVAL));
        operation = (await transport_1.apiRequest.call(this, 'GET', `/v1beta/${operationName}`));
    }
    if (operation.error) {
        throw new n8n_workflow_1.NodeOperationError(this.getNode(), operation.error.message ?? 'Unknown error', {
            description: 'Error uploading file to File Search store',
        });
    }
    return operation.response;
}
async function listFileSearchStores(pageSize, pageToken) {
    const qs = {};
    if (pageSize !== undefined) {
        qs.pageSize = pageSize;
    }
    if (pageToken) {
        qs.pageToken = pageToken;
    }
    return (await transport_1.apiRequest.call(this, 'GET', '/v1beta/fileSearchStores', { qs }));
}
async function deleteFileSearchStore(name, force) {
    const qs = {};
    if (force !== undefined) {
        qs.force = force;
    }
    return (await transport_1.apiRequest.call(this, 'DELETE', `/v1beta/${name}`, { qs }));
}
//# sourceMappingURL=utils.js.map