"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "PrintFileDownloaderService", {
    enumerable: true,
    get: function() {
        return PrintFileDownloaderService;
    }
});
const _node = require("@sentry/node");
const _nodefs = require("node:fs");
const _nodepath = require("node:path");
const _nodeos = require("node:os");
class PrintFileDownloaderService {
    eventEmitter2;
    printJobService;
    fileStorageService;
    fileAnalysisService;
    printerApiFactory;
    printerCache;
    logger;
    constructor(loggerFactory, eventEmitter2, printJobService, fileStorageService, fileAnalysisService, printerApiFactory, printerCache){
        this.eventEmitter2 = eventEmitter2;
        this.printJobService = printJobService;
        this.fileStorageService = fileStorageService;
        this.fileAnalysisService = fileAnalysisService;
        this.printerApiFactory = printerApiFactory;
        this.printerCache = printerCache;
        this.logger = loggerFactory(PrintFileDownloaderService.name);
        this.eventEmitter2.on("printJob.needsFileDownload", (event)=>{
            this.handleFileDownloadRequest(event.jobId).catch((error)=>{
                this.logger.error(`Failed to handle file download for job ${event.jobId}`, error);
                (0, _node.captureException)(error);
            });
        });
        this.logger.log("Print file downloader service initialized");
    }
    async handleFileDownloadRequest(jobId) {
        this.logger.log(`Handling file download request for job ${jobId}`);
        try {
            const job = await this.printJobService.getJobByIdOrFail(jobId);
            if (job.fileStorageId) {
                this.logger.log(`Job ${jobId} already has fileStorageId ${job.fileStorageId} - skipping download`);
                return;
            }
            if (!job.printerId) {
                this.logger.error(`Job ${jobId} has no printerId - cannot download file`);
                return;
            }
            const printer = await this.printerCache.getValue(job.printerId);
            if (!printer) {
                this.logger.error(`Printer ${job.printerId} not found for job ${jobId}`);
                return;
            }
            const printerApi = this.printerApiFactory.getById(job.printerId);
            this.logger.log(`Downloading file ${job.fileName} from printer ${printer.name} (${printer.printerType})`);
            let fileBuffer;
            try {
                const response = await printerApi.downloadFile(job.fileName);
                const chunks = [];
                const stream = response.data;
                await new Promise((resolve, reject)=>{
                    stream.on('data', (chunk)=>chunks.push(chunk));
                    stream.on('end', ()=>resolve());
                    stream.on('error', (err)=>reject(err));
                });
                fileBuffer = Buffer.concat(chunks);
            } catch (downloadError) {
                this.logger.error(`Failed to download file from printer: ${downloadError}`);
                job.analysisState = "FAILED";
                job.statusReason = `File download failed: ${downloadError instanceof Error ? downloadError.message : "Unknown error"}`;
                await this.printJobService.printJobRepository.save(job);
                return;
            }
            this.logger.log(`Downloaded ${fileBuffer.length} bytes for job ${jobId}`);
            const tempPath = (0, _nodepath.join)((0, _nodeos.tmpdir)(), `fdm-monster-download-${jobId}-${Date.now()}-${job.fileName}`);
            (0, _nodefs.writeFileSync)(tempPath, fileBuffer);
            try {
                const fileHash = await this.fileStorageService.calculateFileHash(tempPath);
                this.logger.log(`File hash for job ${jobId}: ${fileHash.substring(0, 12)}...`);
                const existingJob = await this.fileStorageService.findDuplicateByHash(fileHash);
                let metadata;
                let fileStorageId;
                if (existingJob?.fileStorageId) {
                    const cachedMetadata = await this.fileStorageService.loadMetadata(existingJob.fileStorageId);
                    if (cachedMetadata) {
                        this.logger.log(`Duplicate file detected (job ${existingJob.id}, hash match) - reusing storage ${existingJob.fileStorageId}`);
                        metadata = {
                            ...cachedMetadata,
                            fileName: job.fileName
                        };
                        fileStorageId = existingJob.fileStorageId;
                    } else if (existingJob.analysisState === "ANALYZED" && existingJob.metadata) {
                        this.logger.log(`Duplicate file with DB metadata (job ${existingJob.id}) - reusing storage ${existingJob.fileStorageId}`);
                        metadata = {
                            ...existingJob.metadata,
                            fileName: job.fileName
                        };
                        fileStorageId = existingJob.fileStorageId;
                        await this.fileStorageService.saveMetadata(fileStorageId, metadata, fileHash, job.fileName);
                    } else {
                        this.logger.log(`Duplicate file not analyzed - reusing storage ${existingJob.fileStorageId}, analyzing now`);
                        const existingFilePath = this.fileStorageService.getFilePath(existingJob.fileStorageId);
                        const analysisResult = await this.fileAnalysisService.analyzeFile(existingFilePath);
                        metadata = analysisResult.metadata;
                        fileStorageId = existingJob.fileStorageId;
                        await this.fileStorageService.saveMetadata(fileStorageId, metadata, fileHash, job.fileName);
                    }
                } else {
                    this.logger.log(`Analyzing downloaded file: ${job.fileName}`);
                    const analysisResult = await this.fileAnalysisService.analyzeFile(tempPath);
                    metadata = analysisResult.metadata;
                    const thumbnails = analysisResult.thumbnails;
                    this.logger.log(`Analysis complete: format=${metadata.fileFormat}, layers=${metadata.totalLayers}, time=${metadata.gcodePrintTimeSeconds}s, filament=${metadata.filamentUsedGrams}g`);
                    const fileObject = {
                        path: tempPath,
                        originalname: job.fileName,
                        mimetype: "application/octet-stream",
                        size: fileBuffer.length
                    };
                    fileStorageId = await this.fileStorageService.saveFile(fileObject, fileHash);
                    this.logger.log(`Saved file to storage: ${fileStorageId}`);
                    let thumbnailMetadata = [];
                    if (thumbnails.length > 0) {
                        thumbnailMetadata = await this.fileStorageService.saveThumbnails(fileStorageId, thumbnails);
                        this.logger.log(`Saved ${thumbnailMetadata.length} thumbnail(s) for ${fileStorageId}`);
                    }
                    await this.fileStorageService.saveMetadata(fileStorageId, metadata, fileHash, job.fileName, thumbnailMetadata);
                    this.logger.log(`Saved metadata JSON for ${fileStorageId}`);
                }
                job.fileStorageId = fileStorageId;
                job.fileHash = fileHash;
                job.fileSize = fileBuffer.length;
                job.fileFormat = metadata.fileFormat;
                job.metadata = metadata;
                job.analysisState = "ANALYZED";
                job.analyzedAt = new Date();
                await this.printJobService.printJobRepository.save(job);
                this.logger.log(`Successfully processed downloaded file for job ${jobId}: storageId=${fileStorageId}, analysisState=${job.analysisState}`);
            } finally{
                try {
                    (0, _nodefs.unlinkSync)(tempPath);
                } catch (cleanupError) {
                    this.logger.warn(`Failed to clean up temp file ${tempPath}: ${cleanupError}`);
                }
            }
        } catch (error) {
            this.logger.error(`Failed to download and analyze file for job ${jobId}`, error);
            (0, _node.captureException)(error);
            try {
                const job = await this.printJobService.printJobRepository.findOne({
                    where: {
                        id: jobId
                    }
                });
                if (job) {
                    job.analysisState = "FAILED";
                    job.statusReason = `File download/analysis failed: ${error instanceof Error ? error.message : "Unknown error"}`;
                    await this.printJobService.printJobRepository.save(job);
                }
            } catch (updateError) {
                this.logger.error(`Failed to mark job ${jobId} as failed`, updateError);
            }
        }
    }
}

//# sourceMappingURL=print-file-downloader.service.js.map