"use strict";
var __decorate = (this && this.__decorate) || function (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;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const temp = require("temp");
const constants_1 = require("../constants");
const helpers_1 = require("../common/helpers");
const decorators_1 = require("../common/decorators");
class ITMSTransporterService {
    constructor($applePortalApplicationService, $childProcess, $errors, $fs, $injector, $logger, $plistParser, $xcodeSelectService) {
        this.$applePortalApplicationService = $applePortalApplicationService;
        this.$childProcess = $childProcess;
        this.$errors = $errors;
        this.$fs = $fs;
        this.$injector = $injector;
        this.$logger = $logger;
        this.$plistParser = $plistParser;
        this.$xcodeSelectService = $xcodeSelectService;
    }
    get $projectData() {
        return this.$injector.resolve("projectData");
    }
    upload(data) {
        return __awaiter(this, void 0, void 0, function* () {
            temp.track();
            const itmsTransporterPath = yield this.getITMSTransporterPath();
            const ipaFileName = "app.ipa";
            const itmsDirectory = temp.mkdirSync("itms-");
            const innerDirectory = path.join(itmsDirectory, "mybundle.itmsp");
            const ipaFileLocation = path.join(innerDirectory, ipaFileName);
            const loggingLevel = data.verboseLogging ? constants_1.ITMSConstants.VerboseLoggingLevels.Verbose : constants_1.ITMSConstants.VerboseLoggingLevels.Informational;
            const bundleId = yield this.getBundleIdentifier(data);
            const application = yield this.$applePortalApplicationService.getApplicationByBundleId(data, bundleId);
            this.$fs.createDirectory(innerDirectory);
            this.$fs.copyFile(data.ipaFilePath, ipaFileLocation);
            const ipaFileHash = yield this.$fs.getFileShasum(ipaFileLocation, { algorithm: "md5" });
            const ipaFileSize = this.$fs.getFileSize(ipaFileLocation);
            const metadata = this.getITMSMetadataXml(application.adamId, ipaFileName, ipaFileHash, ipaFileSize);
            this.$fs.writeFile(path.join(innerDirectory, constants_1.ITMSConstants.ApplicationMetadataFile), metadata);
            yield this.$childProcess.spawnFromEvent(itmsTransporterPath, ["-m", "upload", "-f", itmsDirectory, "-u", helpers_1.quoteString(data.username), "-p", helpers_1.quoteString(data.password), "-v", loggingLevel], "close", { stdio: "inherit" });
        });
    }
    getBundleIdentifier(data) {
        return __awaiter(this, void 0, void 0, function* () {
            const { shouldExtractIpa, ipaFilePath } = data;
            if (shouldExtractIpa) {
                if (!this.$fs.exists(ipaFilePath) || path.extname(ipaFilePath) !== ".ipa") {
                    this.$errors.failWithoutHelp(`Cannot use specified ipa file ${ipaFilePath}. File either does not exist or is not an ipa file.`);
                }
                this.$logger.trace("--ipa set - extracting .ipa file to get app's bundle identifier");
                temp.track();
                const destinationDir = temp.mkdirSync("ipa-");
                yield this.$fs.unzip(ipaFilePath, destinationDir);
                const payloadDir = path.join(destinationDir, "Payload");
                let allFiles = this.$fs.readDirectory(payloadDir);
                this.$logger.debug("ITMSTransporter .ipa Payload files:");
                allFiles.forEach(f => this.$logger.debug(" - " + f));
                allFiles = allFiles.filter(f => path.extname(f).toLowerCase() === ".app");
                if (allFiles.length > 1) {
                    this.$errors.failWithoutHelp("In the .ipa the ITMSTransporter is uploading there is more than one .app file. We don't know which one to upload.");
                }
                else if (allFiles.length <= 0) {
                    this.$errors.failWithoutHelp("In the .ipa the ITMSTransporter is uploading there must be at least one .app file.");
                }
                const appFile = path.join(payloadDir, allFiles[0]);
                const plistObject = yield this.$plistParser.parseFile(path.join(appFile, constants_1.INFO_PLIST_FILE_NAME));
                const bundleId = plistObject && plistObject.CFBundleIdentifier;
                if (!bundleId) {
                    this.$errors.failWithoutHelp(`Unable to determine bundle identifier from ${ipaFilePath}.`);
                }
                this.$logger.trace(`bundle identifier determined to be ${bundleId}`);
                return bundleId;
            }
            return this.$projectData.projectIdentifiers.ios;
        });
    }
    getITMSTransporterPath() {
        return __awaiter(this, void 0, void 0, function* () {
            const xcodePath = yield this.$xcodeSelectService.getContentsDirectoryPath();
            const loaderAppContentsPath = path.join(xcodePath, "Applications", "Application Loader.app", "Contents");
            const itmsTransporterPath = path.join(loaderAppContentsPath, constants_1.ITMSConstants.iTMSDirectoryName, "bin", constants_1.ITMSConstants.iTMSExecutableName);
            if (!this.$fs.exists(itmsTransporterPath)) {
                this.$errors.failWithoutHelp('iTMS Transporter not found on this machine - make sure your Xcode installation is not damaged.');
            }
            return itmsTransporterPath;
        });
    }
    getITMSMetadataXml(appleId, ipaFileName, ipaFileHash, ipaFileSize) {
        return `<?xml version="1.0" encoding="UTF-8"?>
<package version="software4.7" xmlns="http://apple.com/itunes/importer">
    <software_assets apple_id="${appleId}">
        <asset type="bundle">
            <data_file>
                <file_name>${ipaFileName}</file_name>
                <checksum type="md5">${ipaFileHash}</checksum>
                <size>${ipaFileSize}</size>
            </data_file>
        </asset>
    </software_assets>
</package>`;
    }
}
__decorate([
    decorators_1.cache()
], ITMSTransporterService.prototype, "getITMSTransporterPath", null);
exports.ITMSTransporterService = ITMSTransporterService;
$injector.register("itmsTransporterService", ITMSTransporterService);
