"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "PrintJobController", {
    enumerable: true,
    get: function() {
        return PrintJobController;
    }
});
const _awilixexpress = require("awilix-express");
const _serverconstants = require("../server.constants");
const _express = require("express");
const _authenticate = require("../middleware/authenticate");
const _authorizationconstants = require("../constants/authorization.constants");
const _printjobvalidation = require("../services/validators/print-job.validation");
const _validators = require("../handlers/validators");
const _printjobservice = require("../services/orm/print-job.service");
const _fileanalysisservice = require("../services/file-analysis.service");
const _filestorageservice = require("../services/file-storage.service");
const _loggerfactory = require("../handlers/logger-factory");
const _paramconvertermiddleware = require("../middleware/param-converter.middleware");
const _runtimeexceptions = require("../exceptions/runtime.exceptions");
const _thumbnailutil = require("../utils/thumbnail.util");
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 PrintJobController {
    printJobService;
    fileAnalysisService;
    fileStorageService;
    logger;
    constructor(loggerFactory, printJobService, fileAnalysisService, fileStorageService){
        this.printJobService = printJobService;
        this.fileAnalysisService = fileAnalysisService;
        this.fileStorageService = fileStorageService;
        this.logger = loggerFactory(PrintJobController.name);
    }
    async searchJobs(req, res) {
        const { searchPrinter, searchFile, startDate, endDate } = await (0, _validators.validateInput)(req.query, _printjobvalidation.searchJobsSchema);
        const endDateObj = endDate ? this.toEndOfDay(new Date(endDate)) : undefined;
        const result = await this.printJobService.searchPrintJobs(searchPrinter, searchFile, startDate ? new Date(startDate) : undefined, endDateObj);
        res.send(result);
    }
    async searchJobsPaged(req, res) {
        const { page, pageSize, searchPrinter, searchFile, startDate, endDate } = await (0, _validators.validateInput)(req.query, _printjobvalidation.searchJobsPagedSchema);
        const endDateObj = endDate ? this.toEndOfDay(new Date(endDate)) : undefined;
        const [items, count] = await this.printJobService.searchPrintJobsPaged(searchPrinter, searchFile, startDate ? new Date(startDate) : undefined, endDateObj, page, pageSize);
        const itemsWithThumbnails = await Promise.all(items.map(async (job)=>{
            let thumbnails = [];
            if (job.fileStorageId) {
                try {
                    const metadata = await this.fileStorageService.loadMetadata(job.fileStorageId);
                    thumbnails = (0, _thumbnailutil.extractThumbnailsFromMetadata)(metadata);
                } catch  {}
            }
            return {
                ...job,
                thumbnails
            };
        }));
        res.send({
            items: itemsWithThumbnails,
            count,
            pages: Math.ceil(count / pageSize)
        });
    }
    async getJob(req, res) {
        const jobId = req.local.id;
        const job = await this.printJobService.getJobByIdOrFail(jobId, [
            'printer'
        ]);
        try {
            let thumbnails = [];
            if (job.fileStorageId) {
                const metadata = await this.fileStorageService.loadMetadata(job.fileStorageId);
                thumbnails = (0, _thumbnailutil.extractThumbnailsFromMetadata)(metadata);
            }
            res.send({
                ...job,
                thumbnails
            });
        } catch (error) {
            this.logger.error(`Failed to get job ${jobId}: ${error}`);
            res.status(500).send({
                error: "Failed to get job"
            });
        }
    }
    async setCompleted(req, res) {
        const jobId = req.local.id;
        const job = await this.printJobService.getJobByIdOrFail(jobId);
        try {
            if ([
                "PENDING",
                "QUEUED"
            ].includes(job.status)) {
                res.status(400).send({
                    error: "Can only mark jobs which are not \"PENDING\" | \"QUEUED\" as completed",
                    currentStatus: job.status,
                    suggestion: "This endpoint is for resolving jobs with unknown state"
                });
                return;
            }
            const previousStatus = job.status;
            await this.printJobService.markAsCompleted(jobId);
            res.send({
                message: "Job marked as completed",
                jobId,
                previousStatus,
                newStatus: "COMPLETED"
            });
        } catch (error) {
            this.logger.error(`Failed to mark job ${jobId} as completed: ${error}`);
            res.status(500).send({
                error: "Failed to update job status",
                message: error instanceof Error ? error.message : "Unknown error"
            });
        }
    }
    async setFailed(req, res) {
        const jobId = req.local.id;
        const job = await this.printJobService.getJobByIdOrFail(jobId);
        const previousStatus = job.status;
        if (![
            "UNKNOWN",
            "PRINTING",
            "CANCELLED",
            "COMPLETED"
        ].includes(job.status)) {
            res.status(400).send({
                error: "Can only mark UNKNOWN, PRINTING, CANCELLED, or COMPLETED jobs as failed",
                currentStatus: job.status
            });
            return;
        }
        try {
            await this.printJobService.markAsFailed(jobId, "Manually marked as failed by user");
            res.send({
                message: "Job marked as failed",
                jobId,
                previousStatus,
                newStatus: "FAILED"
            });
        } catch (error) {
            this.logger.error(`Failed to mark job ${jobId} as failed: ${error}`);
            res.status(500).send({
                error: "Failed to update job status",
                message: error instanceof Error ? error.message : "Unknown error"
            });
        }
    }
    async setCancelled(req, res) {
        const jobId = req.local.id;
        const job = await this.printJobService.getJobByIdOrFail(jobId);
        const previousStatus = job.status;
        if (![
            "UNKNOWN",
            "PRINTING",
            "PAUSED"
        ].includes(job.status)) {
            res.status(400).send({
                error: "Can only mark UNKNOWN, PRINTING, or PAUSED jobs as cancelled",
                currentStatus: job.status
            });
            return;
        }
        try {
            await this.printJobService.markAsCancelled(jobId, "Manually marked as cancelled by user");
            res.send({
                message: "Job marked as cancelled",
                jobId,
                previousStatus,
                newStatus: "CANCELLED"
            });
        } catch (error) {
            this.logger.error(`Failed to mark job ${jobId} as cancelled: ${error}`);
            res.status(500).send({
                error: "Failed to update job status",
                message: error instanceof Error ? error.message : "Unknown error"
            });
        }
    }
    async setUnknown(req, res) {
        const jobId = req.local.id;
        const job = await this.printJobService.getJobByIdOrFail(jobId);
        const previousStatus = job.status;
        if (![
            "PRINTING",
            "PAUSED"
        ].includes(job.status)) {
            res.status(400).send({
                error: "Can only mark PRINTING or PAUSED jobs as unknown",
                currentStatus: job.status,
                suggestion: "This endpoint is for marking jobs with uncertain state (e.g., after connection loss)"
            });
            return;
        }
        try {
            await this.printJobService.markAsUnknown(jobId);
            res.send({
                message: "Job marked as unknown",
                jobId,
                previousStatus,
                newStatus: "UNKNOWN"
            });
        } catch (error) {
            this.logger.error(`Failed to mark job ${jobId} as unknown: ${error}`);
            res.status(500).send({
                error: "Failed to update job status",
                message: error instanceof Error ? error.message : "Unknown error"
            });
        }
    }
    async reAnalyzeJob(req, res) {
        const jobId = req.local.id;
        const job = await this.printJobService.getJobByIdOrFail(jobId);
        this.logger.log(`Re-analyzing job ${jobId}`);
        try {
            if (!job.fileStorageId) {
                this.logger.log(`Job ${jobId} has no fileStorageId - triggering download and analysis`);
                await this.printJobService.triggerFileAnalysis(jobId);
                res.send({
                    message: "File download and analysis triggered (async)",
                    jobId,
                    status: "pending"
                });
                return;
            }
            const filePath = this.fileStorageService.getFilePath(job.fileStorageId);
            const exists = await this.fileAnalysisService.needsAnalysis(filePath);
            if (!exists) {
                throw new _runtimeexceptions.NotFoundException(`File not found in storage: ${job.fileStorageId}`);
            }
            this.logger.log(`Re-analyzing file for job ${jobId}: ${filePath}`);
            job.analysisState = "ANALYZING";
            await this.printJobService.updateJob(job);
            const { metadata, thumbnails } = await this.fileAnalysisService.analyzeFile(filePath);
            let thumbnailMetadata = [];
            if (thumbnails && thumbnails.length > 0) {
                thumbnailMetadata = await this.fileStorageService.saveThumbnails(job.fileStorageId, thumbnails);
                this.logger.log(`Saved ${thumbnailMetadata.length} thumbnail(s) for job ${jobId}`);
            }
            await this.printJobService.handleFileAnalyzed(jobId, metadata, thumbnails);
            const fileHash = job.fileHash || undefined;
            await this.fileStorageService.saveMetadata(job.fileStorageId, metadata, fileHash, job.fileName, thumbnailMetadata);
            this.logger.log(`Successfully re-analyzed job ${jobId}`);
            res.send({
                message: "File re-analyzed successfully",
                jobId,
                status: "analyzed",
                metadata,
                thumbnailCount: thumbnails?.length || 0
            });
        } catch (error) {
            this.logger.error(`Failed to re-analyze job ${jobId}: ${error}`);
            res.status(500).send({
                error: "Re-analysis failed",
                message: error instanceof Error ? error.message : "Unknown error"
            });
        }
    }
    async deleteJob(req, res) {
        const jobId = req.local.id;
        const job = await this.printJobService.getJobByIdOrFail(jobId);
        const deleteFileParam = req.query.deleteFile === 'true';
        if (job.status === "PRINTING" || job.status === "PAUSED") {
            res.status(400).send({
                error: "Cannot delete active print job",
                status: job.status,
                suggestion: "Wait for print to complete or cancel it first"
            });
            return;
        }
        try {
            const fileStorageId = job.fileStorageId;
            const fileName = job.fileName;
            await this.printJobService.deleteJob(job);
            this.logger.log(`Deleted job ${jobId}: ${fileName}`);
            if (fileStorageId && deleteFileParam) {
                const otherJobs = await this.printJobService.countJobsReferencingFile(fileStorageId);
                if (otherJobs === 0) {
                    try {
                        await this.fileStorageService.deleteFile(fileStorageId);
                        this.logger.log(`Deleted file as requested: ${fileStorageId}`);
                        res.send({
                            message: "Job and associated file deleted",
                            jobId,
                            fileDeleted: true
                        });
                    } catch (error) {
                        this.logger.warn(`Failed to delete file ${fileStorageId}: ${error}`);
                        res.send({
                            message: "Job deleted, but file deletion failed",
                            jobId,
                            fileDeleted: false
                        });
                    }
                } else {
                    this.logger.log(`File ${fileStorageId} still referenced by ${otherJobs} other job(s) - keeping file`);
                    res.send({
                        message: "Job deleted (file kept - still used by other jobs)",
                        jobId,
                        fileDeleted: false,
                        remainingReferences: otherJobs
                    });
                }
            } else {
                res.send({
                    message: "Job deleted",
                    jobId,
                    fileDeleted: false
                });
            }
        } catch (error) {
            this.logger.error(`Failed to delete job ${jobId}: ${error}`);
            res.status(500).send({
                error: "Delete failed",
                message: error instanceof Error ? error.message : "Unknown error"
            });
        }
    }
    toEndOfDay(date) {
        const endOfDay = new Date(date);
        endOfDay.setHours(23, 59, 59, 999);
        return endOfDay;
    }
}
_ts_decorate([
    (0, _awilixexpress.GET)(),
    (0, _awilixexpress.route)("/search"),
    _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)
], PrintJobController.prototype, "searchJobs", null);
_ts_decorate([
    (0, _awilixexpress.GET)(),
    (0, _awilixexpress.route)("/search-paged"),
    _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)
], PrintJobController.prototype, "searchJobsPaged", null);
_ts_decorate([
    (0, _awilixexpress.GET)(),
    (0, _awilixexpress.route)("/:id"),
    (0, _awilixexpress.before)([
        (0, _paramconvertermiddleware.ParamId)("id")
    ]),
    _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)
], PrintJobController.prototype, "getJob", null);
_ts_decorate([
    (0, _awilixexpress.POST)(),
    (0, _awilixexpress.route)("/:id/set-completed"),
    (0, _awilixexpress.before)([
        (0, _paramconvertermiddleware.ParamId)("id")
    ]),
    _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)
], PrintJobController.prototype, "setCompleted", null);
_ts_decorate([
    (0, _awilixexpress.POST)(),
    (0, _awilixexpress.route)("/:id/set-failed"),
    (0, _awilixexpress.before)([
        (0, _paramconvertermiddleware.ParamId)("id")
    ]),
    _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)
], PrintJobController.prototype, "setFailed", null);
_ts_decorate([
    (0, _awilixexpress.POST)(),
    (0, _awilixexpress.route)("/:id/set-cancelled"),
    (0, _awilixexpress.before)([
        (0, _paramconvertermiddleware.ParamId)("id")
    ]),
    _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)
], PrintJobController.prototype, "setCancelled", null);
_ts_decorate([
    (0, _awilixexpress.POST)(),
    (0, _awilixexpress.route)("/:id/set-unknown"),
    (0, _awilixexpress.before)([
        (0, _paramconvertermiddleware.ParamId)("id")
    ]),
    _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)
], PrintJobController.prototype, "setUnknown", null);
_ts_decorate([
    (0, _awilixexpress.POST)(),
    (0, _awilixexpress.route)("/:id/re-analyze"),
    (0, _awilixexpress.before)([
        (0, _paramconvertermiddleware.ParamId)("id")
    ]),
    _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)
], PrintJobController.prototype, "reAnalyzeJob", null);
_ts_decorate([
    (0, _awilixexpress.DELETE)(),
    (0, _awilixexpress.route)("/:id"),
    (0, _awilixexpress.before)([
        (0, _paramconvertermiddleware.ParamId)("id")
    ]),
    _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)
], PrintJobController.prototype, "deleteJob", null);
PrintJobController = _ts_decorate([
    (0, _awilixexpress.route)(_serverconstants.AppConstants.apiRoute + "/print-jobs"),
    (0, _awilixexpress.before)([
        (0, _authenticate.authenticate)(),
        (0, _authenticate.authorizeRoles)([
            _authorizationconstants.ROLES.ADMIN
        ])
    ]),
    _ts_metadata("design:type", Function),
    _ts_metadata("design:paramtypes", [
        typeof _loggerfactory.ILoggerFactory === "undefined" ? Object : _loggerfactory.ILoggerFactory,
        typeof _printjobservice.PrintJobService === "undefined" ? Object : _printjobservice.PrintJobService,
        typeof _fileanalysisservice.FileAnalysisService === "undefined" ? Object : _fileanalysisservice.FileAnalysisService,
        typeof _filestorageservice.FileStorageService === "undefined" ? Object : _filestorageservice.FileStorageService
    ])
], PrintJobController);

//# sourceMappingURL=print-job.controller.js.map