"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isTrusysAzureBlobStorageUrl = isTrusysAzureBlobStorageUrl;
exports.maxFileBytesForDatasetMediaType = maxFileBytesForDatasetMediaType;
exports.ingestRemoteDatasetMediaUrl = ingestRemoteDatasetMediaUrl;
exports.resolveMediaUrlsToTrusysBlobs = resolveMediaUrlsToTrusysBlobs;
const fs_1 = __importDefault(require("fs"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const uuid_1 = require("uuid");
const constants_1 = require("../../../constants");
const uploadFilesToAzure_1 = require("../../../util/uploadFilesToAzure");
const MAX_FILE_BYTES_FALLBACK = 25 * 1024 * 1024;
const isHttpUrl = (s) => /^https?:\/\//i.test(s);
/**
 * URLs that already point at Trusys-managed storage should be stored as-is (no re-download / re-upload).
 * Primary: Azure Blob host. Secondary: path layout used by Control Plane uploads (`/workspace/.../project/...`).
 */
function isTrusysAzureBlobStorageUrl(raw) {
    const s = raw.trim();
    if (!isHttpUrl(s)) {
        return false;
    }
    try {
        const u = new URL(s);
        const host = u.hostname.toLowerCase();
        if (host.endsWith('.blob.core.windows.net') || host.endsWith('.dfs.core.windows.net')) {
            return true;
        }
        const pathLower = decodeURIComponent(u.pathname).toLowerCase();
        if (pathLower.includes('/workspace/') && pathLower.includes('/project/')) {
            return true;
        }
    }
    catch {
        return false;
    }
    return false;
}
function guessContentType(urlOrName, fallback) {
    if (fallback) {
        return fallback;
    }
    const ext = path_1.default.extname(urlOrName).toLowerCase();
    const map = {
        '.wav': 'audio/wav',
        '.mp3': 'audio/mpeg',
        '.opus': 'audio/opus',
        '.m4a': 'audio/mp4',
        '.ogg': 'audio/ogg',
        '.mp4': 'video/mp4',
        '.webm': 'video/webm',
        '.mpg': 'video/mpeg',
        '.mpeg': 'video/mpeg',
        '.avi': 'video/x-msvideo',
        '.jpg': 'image/jpeg',
        '.jpeg': 'image/jpeg',
        '.png': 'image/png',
        '.webp': 'image/webp',
        '.json': 'application/json',
        '.txt': 'text/plain',
        '.pdf': 'application/pdf',
    };
    return map[ext] || 'application/octet-stream';
}
function isAllowedContentType(datasetVarType, contentType) {
    const ct = contentType.toLowerCase();
    if (datasetVarType === constants_1.DATASET_VAR_TYPE.VOICE) {
        return (ct.startsWith('audio/') ||
            ct === 'application/octet-stream' ||
            ct === 'binary/octet-stream');
    }
    if (datasetVarType === constants_1.DATASET_VAR_TYPE.IMAGE) {
        return (ct.startsWith('image/') ||
            ct === 'application/octet-stream' ||
            ct === 'binary/octet-stream');
    }
    if (datasetVarType === constants_1.DATASET_VAR_TYPE.VIDEO) {
        return (ct.startsWith('video/') ||
            ct === 'application/octet-stream' ||
            ct === 'binary/octet-stream');
    }
    if (datasetVarType === constants_1.DATASET_VAR_TYPE.CONVERSATION) {
        return ct.startsWith('application/json') || ct.startsWith('text/');
    }
    return true;
}
function maxFileBytesForDatasetMediaType(expectedType) {
    if (expectedType === constants_1.DATASET_VAR_TYPE.VOICE) {
        return (0, constants_1.getDatasetAudioMaxFileBytes)();
    }
    if (expectedType === constants_1.DATASET_VAR_TYPE.IMAGE) {
        return (0, constants_1.getDatasetImageMaxFileBytes)();
    }
    if (expectedType === constants_1.DATASET_VAR_TYPE.VIDEO) {
        return (0, constants_1.getDatasetVideoMaxFileBytes)();
    }
    return MAX_FILE_BYTES_FALLBACK;
}
/**
 * Download a remote http(s) media file and upload it to the dataset media folder in Azure (via Control Plane).
 * Caller must ensure the URL is not already a Trusys blob URL if passthrough is desired.
 */
async function ingestRemoteDatasetMediaUrl(params) {
    const response = await fetch(params.url);
    if (!response.ok) {
        const err = new Error(`Failed to download url. Please check the url and try again.`);
        err.status = 400;
        throw err;
    }
    const contentTypeHeader = response.headers.get('content-type') || undefined;
    const contentLengthHeader = response.headers.get('content-length');
    const contentLength = contentLengthHeader ? Number(contentLengthHeader) : undefined;
    const maxBytes = params.expectedType
        ? maxFileBytesForDatasetMediaType(params.expectedType)
        : MAX_FILE_BYTES_FALLBACK;
    if (typeof contentLength === 'number' &&
        Number.isFinite(contentLength) &&
        contentLength > maxBytes) {
        const err = new Error(`File too large (max ${Math.round(maxBytes / (1024 * 1024))}MB)`);
        err.status = 400;
        throw err;
    }
    const contentType = guessContentType(params.url, contentTypeHeader);
    if (params.expectedType &&
        !isAllowedContentType(params.expectedType, contentType)) {
        const err = new Error(`Invalid file type for ${params.expectedType}`);
        err.status = 400;
        throw err;
    }
    const fileExt = path_1.default.extname(new URL(params.url).pathname) || '';
    const tmpDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'dataset-media-'));
    const fileName = `${(0, uuid_1.v4)()}${fileExt || ''}`;
    const tmpFilePath = path_1.default.join(tmpDir, fileName);
    const arrayBuffer = await response.arrayBuffer();
    const buf = Buffer.from(arrayBuffer);
    if (buf.length > maxBytes) {
        const err = new Error(`File too large (max ${Math.round(maxBytes / (1024 * 1024))}MB)`);
        err.status = 400;
        throw err;
    }
    fs_1.default.writeFileSync(tmpFilePath, buf);
    try {
        const folder = `workspace/${params.orgId}/project/${params.projectId}/dataset/${params.datasetId}/media`;
        const urlMap = await (0, uploadFilesToAzure_1.uploadFilesToAzure)([
            {
                filePath: tmpFilePath,
                fileName,
                contentType,
                cleanupAfterUpload: true,
                privateContainer: true,
                generateSasToken: params.generateSasToken,
            },
        ], params.token, folder);
        const blobUrl = urlMap[fileName] || '';
        if (!blobUrl) {
            const err = new Error('Upload succeeded but no blob url returned');
            err.status = 500;
            throw err;
        }
        return blobUrl;
    }
    finally {
        try {
            if (fs_1.default.existsSync(tmpFilePath)) {
                fs_1.default.unlinkSync(tmpFilePath);
            }
        }
        catch { }
        try {
            if (fs_1.default.existsSync(tmpDir)) {
                fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
            }
        }
        catch { }
    }
}
/**
 * For each item: if URL is already Trusys blob storage, return unchanged; otherwise ingest to Azure.
 */
async function resolveMediaUrlsToTrusysBlobs(params) {
    const out = [];
    for (const item of params.items) {
        const trimmed = String(item.url ?? '').trim();
        if (!trimmed) {
            const err = new Error('Each item must include a non-empty url');
            err.status = 400;
            throw err;
        }
        if (!isHttpUrl(trimmed)) {
            const err = new Error('Each url must be http(s)');
            err.status = 400;
            throw err;
        }
        if (isTrusysAzureBlobStorageUrl(trimmed)) {
            out.push(trimmed);
            continue;
        }
        const blobUrl = await ingestRemoteDatasetMediaUrl({
            url: trimmed,
            orgId: params.orgId,
            projectId: params.projectId,
            datasetId: params.datasetId,
            token: params.token,
            expectedType: item.expectedType || undefined,
            generateSasToken: params.generateSasToken,
        });
        out.push(blobUrl);
    }
    return out;
}
//# sourceMappingURL=datasetMediaUrlResolver.js.map