"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = require("fs");
const uuid_1 = require("uuid");
const vcs_uploading_interface_1 = require("../../interfaces/vcs-uploading.interface");
const https = require("https");
const urlJoin = require("url-join");
const SecureRequest_1 = require("../../modules/SecureRequest");
const versionControllHelpers_1 = require("../../utils/versionControllHelpers");
const routes_1 = require("./routes");
const socketManager_1 = require("./socketManager");
const jsonwebtoken_1 = require("jsonwebtoken");
function replaceParams(url, params) {
    return Object.entries(params)
        .reduce((resUrl, [key, value]) => resUrl.replace(`{${key}}`, value), url);
}
class ContentClient {
    constructor(apiUrl, tokenHandler, keyCloackClient) {
        this.apiUrl = apiUrl;
        this.tokenHandler = tokenHandler;
        this.keyCloackClient = keyCloackClient;
        this.request = new SecureRequest_1.default(this.tokenHandler, this.keyCloackClient);
        this.tokenHandler = this.tokenHandler;
        this.correlationId = null;
    }
    get(params) {
        return __awaiter(this, void 0, void 0, function* () {
            const endpoint = this.apiUrl + replaceParams(routes_1.default.get, params);
            const { data } = yield this.request.get(endpoint);
            return data;
        });
    }
    getByVersion(params) {
        return __awaiter(this, void 0, void 0, function* () {
            const endpoint = this.apiUrl + replaceParams(routes_1.default.getByVersion, params);
            const { data } = yield this.request.get(endpoint);
            return data;
        });
    }
    getDownloadLink(id) {
        return __awaiter(this, void 0, void 0, function* () {
            const endpoint = this.apiUrl + routes_1.default.downloadLink.replace('{id}', id);
            return yield this.request.get(endpoint);
        });
    }
    upload(filePath, id, onProgressCallback) {
        return __awaiter(this, void 0, void 0, function* () {
            this.setCorrelationId();
            const tokens = yield this.tokenHandler.get();
            const fileSize = (0, fs_1.statSync)(filePath).size;
            const FormData = require('form-data');
            const form = new FormData();
            let uploaded = 0;
            let uploadProgress = 0;
            form.append('package', (0, fs_1.createReadStream)(filePath));
            form.append('correlation_id', this.correlationId);
            form.on('data', (data) => {
                uploaded += data.length;
                uploadProgress = Math.round(uploaded / fileSize * 100) * 0.7;
                if (onProgressCallback) {
                    onProgressCallback(uploadProgress);
                }
            });
            const uploadRoute = id ? routes_1.default.uploadNewVersion.replace('{id}', id) : routes_1.default.createNew;
            const { origin, pathname } = (0, versionControllHelpers_1.parseService)(this.apiUrl);
            return new Promise((resolve, reject) => {
                const request = https.request({
                    method: 'post',
                    host: origin.replace('https://', ''),
                    path: urlJoin(pathname, uploadRoute),
                    headers: Object.assign(Object.assign({}, form.getHeaders()), { Authorization: `Bearer ${tokens.access_token}` }),
                });
                form.pipe(request);
                request.on('response', (response) => {
                    let data = '';
                    if (response.statusCode >= 370) {
                        request.destroy();
                        return reject({ code: response.statusCode });
                    }
                    response.on('data', (chunk) => {
                        data += chunk;
                    });
                    response.on('end', () => {
                        const responseBody = JSON.parse(data);
                        request.destroy();
                        if (responseBody.error)
                            reject(responseBody.error);
                        else
                            resolve(responseBody);
                    });
                });
            });
        });
    }
    establishConnection() {
        return __awaiter(this, void 0, void 0, function* () {
            const token = yield this.tokenHandler.get();
            const { origin, pathname } = (0, versionControllHelpers_1.parseService)(this.apiUrl);
            const namespace = '/contentprogress';
            return (0, socketManager_1.getConnection)({ namespace, domain: origin }, {
                path: `${pathname}/api/socket.io`,
                auth: { token: `Bearer ${token.access_token}` },
            });
        });
    }
    startTrackSocketsProgress(connection, onProgressCallback) {
        return __awaiter(this, void 0, void 0, function* () {
            const token = yield this.tokenHandler.get();
            const { account_id } = (0, jsonwebtoken_1.decode)(token.access_token);
            return new Promise((resolve, reject) => {
                connection
                    .on('connect', () => {
                    connection.emit('room', account_id);
                    connection.on('bundleUpdated', this.getOnBundleUpdated(connection, resolve, reject, onProgressCallback));
                })
                    .on('connect_error', (err) => {
                    connection.close();
                    return reject(err);
                });
            });
        });
    }
    setCorrelationId() {
        this.correlationId = `${(0, uuid_1.v4)()}.${(0, uuid_1.v4)()}`;
    }
    getOnBundleUpdated(connection, resolve, reject, onProgressCallback) {
        return (item) => {
            if (item.correlation_id === this.correlationId) {
                try {
                    if (onProgressCallback) {
                        onProgressCallback(item.progress);
                    }
                    if ([vcs_uploading_interface_1.ContentProgressStatuses.UPDATED, vcs_uploading_interface_1.ContentProgressStatuses.CREATED].includes(item.upload_status)) {
                        connection.close();
                        resolve(item);
                    }
                    else if (item.upload_status === vcs_uploading_interface_1.ContentProgressStatuses.FAILED) {
                        reject(item.error_message);
                    }
                }
                catch (e) {
                    return reject(e);
                }
            }
        };
    }
}
exports.default = ContentClient;
//# sourceMappingURL=contentClient.js.map