"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "PrinterFilesController", {
    enumerable: true,
    get: function() {
        return PrinterFilesController;
    }
});
const _awilixexpress = require("awilix-express");
const _authenticate = require("../middleware/authenticate");
const _validators = require("../handlers/validators");
const _serverconstants = require("../server.constants");
const _printerfilescontrollervalidation = require("./validation/printer-files-controller.validation");
const _runtimeexceptions = require("../exceptions/runtime.exceptions");
const _printer = require("../middleware/printer");
const _authorizationconstants = require("../constants/authorization.constants");
const _printerfilesstore = require("../state/printer-files.store");
const _multerservice = require("../services/core/multer.service");
const _loggerfactory = require("../handlers/logger-factory");
const _express = require("express");
const _printerapiinterface = require("../services/printer-api.interface");
const _printerthumbnailcache = require("../state/printer-thumbnail.cache");
const _node = require("@sentry/node");
const _errorutils = require("../utils/error.utils");
const _printerresolver = require("../middleware/printer-resolver");
const _fileanalysisservice = require("../services/file-analysis.service");
const _filestorageservice = require("../services/file-storage.service");
const _nodefs = require("node:fs");
const _printjobservice = require("../services/orm/print-job.service");
const _nodepath = require("node:path");
function _ts_decorate(decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
}
function _ts_metadata(k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}
class PrinterFilesController {
    printerApi;
    printerFilesStore;
    printJobService;
    fileAnalysisService;
    fileStorageService;
    multerService;
    printerThumbnailCache;
    logger;
    constructor(loggerFactory, printerApi, printerFilesStore, printJobService, fileAnalysisService, fileStorageService, multerService, printerThumbnailCache){
        this.printerApi = printerApi;
        this.printerFilesStore = printerFilesStore;
        this.printJobService = printJobService;
        this.fileAnalysisService = fileAnalysisService;
        this.fileStorageService = fileStorageService;
        this.multerService = multerService;
        this.printerThumbnailCache = printerThumbnailCache;
        this.logger = loggerFactory(PrinterFilesController.name);
    }
    async purgeIndexedFiles(req, res) {
        await this.printerFilesStore.purgeFiles();
        res.send();
    }
    async getThumbnails(req, res) {
        const thumbnails = await this.printerThumbnailCache.getAllValues();
        res.send(thumbnails);
    }
    async getFiles(req, res) {
        const { currentPrinterId } = (0, _printerresolver.getScopedPrinter)(req);
        this.logger.log("Refreshing file storage (eager load)");
        const files = await this.printerFilesStore.loadFiles(currentPrinterId);
        res.send(files);
    }
    async startPrintFile(req, res) {
        const { currentPrinterId } = (0, _printerresolver.getScopedPrinter)(req);
        const { filePath } = await (0, _validators.validateInput)(req.body, _printerfilescontrollervalidation.startPrintFileSchema);
        const encodedFilePath = encodeURIComponent(filePath);
        await this.printerApi.startPrint(encodedFilePath);
        this.logger.log(`Started print for printer ${currentPrinterId}`);
        res.send();
    }
    async getFilesCache(req, res) {
        const { currentPrinter } = (0, _printerresolver.getScopedPrinter)(req);
        res.send(this.printerFilesStore.getFiles(currentPrinter.id));
    }
    async downloadFile(req, res) {
        this.logger.log(`Downloading file ${req.params.path}`);
        const { path } = await (0, _validators.validateInput)(req.params, _printerfilescontrollervalidation.downloadFileSchema);
        const encodedFilePath = encodeURIComponent(path);
        const response = await this.printerApi.downloadFile(encodedFilePath);
        res.setHeader("Content-Type", response.headers["content-type"]);
        res.setHeader("Content-Length", response.headers["content-length"]);
        res.setHeader("Content-Disposition", response.headers["content-disposition"]);
        if (response.headers["etag"]?.length) {
            res.setHeader("ETag", response.headers["etag"]);
        }
        response.data.pipe(res);
    }
    async deleteFileOrFolder(req, res) {
        const { currentPrinterId } = (0, _printerresolver.getScopedPrinter)(req);
        const { path } = await (0, _validators.validateInput)(req.query, _printerfilescontrollervalidation.getFileSchema);
        const encodedFilePath = encodeURIComponent(path);
        const result = await this.printerApi.deleteFile(encodedFilePath);
        await this.printerFilesStore.deleteFile(currentPrinterId, path);
        res.send(result);
    }
    async clearPrinterFiles(req, res) {
        const { currentPrinterId } = (0, _printerresolver.getScopedPrinter)(req);
        const failedFiles = [];
        const succeededFiles = [];
        const nonRecursiveFiles = await this.printerApi.getFiles();
        for (let file of nonRecursiveFiles){
            try {
                const encodedFilePath = encodeURIComponent(file.path);
                await this.printerApi.deleteFile(encodedFilePath);
                succeededFiles.push(file);
            } catch (e) {
                failedFiles.push(file);
            }
        }
        await this.printerFilesStore.purgePrinterFiles(currentPrinterId);
        res.send({
            failedFiles,
            succeededFiles
        });
    }
    async getPrinterThumbnail(req, res) {
        const { currentPrinterId } = (0, _printerresolver.getScopedPrinter)(req);
        const printerThumbnail = await this.printerThumbnailCache.getValue(currentPrinterId);
        res.send(printerThumbnail);
    }
    async uploadPrinterFile(req, res) {
        const { currentPrinterId, currentPrinter } = (0, _printerresolver.getScopedPrinter)(req);
        const acceptedExtensions = this.getAcceptedFileExtensions(currentPrinter.printerType);
        const files = await this.multerService.multerLoadFileAsync(req, res, acceptedExtensions, true);
        const { startPrint: startPrintString } = await (0, _validators.validateInput)(req.body, _printerfilescontrollervalidation.uploadFileSchema);
        const startPrint = startPrintString === "true";
        if (!files?.length) {
            throw new _runtimeexceptions.ValidationException({
                error: `No file was available for upload. Did you upload files with one of these extensions: ${acceptedExtensions.join(", ")}?`
            });
        }
        if (files.length > 1) {
            throw new _runtimeexceptions.ValidationException({
                error: "Only 1 file can be uploaded at a time"
            });
        }
        const uploadedFile = files[0];
        const token = this.multerService.startTrackingSession(uploadedFile, currentPrinterId);
        await this.printerApi.uploadFile(uploadedFile, startPrint, token).catch((e)=>{
            try {
                this.multerService.clearUploadedFile(uploadedFile);
            } catch (e) {
                this.logger.error(`Could not remove uploaded file from temporary storage ${(0, _errorutils.errorSummary)(e)}`);
            }
            throw e;
        });
        await this.printerFilesStore.loadFiles(currentPrinterId);
        const ext = (0, _nodepath.extname)(uploadedFile.originalname);
        const tempPathWithExt = uploadedFile.path + ext;
        try {
            this.logger.log(`Processing uploaded file: ${uploadedFile.originalname} (ext: ${ext})`);
            if (!(0, _nodefs.existsSync)(uploadedFile.path)) {
                throw new _runtimeexceptions.NotFoundException(`Upload file does not exist: ${uploadedFile.path}`);
            }
            (0, _nodefs.copyFileSync)(uploadedFile.path, tempPathWithExt);
            const fileHash = await this.fileStorageService.calculateFileHash(tempPathWithExt);
            this.logger.log(`File hash: ${fileHash.substring(0, 12)}...`);
            const existingJob = await this.fileStorageService.findDuplicateByHash(fileHash);
            let metadata;
            let fileStorageId;
            if (existingJob && 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: uploadedFile.originalname
                    };
                    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: uploadedFile.originalname
                    };
                    fileStorageId = existingJob.fileStorageId;
                    await this.fileStorageService.saveMetadata(fileStorageId, metadata, fileHash, uploadedFile.originalname);
                } 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, uploadedFile.originalname);
                    this.logger.log(`Analysis complete and cached: ${fileStorageId}`);
                }
            } else {
                this.logger.log(`Analyzing new file: ${uploadedFile.originalname}`);
                const analysisResult = await this.fileAnalysisService.analyzeFile(tempPathWithExt);
                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, thumbnails=${thumbnails.length}`);
                fileStorageId = await this.fileStorageService.saveFile(uploadedFile, fileHash);
                this.logger.log(`Saved file to storage: ${fileStorageId} (deterministic from hash+name)`);
                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, uploadedFile.originalname, thumbnailMetadata);
                this.logger.log(`Saved metadata JSON for ${fileStorageId}`);
            }
            const job = await this.printJobService.createPendingJob(currentPrinterId, uploadedFile.originalname, metadata, currentPrinter.name);
            job.fileStorageId = fileStorageId;
            job.fileHash = fileHash;
            await this.printJobService.printJobRepository.save(job);
            this.logger.log(`Created job ${job.id}: format=${job.fileFormat}, ` + `state=${job.analysisState}, ` + `storageId=${fileStorageId}, ` + `hash=${fileHash.substring(0, 8)}...`);
            if ((0, _nodefs.existsSync)(tempPathWithExt)) {
                (0, _nodefs.unlinkSync)(tempPathWithExt);
            }
        } catch (error) {
            this.logger.error(`File processing failed: ${(0, _errorutils.errorSummary)(error)}`);
            (0, _node.captureException)(error);
        } finally{
            try {
                this.multerService.clearUploadedFile(uploadedFile);
            } catch (e) {
                this.logger.error(`Could not remove uploaded file from temporary storage ${(0, _errorutils.errorSummary)(e)}`);
            }
        }
        res.send();
    }
    getAcceptedFileExtensions(printerType) {
        if (printerType === _printerapiinterface.BambuType) {
            return _serverconstants.AppConstants.defaultAcceptedBambuExtensions;
        }
        return _serverconstants.AppConstants.defaultAcceptedGcodeExtensions;
    }
}
_ts_decorate([
    (0, _awilixexpress.POST)(),
    (0, _awilixexpress.route)("/purge"),
    (0, _awilixexpress.before)((0, _authenticate.permission)(_authorizationconstants.PERMS.PrinterFiles.Clear)),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _express.Request === "undefined" ? Object : _express.Request,
        typeof _express.Response === "undefined" ? Object : _express.Response
    ]),
    _ts_metadata("design:returntype", Promise)
], PrinterFilesController.prototype, "purgeIndexedFiles", null);
_ts_decorate([
    (0, _awilixexpress.GET)(),
    (0, _awilixexpress.route)("/thumbnails"),
    (0, _awilixexpress.before)((0, _authenticate.permission)(_authorizationconstants.PERMS.PrinterFiles.Get)),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _express.Request === "undefined" ? Object : _express.Request,
        typeof _express.Response === "undefined" ? Object : _express.Response
    ]),
    _ts_metadata("design:returntype", Promise)
], PrinterFilesController.prototype, "getThumbnails", null);
_ts_decorate([
    (0, _awilixexpress.GET)(),
    (0, _awilixexpress.route)("/:id"),
    (0, _awilixexpress.before)((0, _authenticate.permission)(_authorizationconstants.PERMS.PrinterFiles.Get)),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _express.Request === "undefined" ? Object : _express.Request,
        typeof _express.Response === "undefined" ? Object : _express.Response
    ]),
    _ts_metadata("design:returntype", Promise)
], PrinterFilesController.prototype, "getFiles", null);
_ts_decorate([
    (0, _awilixexpress.POST)(),
    (0, _awilixexpress.route)("/:id/select"),
    (0, _awilixexpress.route)("/:id/print"),
    (0, _awilixexpress.before)((0, _authenticate.permission)(_authorizationconstants.PERMS.PrinterFiles.Actions)),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _express.Request === "undefined" ? Object : _express.Request,
        typeof _express.Response === "undefined" ? Object : _express.Response
    ]),
    _ts_metadata("design:returntype", Promise)
], PrinterFilesController.prototype, "startPrintFile", null);
_ts_decorate([
    (0, _awilixexpress.GET)(),
    (0, _awilixexpress.route)("/:id/cache"),
    (0, _awilixexpress.before)((0, _authenticate.permission)(_authorizationconstants.PERMS.PrinterFiles.Get)),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _express.Request === "undefined" ? Object : _express.Request,
        typeof _express.Response === "undefined" ? Object : _express.Response
    ]),
    _ts_metadata("design:returntype", Promise)
], PrinterFilesController.prototype, "getFilesCache", null);
_ts_decorate([
    (0, _awilixexpress.GET)(),
    (0, _awilixexpress.route)("/:id/download/:path"),
    (0, _awilixexpress.before)((0, _authenticate.permission)(_authorizationconstants.PERMS.PrinterFiles.Get)),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _express.Request === "undefined" ? Object : _express.Request,
        typeof _express.Response === "undefined" ? Object : _express.Response
    ]),
    _ts_metadata("design:returntype", Promise)
], PrinterFilesController.prototype, "downloadFile", null);
_ts_decorate([
    (0, _awilixexpress.DELETE)(),
    (0, _awilixexpress.route)("/:id"),
    (0, _awilixexpress.before)((0, _authenticate.permission)(_authorizationconstants.PERMS.PrinterFiles.Delete)),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _express.Request === "undefined" ? Object : _express.Request,
        typeof _express.Response === "undefined" ? Object : _express.Response
    ]),
    _ts_metadata("design:returntype", Promise)
], PrinterFilesController.prototype, "deleteFileOrFolder", null);
_ts_decorate([
    (0, _awilixexpress.DELETE)(),
    (0, _awilixexpress.route)("/:id/clear"),
    (0, _awilixexpress.before)((0, _authenticate.permission)(_authorizationconstants.PERMS.PrinterFiles.Clear)),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _express.Request === "undefined" ? Object : _express.Request,
        typeof _express.Response === "undefined" ? Object : _express.Response
    ]),
    _ts_metadata("design:returntype", Promise)
], PrinterFilesController.prototype, "clearPrinterFiles", null);
_ts_decorate([
    (0, _awilixexpress.GET)(),
    (0, _awilixexpress.route)("/:id/thumbnail"),
    (0, _awilixexpress.before)((0, _authenticate.permission)(_authorizationconstants.PERMS.PrinterFiles.Get)),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _express.Request === "undefined" ? Object : _express.Request,
        typeof _express.Response === "undefined" ? Object : _express.Response
    ]),
    _ts_metadata("design:returntype", Promise)
], PrinterFilesController.prototype, "getPrinterThumbnail", null);
_ts_decorate([
    (0, _awilixexpress.POST)(),
    (0, _awilixexpress.route)("/:id/upload"),
    (0, _awilixexpress.before)((0, _authenticate.permission)(_authorizationconstants.PERMS.PrinterFiles.Upload)),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _express.Request === "undefined" ? Object : _express.Request,
        typeof _express.Response === "undefined" ? Object : _express.Response
    ]),
    _ts_metadata("design:returntype", Promise)
], PrinterFilesController.prototype, "uploadPrinterFile", null);
PrinterFilesController = _ts_decorate([
    (0, _awilixexpress.route)(_serverconstants.AppConstants.apiRoute + "/printer-files"),
    (0, _awilixexpress.before)([
        (0, _authenticate.authenticate)(),
        (0, _authenticate.authorizeRoles)([
            _authorizationconstants.ROLES.ADMIN,
            _authorizationconstants.ROLES.OPERATOR
        ]),
        (0, _printer.printerResolveMiddleware)()
    ]),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _loggerfactory.ILoggerFactory === "undefined" ? Object : _loggerfactory.ILoggerFactory,
        typeof _printerapiinterface.IPrinterApi === "undefined" ? Object : _printerapiinterface.IPrinterApi,
        typeof _printerfilesstore.PrinterFilesStore === "undefined" ? Object : _printerfilesstore.PrinterFilesStore,
        typeof _printjobservice.PrintJobService === "undefined" ? Object : _printjobservice.PrintJobService,
        typeof _fileanalysisservice.FileAnalysisService === "undefined" ? Object : _fileanalysisservice.FileAnalysisService,
        typeof _filestorageservice.FileStorageService === "undefined" ? Object : _filestorageservice.FileStorageService,
        typeof _multerservice.MulterService === "undefined" ? Object : _multerservice.MulterService,
        typeof _printerthumbnailcache.PrinterThumbnailCache === "undefined" ? Object : _printerthumbnailcache.PrinterThumbnailCache
    ])
], PrinterFilesController);

//# sourceMappingURL=printer-files.controller.js.map