"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../utils/types");
const OcrDriverBase_1 = require("../OcrDriverBase");
const Logger_1 = require("@joplin/utils/Logger");
const types_2 = require("../../database/types");
const KvStore_1 = require("../../KvStore");
const shim_1 = require("../../../shim");
const time_1 = require("@joplin/utils/time");
const Resource_1 = require("../../../models/Resource");
const registry_1 = require("../../../registry");
const logger = Logger_1.default.create('OcrDriverTranscribe');
class OcrDriverTranscribe extends OcrDriverBase_1.default {
    constructor(interval) {
        super();
        this.retryIntervals_ = [10 * 1000, 15 * 1000, 30 * 1000, 60 * 1000];
        this.jobIdKeyPrefix_ = 'OcrDriverTranscribe::JobId::';
        this.disposed_ = false;
        this.retryIntervals_ = interval !== null && interval !== void 0 ? interval : this.retryIntervals_;
    }
    get driverId() {
        return types_2.ResourceOcrDriverId.HandwrittenText;
    }
    async recognize(_language, filePath, resourceId) {
        logger.info(`${resourceId}: Starting to recognize resource from ${filePath}`);
        const key = `${this.jobIdKeyPrefix_}${resourceId}`;
        const storedJobId = await KvStore_1.default.instance().value(key);
        let jobId = typeof storedJobId === 'string' ? storedJobId : null;
        try {
            if (!jobId) {
                await Resource_1.default.save({
                    id: resourceId,
                    ocr_status: types_2.ResourceOcrStatus.Processing,
                });
                logger.info(`${resourceId}: Job does not exist yet, creating...`);
                jobId = await this.queueJob(filePath, resourceId);
                logger.info(`${resourceId}: Job created, reference: ${jobId}`);
                await KvStore_1.default.instance().setValue(key, jobId);
            }
            const ocrResult = await this.checkJobIsFinished(jobId, resourceId);
            await KvStore_1.default.instance().deleteValue(key);
            return Object.assign(Object.assign({}, (0, types_1.emptyRecognizeResult)()), ocrResult);
        }
        catch (error) {
            if (shim_1.default.fetchRequestCanBeRetried(error) || error.code === 503) {
                return (0, types_1.emptyRecognizeResult)();
            }
            await KvStore_1.default.instance().deleteValue(key);
            return Object.assign(Object.assign({}, (0, types_1.emptyRecognizeResult)()), { ocr_status: types_2.ResourceOcrStatus.Error, ocr_error: error.message });
        }
    }
    async queueJob(filePath, resourceId) {
        const api = await this.api();
        const result = await api.exec('POST', 'api/transcribe', null, null, {
            'Content-Type': 'application/octet-stream',
        }, { path: filePath, source: 'file' });
        logger.info(`${resourceId}: Job queued`);
        return result.jobId;
    }
    async checkJobIsFinished(jobId, resourceId) {
        logger.info(`${resourceId}: Checking if job is finished...`);
        let i = 0;
        while (true) {
            if (this.disposed_)
                break;
            const api = await this.api();
            const response = await api.exec('GET', `api/transcribe/${jobId}`);
            if (this.disposed_)
                break;
            if (response.state === 'completed') {
                logger.info(`${resourceId}: Finished.`);
                return {
                    ocr_status: types_2.ResourceOcrStatus.Done,
                    ocr_text: response.output.result,
                };
            }
            else if (response.state === 'failed') {
                logger.info(`${resourceId}: Failed.`);
                return {
                    ocr_status: types_2.ResourceOcrStatus.Error,
                    ocr_error: response.output,
                };
            }
            logger.info(`${resourceId}: Job not finished yet, waiting... ${this.getInterval(i)}`);
            await (0, time_1.msleep)(this.getInterval(i));
            i += 1;
        }
        return {
            ocr_status: types_2.ResourceOcrStatus.Error,
            ocr_error: 'OcrDriverTranscribe was stopped while waiting for a transcription',
        };
    }
    getInterval(index) {
        if (index >= this.retryIntervals_.length) {
            return this.retryIntervals_[this.retryIntervals_.length - 1];
        }
        return this.retryIntervals_[index];
    }
    async api() {
        const fileApi = await registry_1.reg.syncTarget().fileApi();
        return fileApi.driver().api();
    }
    dispose() {
        this.disposed_ = true;
        return Promise.resolve();
    }
}
exports.default = OcrDriverTranscribe;
//# sourceMappingURL=OcrDriverTranscribe.js.map