<?php
// Copyright 1999-2017. Plesk International GmbH. All rights reserved.

namespace Plesk\MigrationLibV8\MailImport\Backend;

use Plesk\MigrationLibV8\Common\Exception\NonZeroExitCode;
use Plesk\MigrationLibV8\MailImport\Backend\Files\Config;

/**
 * Wrapper around "plesk-migrator" utility (which is backend entry point) for mail import.
 */
class Tool
{
    /**
     * Mail migration: schedule mail migration tasks.
     * Once the tasks are scheduled, start them with 'runSiteMigrationTasks' function.
     *
     * @param Config $config
     * @param string $migrationListFile full path to file with migration list
     * @param bool $isAsyncStatusReport
     * @return string ID of the task scheduled for the last mail address pair in the specified migration list
     */
    public function addMailMigrationTasks(
        Config $config, $migrationListFile, $isAsyncStatusReport
    ) {
        $command = 'add-mail-migration-tasks';
        $args = [
            "--mail-migration-list=$migrationListFile",
        ];
        if ($isAsyncStatusReport) {
            $args[] = '--async-status-report';
        }
        $args[] = '--quiet';
        $stdout = $this->_exec($command, $args, $config);
        $taskInfo = json_decode(trim($stdout), true);
        return $taskInfo['task_id'];
    }

    /**
     * Mail migration: cancel mail migration tasks related to mail address pairs specified by migration list.
     *
     * @param Files\Config $config
     * @param string $migrationListFile full path to file with migration list
     */
    public function cancelMailMigrationTasks(
        Config $config, $migrationListFile
    ) {
        $command = 'cancel-mail-migration-tasks';
        $args = [
            "--mail-migration-list=$migrationListFile",
        ];
        $this->_exec($command, $args, $config);
    }

    /**
     * Mail migration: run previously scheduled mail migration tasks.
     * Schedule site migration tasks with 'addMailMigrationTasks' function.
     *
     * On Unix this function returns once the task runner was started (asynchronously).
     * On Windows this function returns only once the task runner was finished (synchronously).
     * The difference is caused by difficulties implementing asynchronous command execution on Windows.
     *
     * @param Config $config
     */
    public function runMailMigrationTasks(Config $config)
    {
        // Start task queue runner for mail migration.
        // If it is already running, this call will simply do nothing -
        // "run-mail-migration-tasks" will exit immediately.
        $this->_exec('run-mail-migration-tasks', ['--async'], $config);
    }

    /**
     * Execute backend action for mail migration.
     *
     * Backend for mail migration runs under superuser (root on Linux, SYSTEM on Windows)
     * with Plesk 17.0 SDK features, which are not available on Plesk 12.5. No Administrator password is
     * required on Windows comparing to regular migration, so mail migration could be launched by customer,
     * not only by server administrator.
     *
     * @param string $action
     * @param string[] $args
     * @param Config $config
     * @return mixed
     * @throws \Exception
     */
    private function _exec($action, $args, Config $config=null)
    {
        // Execute the backend under superuser
        $params = [$action];
        if (!is_null($config)) {
            $params[] = $config->getPath();
        }
        $params = array_merge($params, $args);

        if (\pm_ProductInfo::isWindows()) {
            $sbinExecutable = 'plesk-migrator.bat';
        } else {
            $sbinExecutable = 'plesk-migrator';
        }

        $result = \pm_ApiCli::callSbin($sbinExecutable, $params, \pm_ApiCli::RESULT_FULL, []);
        if ($result['code'] !== 0) {
            $commandParts = ['plesk-migrator'];
            $commandParts = array_merge($commandParts, $params);
            foreach ($commandParts as &$commandPart) {
                $commandPart = escapeshellarg($commandPart);
            }

            throw new NonZeroExitCode(
                implode(" ", $commandParts), $result['code'], $result['stdout'], $result['stderr']
            );
        }
        return $result['stdout'];
    }
}
