"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.datasetRowsService = exports.DatasetRowsService = void 0;
const drizzle_orm_1 = require("drizzle-orm");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const uuid_1 = require("uuid");
const constants_1 = require("../../../constants");
const database_1 = require("../../../database");
const tables_1 = require("../../../database/tables");
const uploadFilesToAzure_1 = require("../../../util/uploadFilesToAzure");
const datasetMediaUrlResolver_1 = require("./datasetMediaUrlResolver");
const datasetVoiceTranscript_1 = require("./datasetVoiceTranscript");
const isNonEmptyString = (v) => typeof v === 'string' && v.trim().length > 0;
const getFieldName = (field) => typeof field === 'object' ? String(field.name) : String(field);
const getFieldType = (field) => typeof field === 'object' && field.type
    ? String(field.type)
    : constants_1.DATASET_VAR_TYPE.TEXT;
const getUploadDatasetVarTypeFromConfig = (datasetConfig) => {
    const dataType = Number(datasetConfig?.dataType);
    if (!Number.isFinite(dataType)) {
        return null;
    }
    if (dataType === constants_1.DATASET_UPLOAD_DATA_TYPE.AUDIO) {
        return constants_1.DATASET_VAR_TYPE.VOICE;
    }
    if (dataType === constants_1.DATASET_UPLOAD_DATA_TYPE.IMAGE) {
        return constants_1.DATASET_VAR_TYPE.IMAGE;
    }
    if (dataType === constants_1.DATASET_UPLOAD_DATA_TYPE.VIDEO) {
        return constants_1.DATASET_VAR_TYPE.VIDEO;
    }
    if (dataType === constants_1.DATASET_UPLOAD_DATA_TYPE.CONVERSATION) {
        return constants_1.DATASET_VAR_TYPE.CONVERSATION;
    }
    if (dataType === constants_1.DATASET_UPLOAD_DATA_TYPE.TEXT) {
        return constants_1.DATASET_VAR_TYPE.TEXT;
    }
    return null;
};
const mediaUrlFieldByType = {
    [constants_1.DATASET_VAR_TYPE.VOICE]: 'voiceUrl',
    [constants_1.DATASET_VAR_TYPE.IMAGE]: 'imageUrl',
    [constants_1.DATASET_VAR_TYPE.VIDEO]: 'videoUrl',
    [constants_1.DATASET_VAR_TYPE.CONVERSATION]: 'conversationUrl',
};
const isHttpUrl = (s) => /^https?:\/\//i.test(s);
const isValidAbsoluteHttpUrl = (raw) => {
    const s = raw.trim();
    if (!isHttpUrl(s)) {
        return false;
    }
    try {
        const u = new URL(s);
        return u.protocol === 'http:' || u.protocol === 'https:';
    }
    catch {
        return false;
    }
};
/** Display name stem (no extension) from a media URL path — used for image/video/conversation `value`. */
const filenameStemFromHttpUrl = (urlStr) => {
    const s = urlStr.trim();
    if (!s) {
        return '';
    }
    try {
        const seg = decodeURIComponent(new URL(s).pathname.split('/').pop() || '');
        const base = seg || 'file';
        return path_1.default.parse(base).name || base;
    }
    catch {
        const m = s.match(/\/([^/?#]+)(?:\?|#|$)/);
        if (!m?.[1]) {
            return '';
        }
        try {
            const base = decodeURIComponent(m[1]);
            return path_1.default.parse(base).name || base;
        }
        catch {
            return path_1.default.parse(m[1]).name || m[1];
        }
    }
};
const 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';
};
const 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;
};
class DatasetRowsService {
    static maxFileBytesForExpectedType(expectedType) {
        return (0, datasetMediaUrlResolver_1.maxFileBytesForDatasetMediaType)(expectedType);
    }
    getEffectiveFieldType(dataset, fieldDef) {
        if (dataset.type === constants_1.DATASET_TYPE.UPLOAD) {
            const fromConfig = getUploadDatasetVarTypeFromConfig(dataset.config);
            if (fromConfig) {
                return fromConfig;
            }
        }
        return getFieldType(fieldDef);
    }
    /**
     * For upload datasets: request SAS on blob URLs only for non-audio / non-CSV (TEXT) data types
     * (e.g. image, video, conversation, documents).
     */
    getGenerateSasTokenForUploadRow(dataset) {
        if (dataset.type !== constants_1.DATASET_TYPE.UPLOAD) {
            return false;
        }
        const dataType = Number(dataset.config?.dataType);
        if (!Number.isFinite(dataType)) {
            return false;
        }
        if (dataType === constants_1.DATASET_UPLOAD_DATA_TYPE.AUDIO || dataType === constants_1.DATASET_UPLOAD_DATA_TYPE.TEXT) {
            return false;
        }
        return true;
    }
    async getDatasetOrThrow(datasetId) {
        const db = await (0, database_1.getDb)();
        const [dataset] = await db
            .select({
            id: tables_1.trusysDatasetsTable.id,
            name: tables_1.trusysDatasetsTable.name,
            fields: tables_1.trusysDatasetsTable.fields,
            projectId: tables_1.trusysDatasetsTable.projectId,
            workspaceId: tables_1.trusysDatasetsTable.workspaceId,
            type: tables_1.trusysDatasetsTable.type,
            config: tables_1.trusysDatasetsTable.config,
        })
            .from(tables_1.trusysDatasetsTable)
            .where((0, drizzle_orm_1.eq)(tables_1.trusysDatasetsTable.id, datasetId))
            .limit(1);
        if (!dataset) {
            const err = new Error('Dataset not found');
            err.status = 404;
            throw err;
        }
        return dataset;
    }
    async ingestRemoteUrlToAzure(params) {
        return (0, datasetMediaUrlResolver_1.ingestRemoteDatasetMediaUrl)(params);
    }
    async uploadMulterFileToAzure(params) {
        if (params.expectedType === constants_1.DATASET_VAR_TYPE.VOICE) {
            const ext = path_1.default.extname(params.file.originalname).toLowerCase();
            if (!(0, constants_1.isAllowedDatasetAudioExtension)(ext)) {
                const err = new Error('Invalid audio file type. Only .wav, .mp3, and .opus are allowed.');
                err.status = 400;
                throw err;
            }
        }
        if (params.expectedType === constants_1.DATASET_VAR_TYPE.IMAGE) {
            const ext = path_1.default.extname(params.file.originalname).toLowerCase();
            if (!(0, constants_1.isAllowedDatasetImageExtension)(ext)) {
                const err = new Error('Invalid image file type. Only .jpg, .jpeg, .png, and .webp are allowed.');
                err.status = 400;
                throw err;
            }
        }
        if (params.expectedType === constants_1.DATASET_VAR_TYPE.VIDEO) {
            const ext = path_1.default.extname(params.file.originalname).toLowerCase();
            if (!(0, constants_1.isAllowedDatasetVideoExtension)(ext)) {
                const err = new Error('Invalid video file type. Only .mp4, .mpg, .mpeg, .webm, and .avi are allowed.');
                err.status = 400;
                throw err;
            }
        }
        const contentType = params.file.mimetype || guessContentType(params.file.originalname);
        if (!isAllowedContentType(params.expectedType, contentType)) {
            const err = new Error(`Invalid file type for ${params.expectedType}`);
            err.status = 400;
            throw err;
        }
        let size = params.file.size;
        if (!size && params.file.path) {
            try {
                size = fs_1.default.statSync(params.file.path).size;
            }
            catch {
                size = 0;
            }
        }
        const maxBytes = DatasetRowsService.maxFileBytesForExpectedType(params.expectedType);
        if (size > maxBytes) {
            const err = new Error(`File too large (max ${Math.round(maxBytes / (1024 * 1024))}MB)`);
            err.status = 400;
            throw err;
        }
        const folder = `workspace/${params.orgId}/project/${params.projectId}/dataset/${params.datasetId}/media`;
        const fileName = params.file.filename;
        const urlMap = await (0, uploadFilesToAzure_1.uploadFilesToAzure)([
            {
                filePath: params.file.path,
                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;
    }
    async normalizeAndValidateRow(params) {
        const dataset = params.datasetCached ?? (await this.getDatasetOrThrow(params.datasetId));
        const fields = Array.isArray(dataset.fields) ? dataset.fields : [];
        const fieldNames = fields.map(getFieldName).filter(Boolean);
        const orgId = dataset.workspaceId || '';
        if (!orgId) {
            const err = new Error('Dataset workspaceId is missing');
            err.status = 500;
            throw err;
        }
        const generateSasToken = this.getGenerateSasTokenForUploadRow(dataset);
        const recordData = {};
        let rowBytes = 0;
        for (let idx = 0; idx < fieldNames.length; idx++) {
            const fieldName = fieldNames[idx];
            const fieldDef = fields[idx] ?? fieldName;
            const fieldType = this.getEffectiveFieldType(dataset, fieldDef);
            const uploadedFile = params.filesByField?.[fieldName];
            const raw = params.input?.[fieldName];
            if (fieldType === constants_1.DATASET_VAR_TYPE.TEXT) {
                if (uploadedFile) {
                    const err = new Error(`Unexpected file upload for text field: ${fieldName}`);
                    err.status = 400;
                    throw err;
                }
                const value = typeof raw === 'object' && raw && 'value' in raw ? raw.value : raw;
                if (!isNonEmptyString(value)) {
                    const err = new Error(`Missing required field: ${fieldName}`);
                    err.status = 400;
                    throw err;
                }
                recordData[fieldName] = { type: constants_1.DATASET_VAR_TYPE.TEXT, value: String(value) };
                continue;
            }
            const urlField = mediaUrlFieldByType[fieldType];
            if (!urlField) {
                const err = new Error(`Unsupported field type: ${fieldType}`);
                err.status = 400;
                throw err;
            }
            if (uploadedFile) {
                let voiceTranscript = '';
                if (fieldType === constants_1.DATASET_VAR_TYPE.VOICE && uploadedFile.path) {
                    voiceTranscript = await (0, datasetVoiceTranscript_1.transcribeDatasetAudioFile)(uploadedFile.path, dataset.workspaceId);
                }
                const blobUrl = await this.uploadMulterFileToAzure({
                    file: uploadedFile,
                    orgId,
                    projectId: dataset.projectId,
                    datasetId: dataset.id,
                    token: params.token,
                    expectedType: fieldType,
                    generateSasToken,
                });
                rowBytes += DatasetRowsService.maxFileBytesForExpectedType(fieldType);
                if (rowBytes > DatasetRowsService.MAX_ROW_BYTES) {
                    const err = new Error(`Row exceeds max media size (max ${DatasetRowsService.MAX_ROW_BYTES} bytes)`);
                    err.status = 400;
                    throw err;
                }
                let valueText = '';
                if (raw && typeof raw === 'object' && typeof raw.value === 'string') {
                    valueText = raw.value;
                }
                if (fieldType === constants_1.DATASET_VAR_TYPE.VOICE && voiceTranscript) {
                    valueText = voiceTranscript;
                }
                else if (!isNonEmptyString(valueText)) {
                    valueText = path_1.default.parse(uploadedFile.originalname).name;
                }
                recordData[fieldName] = {
                    type: fieldType,
                    value: valueText,
                    [urlField]: blobUrl,
                };
                continue;
            }
            let incomingUrl;
            let valueText;
            if (typeof raw === 'string') {
                incomingUrl = raw;
            }
            else if (raw && typeof raw === 'object') {
                if (typeof raw[urlField] === 'string') {
                    incomingUrl = raw[urlField];
                }
                else if (typeof raw.url === 'string') {
                    incomingUrl = raw.url;
                }
                else if (typeof raw.value === 'string' && isHttpUrl(raw.value)) {
                    incomingUrl = raw.value;
                }
                if (typeof raw.value === 'string' && !isHttpUrl(raw.value)) {
                    valueText = raw.value;
                }
            }
            if (!isNonEmptyString(incomingUrl)) {
                const err = new Error(`Missing required media URL or file for field: ${fieldName}`);
                err.status = 400;
                throw err;
            }
            if (isHttpUrl(incomingUrl) && !isValidAbsoluteHttpUrl(incomingUrl)) {
                const err = new Error(`Invalid URL for field: ${fieldName}`);
                err.status = 400;
                throw err;
            }
            let existingMediaUrl = '';
            if (params.mode === 'update') {
                const existingCell = params.existingRecordData?.[fieldName];
                if (existingCell && typeof existingCell === 'object') {
                    existingMediaUrl = String(existingCell[urlField] ??
                        existingCell.url ??
                        '').trim();
                }
                else if (typeof existingCell === 'string') {
                    existingMediaUrl = existingCell.trim();
                }
            }
            const mediaUrlUnchangedOnUpdate = params.mode === 'update' &&
                isNonEmptyString(existingMediaUrl) &&
                incomingUrl.trim() === existingMediaUrl;
            const skipDirectUrlFormatCheck = mediaUrlUnchangedOnUpdate && isHttpUrl(incomingUrl) && isValidAbsoluteHttpUrl(incomingUrl);
            const mediaUrlFormatMessage = skipDirectUrlFormatCheck
                ? null
                : (0, constants_1.getDatasetRowDirectMediaUrlValidationError)(fieldType, incomingUrl);
            if (mediaUrlFormatMessage) {
                const err = new Error(mediaUrlFormatMessage);
                err.status = 400;
                throw err;
            }
            let blobUrl = incomingUrl;
            if (isHttpUrl(incomingUrl)) {
                const trimmedUrl = incomingUrl.trim();
                if (mediaUrlUnchangedOnUpdate) {
                    blobUrl = trimmedUrl;
                }
                else if ((0, datasetMediaUrlResolver_1.isTrusysAzureBlobStorageUrl)(trimmedUrl)) {
                    blobUrl = trimmedUrl;
                }
                else {
                    blobUrl = await this.ingestRemoteUrlToAzure({
                        url: trimmedUrl,
                        orgId,
                        projectId: dataset.projectId,
                        datasetId: dataset.id,
                        token: params.token,
                        expectedType: fieldType,
                        generateSasToken,
                    });
                    rowBytes += DatasetRowsService.maxFileBytesForExpectedType(fieldType);
                    if (rowBytes > DatasetRowsService.MAX_ROW_BYTES) {
                        const err = new Error(`Row exceeds max media size (max ${DatasetRowsService.MAX_ROW_BYTES} bytes)`);
                        err.status = 400;
                        throw err;
                    }
                }
            }
            let resolvedValue = valueText ?? '';
            if (fieldType === constants_1.DATASET_VAR_TYPE.VOICE) {
                const keepExistingScript = mediaUrlUnchangedOnUpdate &&
                    isNonEmptyString(resolvedValue) &&
                    !isHttpUrl(resolvedValue);
                if (!keepExistingScript && isHttpUrl(blobUrl)) {
                    const transcript = await (0, datasetVoiceTranscript_1.transcribeDatasetAudioFromUrl)(blobUrl, dataset.workspaceId, params.token);
                    if (isNonEmptyString(transcript)) {
                        resolvedValue = transcript;
                    }
                    else if (!isNonEmptyString(resolvedValue)) {
                        resolvedValue = filenameStemFromHttpUrl(blobUrl);
                    }
                }
            }
            else if (isHttpUrl(blobUrl)) {
                const keepCaption = mediaUrlUnchangedOnUpdate &&
                    isNonEmptyString(resolvedValue) &&
                    !isHttpUrl(resolvedValue);
                if (!keepCaption) {
                    const stem = filenameStemFromHttpUrl(blobUrl);
                    if (isNonEmptyString(stem)) {
                        resolvedValue = stem;
                    }
                }
            }
            recordData[fieldName] = {
                type: fieldType,
                value: resolvedValue,
                [urlField]: blobUrl,
            };
        }
        return { recordData };
    }
    /**
     * Resolve remote media URLs to Trusys blob URLs (batch). Already-Trusys URLs are returned unchanged.
     * Used by the ingest-media-urls-batch HTTP route; dataset row flows call normalization instead.
     */
    async ingestMediaUrlItemsForDataset(params) {
        const dataset = await this.getDatasetOrThrow(params.datasetId);
        const orgId = dataset.workspaceId || '';
        if (!orgId) {
            const err = new Error('Dataset workspaceId is missing');
            err.status = 500;
            throw err;
        }
        const generateSasToken = this.getGenerateSasTokenForUploadRow(dataset);
        return (0, datasetMediaUrlResolver_1.resolveMediaUrlsToTrusysBlobs)({
            items: params.items,
            orgId,
            projectId: dataset.projectId,
            datasetId: dataset.id,
            token: params.token,
            generateSasToken,
        });
    }
    /**
     * Normalize persisted dataset record JSON (media URL ingest, validation).
     * Used by bulk CSV import and legacy PATCH /dataset/:id/table updates.
     */
    async normalizeDatasetRecordForPersist(params) {
        return this.normalizeAndValidateRow({
            datasetId: params.datasetId,
            token: params.token,
            input: params.input,
            mode: params.mode,
            existingRecordData: params.existingRecordData,
            datasetCached: params.datasetCached,
        });
    }
    /** Bulk CSV import: normalize one row (including ingesting external media URLs). */
    async normalizeRecordDataForBulkCsvRow(params) {
        return this.normalizeDatasetRecordForPersist({
            datasetId: params.datasetId,
            token: params.token,
            input: params.input,
            mode: 'create',
            datasetCached: params.datasetCached,
        });
    }
    async createRow(params) {
        const db = await (0, database_1.getDb)();
        const { recordData } = await this.normalizeAndValidateRow({
            datasetId: params.datasetId,
            token: params.token,
            input: params.input,
            filesByField: params.filesByField,
            mode: 'create',
        });
        const maxRecord = await db
            .select({ recordIndex: tables_1.datasetRecordsTable.recordIndex })
            .from(tables_1.datasetRecordsTable)
            .where((0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.datasetId, params.datasetId))
            .orderBy((0, drizzle_orm_1.desc)(tables_1.datasetRecordsTable.recordIndex))
            .limit(1);
        const nextIndex = maxRecord.length > 0 ? maxRecord[0].recordIndex + 1 : 0;
        const recordId = (0, uuid_1.v4)();
        await db.insert(tables_1.datasetRecordsTable).values({
            id: recordId,
            datasetId: params.datasetId,
            recordData,
            recordIndex: nextIndex,
        });
        return { recordId, recordData, recordIndex: nextIndex };
    }
    async updateRow(params) {
        const db = await (0, database_1.getDb)();
        const [existingRow] = await db
            .select({ recordData: tables_1.datasetRecordsTable.recordData })
            .from(tables_1.datasetRecordsTable)
            .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.id, params.recordId), (0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.datasetId, params.datasetId)))
            .limit(1);
        if (!existingRow) {
            const err = new Error('Row not found');
            err.status = 404;
            throw err;
        }
        const existingData = existingRow.recordData &&
            typeof existingRow.recordData === 'object' &&
            !Array.isArray(existingRow.recordData)
            ? { ...existingRow.recordData }
            : {};
        const mergedInput = { ...existingData, ...params.input };
        const { recordData } = await this.normalizeAndValidateRow({
            datasetId: params.datasetId,
            token: params.token,
            input: mergedInput,
            filesByField: params.filesByField,
            mode: 'update',
            existingRecordData: existingData,
        });
        const updated = await db
            .update(tables_1.datasetRecordsTable)
            .set({ recordData, updatedAt: new Date() })
            .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.id, params.recordId), (0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.datasetId, params.datasetId)))
            .returning({ id: tables_1.datasetRecordsTable.id });
        if (!updated?.[0]?.id) {
            const err = new Error('Row not found');
            err.status = 404;
            throw err;
        }
        return { recordId: params.recordId, recordData };
    }
    async deleteRow(params) {
        const db = await (0, database_1.getDb)();
        const [countRow] = await db
            .select({ c: (0, drizzle_orm_1.sql) `count(*)::int` })
            .from(tables_1.datasetRecordsTable)
            .where((0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.datasetId, params.datasetId));
        const total = Number(countRow?.c ?? 0);
        if (total <= 1) {
            const err = new Error('A dataset must contain at least one row. Add another row before removing this one.');
            err.status = 400;
            throw err;
        }
        const deleted = await db
            .delete(tables_1.datasetRecordsTable)
            .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.id, params.recordId), (0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.datasetId, params.datasetId)))
            .returning({ id: tables_1.datasetRecordsTable.id });
        if (!deleted?.[0]?.id) {
            const err = new Error('Row not found');
            err.status = 404;
            throw err;
        }
    }
    async bulkDelete(params) {
        const db = await (0, database_1.getDb)();
        const ids = Array.isArray(params.recordIds) ? params.recordIds.map(String).filter(Boolean) : [];
        if (ids.length === 0) {
            return { deletedIds: [], failed: [] };
        }
        const [countRow] = await db
            .select({ c: (0, drizzle_orm_1.sql) `count(*)::int` })
            .from(tables_1.datasetRecordsTable)
            .where((0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.datasetId, params.datasetId));
        const total = Number(countRow?.c ?? 0);
        const existing = await db
            .select({ id: tables_1.datasetRecordsTable.id })
            .from(tables_1.datasetRecordsTable)
            .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.datasetId, params.datasetId), (0, drizzle_orm_1.inArray)(tables_1.datasetRecordsTable.id, ids)));
        const existingSet = new Set(existing.map((e) => e.id));
        if (existing.length >= total) {
            const err = new Error('Cannot delete all rows. At least one row must remain in the dataset.');
            err.status = 400;
            throw err;
        }
        const missing = ids.filter((id) => !existingSet.has(id));
        const deleted = await db
            .delete(tables_1.datasetRecordsTable)
            .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.datasetId, params.datasetId), (0, drizzle_orm_1.inArray)(tables_1.datasetRecordsTable.id, ids)))
            .returning({ id: tables_1.datasetRecordsTable.id });
        const deletedIds = deleted.map((d) => d.id);
        const failed = missing.map((id) => ({ id, reason: 'Row not found' }));
        return { deletedIds, failed };
    }
}
exports.DatasetRowsService = DatasetRowsService;
// Fallback for media types without a dedicated dataset config cap (e.g. conversation JSON).
DatasetRowsService.MAX_FILE_BYTES = 25 * 1024 * 1024; // 25MB per file
/** Sum cap for all media in one row (allows e.g. two 50MB image/video fields). */
DatasetRowsService.MAX_ROW_BYTES = 100 * 1024 * 1024; // 100MB per row (sum of ingested files)
exports.datasetRowsService = new DatasetRowsService();
//# sourceMappingURL=datasetRowsService.js.map