"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const body_parser_1 = __importDefault(require("body-parser"));
const config_1 = __importDefault(require("config"));
const express_1 = __importDefault(require("express"));
const BaseService_1 = __importDefault(require("../common/BaseService"));
const Datastore_1 = __importDefault(require("../common/Datastore"));
const Logger_1 = __importStar(require("../common/Logger"));
const ErrorCode_1 = __importDefault(require("./ErrorCode"));
const mongodb_1 = require("mongodb");
class DealReplicationService extends BaseService_1.default {
    constructor() {
        super(Logger_1.Category.DealReplicationService);
        this.app = (0, express_1.default)();
        this.handleCreateReplicationRequest = this.handleCreateReplicationRequest.bind(this);
        this.handleUpdateReplicationRequest = this.handleUpdateReplicationRequest.bind(this);
        this.handleListReplicationRequests = this.handleListReplicationRequests.bind(this);
        this.handleGetReplicationRequest = this.handleGetReplicationRequest.bind(this);
        if (!this.enabled) {
            this.logger.warn('Deal Replication Service is not enabled. Exit now...');
            return;
        }
        this.app.use(Logger_1.default.getExpressLogger(Logger_1.Category.DealReplicationService));
        this.app.use(body_parser_1.default.urlencoded({ extended: false }));
        this.app.use(body_parser_1.default.json());
        this.app.use(function (_req, res, next) {
            res.setHeader('Content-Type', 'application/json');
            next();
        });
        this.app.post('/replication', this.handleCreateReplicationRequest);
        this.app.post('/replication/:id', this.handleUpdateReplicationRequest);
        this.app.get('/replications', this.handleListReplicationRequests);
        this.app.get('/replication/:id', this.handleGetReplicationRequest);
    }
    start() {
        const bind = config_1.default.get('deal_replication_service.bind');
        const port = config_1.default.get('deal_replication_service.port');
        this.app.listen(port, bind, () => {
            this.logger.info(`Deal Replication Service started listening at http://${bind}:${port}`);
        });
    }
    async handleGetReplicationRequest(request, response) {
        const id = request.params['id'];
        if (!mongodb_1.ObjectId.isValid(id)) {
            this.sendError(response, ErrorCode_1.default.INVALID_OBJECT_ID);
            return;
        }
        this.logger.info(`Received request to get details of dataset replication request "${id}".`);
        const found = await Datastore_1.default.ReplicationRequestModel.findById(id);
        if (!found) {
            this.sendError(response, ErrorCode_1.default.DATASET_NOT_FOUND);
            return;
        }
        const result = {
            id: found.id,
            datasetId: found.datasetId,
            replica: found.maxReplicas,
            criteria: found.criteria,
            client: found.client,
            urlPrefix: found.urlPrefix,
            maxPrice: found.maxPrice,
            maxNumberOfDeals: found.maxNumberOfDeals,
            isVerfied: String(found.isVerfied),
            duration: found.duration,
            isOffline: String(found.isOffline),
            status: found.status
        };
        response.end(JSON.stringify(result));
    }
    async handleListReplicationRequests(_request, response) {
        this.logger.info('Received request to list all replication requests.');
        const replicationRequests = await Datastore_1.default.ReplicationRequestModel.find();
        const result = [];
        for (const r of replicationRequests) {
            result.push({
                id: r.id,
                datasetId: r.datasetId,
                replica: r.maxReplicas,
                criteria: r.criteria,
                client: r.client,
                maxNumberOfDeals: r.maxNumberOfDeals,
                status: r.status,
                errorMessage: r.errorMessage,
                replicationTotal: await Datastore_1.default.ReplicationRequestModel.count({ datasetId: r.id }),
                replicationActive: await Datastore_1.default.ReplicationRequestModel.count({ datasetId: r.id, status: 'active' }),
                replicationPaused: await Datastore_1.default.ReplicationRequestModel.count({ datasetId: r.id, status: 'paused' }),
                replicationCompleted: await Datastore_1.default.ReplicationRequestModel.count({ datasetId: r.id, status: 'completed' }),
                replicationError: await Datastore_1.default.ReplicationRequestModel.count({ datasetId: r.id, status: 'error' })
            });
        }
        response.end(JSON.stringify(result));
    }
    async handleUpdateReplicationRequest(request, response) {
        const id = request.params['id'];
        if (!mongodb_1.ObjectId.isValid(id)) {
            this.sendError(response, ErrorCode_1.default.INVALID_OBJECT_ID);
            return;
        }
        const { status } = request.body;
        this.logger.info(`Received request to change status of replication request "${id}" to "${status}".`);
        if (!['active', 'paused'].includes(status)) {
            this.sendError(response, ErrorCode_1.default.CHANGE_STATE_INVALID);
            return;
        }
        const found = await Datastore_1.default.ReplicationRequestModel.findById(id);
        if (!found) {
            this.sendError(response, ErrorCode_1.default.DATASET_NOT_FOUND);
            return;
        }
        await Datastore_1.default.ReplicationRequestModel.updateOne({
            id: id,
            status: {
                $nin: [
                    'completed', 'error'
                ]
            }
        }, {
            status
        });
        this.logger.info(`Updated status of incomplete replication request to "${status}".`);
        response.end();
    }
    sendError(response, error) {
        this.logger.warn(`Error code - ${error}`);
        response.status(400);
        response.end(JSON.stringify({ error }));
    }
    async handleCreateReplicationRequest(request, response) {
        const { datasetId, replica, criteria, client, urlPrefix, maxPrice, isVerfied, duration, isOffline, maxNumberOfDeals } = request.body;
        this.logger.info(`Received request to replicate dataset "${datasetId}" from client "${client}.`);
        let realDatasetId = datasetId;
        const existingSR = await Datastore_1.default.ScanningRequestModel.findOne({
            name: datasetId
        });
        if (existingSR) {
            realDatasetId = existingSR._id.toString();
        }
        // Search GenerationRequest by datasetId, if not even one can be found, immediately return error
        const existingGR = await Datastore_1.default.GenerationRequestModel.findOne({
            datasetId: realDatasetId
        });
        if (existingGR == null) {
            this.logger.error(`Did not find any existing GenerationRequest with datasetId ${realDatasetId}`);
            this.sendError(response, ErrorCode_1.default.DATASET_NOT_FOUND);
            return;
        }
        const replicationRequest = new Datastore_1.default.ReplicationRequestModel();
        replicationRequest.datasetId = realDatasetId;
        replicationRequest.maxReplicas = replica;
        replicationRequest.criteria = criteria;
        replicationRequest.client = client;
        replicationRequest.urlPrefix = urlPrefix;
        replicationRequest.maxPrice = maxPrice;
        replicationRequest.isVerfied = isVerfied === 'true';
        replicationRequest.duration = duration;
        replicationRequest.isOffline = isOffline === 'true';
        replicationRequest.maxNumberOfDeals = maxNumberOfDeals;
        replicationRequest.status = 'active';
        try {
            await replicationRequest.save();
            // Create a deal tracking request if not exist
            await Datastore_1.default.DealTrackingStateModel.updateOne({
                stateType: 'client',
                stateKey: client
            }, {
                $setOnInsert: {
                    stateType: 'client',
                    stateKey: client,
                    stateValue: 'track'
                }
            }, {
                upsert: true
            });
        }
        catch (e) {
            this.logger.error(`MongoSave error`, e);
            this.sendError(response, ErrorCode_1.default.INTERNAL_ERROR);
        }
        response.end(JSON.stringify({ id: replicationRequest.id }));
    }
}
exports.default = DealReplicationService;
//# sourceMappingURL=DealReplicationService.js.map