<?php

namespace Smartling\Vendor\Smartling\Tests\Functional;

use DateTime;
use DateTimeZone;
use PHPUnit\Framework\TestCase;
use Smartling\Vendor\Smartling\AuthApi\AuthTokenProvider;
use Smartling\Vendor\Smartling\Exceptions\SmartlingApiException;
use Smartling\Vendor\Smartling\File\FileApi;
use Smartling\Vendor\Smartling\Jobs\JobsApi;
use Smartling\Vendor\Smartling\Jobs\JobStatus;
use Smartling\Vendor\Smartling\Jobs\Params\AddFileToJobParameters;
use Smartling\Vendor\Smartling\Jobs\Params\AddLocaleToJobParameters;
use Smartling\Vendor\Smartling\Jobs\Params\CancelJobParameters;
use Smartling\Vendor\Smartling\Jobs\Params\CreateJobParameters;
use Smartling\Vendor\Smartling\Jobs\Params\ListJobsParameters;
use Smartling\Vendor\Smartling\Jobs\Params\SearchJobsParameters;
use Smartling\Vendor\Smartling\Jobs\Params\UpdateJobParameters;

/**
 * Test class for Jobs API examples.
 */
class JobsApiFunctionalTest extends TestCase
{

    /**
     * @var JobsApi
     */
    private $jobsApi;

    /**
     * @var FileApi
     */
    private $fileApi;

    /**
     * @var string $jobId
     */
    private $jobId = false;

    /**
     * Test mixture.
     */
    public function setUp(): void
    {
        $projectId = \getenv('project_id');
        $userIdentifier = \getenv('user_id');
        $userSecretKey = \getenv('user_key');

        if (
            empty($projectId) ||
            empty($userIdentifier) ||
            empty($userSecretKey)
        ) {
            $this->fail('Missing required parameters');
        }

        $authProvider = AuthTokenProvider::create($userIdentifier, $userSecretKey);
        $this->jobsApi = JobsApi::create($authProvider, $projectId);
        $this->fileApi = FileApi::create($authProvider, $projectId);

        try {
            $this->jobId = $this->createJob();
        } catch (SmartlingApiException $e) {
            $this->fail($e->getMessage());
        }
    }

    public function tearDown(): void
    {
        try {
            $this->cancelJob($this->jobId);
        } catch (SmartlingApiException $e) {
            $this->fail($e->getMessage());
        }
    }

    private function createJob(): string
    {
        $params = new CreateJobParameters();
        $params->setName('Test Job Name ' . \time());
        $params->setDescription('Test Job Description ' . \time());
        $params->setDueDate(DateTime::createFromFormat('Y-m-d H:i:s', '2037-12-31 23:59:59', new DateTimeZone('UTC')));
        $params->setTargetLocales(['es-ES', 'fr-FR']);
        $result = $this->jobsApi->createJob($params);

        $this->assertArrayHasKey('translationJobUid', $result);
        $this->assertArrayHasKey('jobName', $result);
        $this->assertArrayHasKey('targetLocaleIds', $result);
        $this->assertArrayHasKey('description', $result);
        $this->assertArrayHasKey('dueDate', $result);
        $this->assertArrayHasKey('referenceNumber', $result);
        $this->assertArrayHasKey('callbackUrl', $result);
        $this->assertArrayHasKey('callbackMethod', $result);
        $this->assertArrayHasKey('createdDate', $result);
        $this->assertArrayHasKey('modifiedDate', $result);
        $this->assertArrayHasKey('createdByUserUid', $result);
        $this->assertArrayHasKey('modifiedByUserUid', $result);
        $this->assertArrayHasKey('firstCompletedDate', $result);
        $this->assertArrayHasKey('lastCompletedDate', $result);
        $this->assertArrayHasKey('jobStatus', $result);

        return $result['translationJobUid'];
    }

    /**
     * Cancel job.
     *
     * @param string $jobId
     */
    private function cancelJob($jobId)
    {
        $params = new CancelJobParameters();
        $params->setReason('Some reason to cancel');
        $this->jobsApi->cancelJobSync($jobId, $params);
    }

    /**
     * Test for job list.
     */
    public function testJobsApiListJobs()
    {
        try {
            $params = new ListJobsParameters();
            $params->setStatuses([
                JobStatus::AWAITING_AUTHORIZATION,
                JobStatus::IN_PROGRESS,
            ]);
            $result = $this->jobsApi->listJobs($params);

            $this->assertArrayHasKey('totalCount', $result);
            $this->assertArrayHasKey('items', $result);
        } catch (SmartlingApiException $e) {
            $this->fail($e->getMessage());
        }
    }

    /**
     * Test for job update.
     */
    public function testJobsApiUpdateJob()
    {
        try {
            $params = new UpdateJobParameters();
            $params->setName("Test Job Name Updated " . \time());
            $params->setDescription("Test Job Description Updated " . \time());
            $params->setDueDate(DateTime::createFromFormat('Y-m-d H:i:s', '2030-01-01 19:19:17',
                new DateTimeZone('UTC')));
            $result = $this->jobsApi->updateJob($this->jobId, $params);

            $this->assertArrayHasKey('translationJobUid', $result);
            $this->assertArrayHasKey('jobName', $result);
            $this->assertArrayHasKey('targetLocaleIds', $result);
            $this->assertArrayHasKey('description', $result);
            $this->assertArrayHasKey('dueDate', $result);
            $this->assertArrayHasKey('referenceNumber', $result);
            $this->assertArrayHasKey('callbackUrl', $result);
            $this->assertArrayHasKey('callbackMethod', $result);
            $this->assertArrayHasKey('createdDate', $result);
            $this->assertArrayHasKey('modifiedDate', $result);
            $this->assertArrayHasKey('createdByUserUid', $result);
            $this->assertArrayHasKey('modifiedByUserUid', $result);
            $this->assertArrayHasKey('firstCompletedDate', $result);
            $this->assertArrayHasKey('lastCompletedDate', $result);
            $this->assertArrayHasKey('jobStatus', $result);
            $this->assertArrayHasKey('sourceFiles', $result);
        } catch (SmartlingApiException $e) {
            $this->fail($e->getMessage());
        }
    }

    /**
     * Test for job get.
     */
    public function testJobsApiGetJob()
    {
        try {
            $result = $this->jobsApi->getJob($this->jobId);

            $this->assertArrayHasKey('translationJobUid', $result);
            $this->assertArrayHasKey('jobName', $result);
            $this->assertArrayHasKey('targetLocaleIds', $result);
            $this->assertArrayHasKey('description', $result);
            $this->assertArrayHasKey('dueDate', $result);
            $this->assertArrayHasKey('referenceNumber', $result);
            $this->assertArrayHasKey('callbackUrl', $result);
            $this->assertArrayHasKey('callbackMethod', $result);
            $this->assertArrayHasKey('createdDate', $result);
            $this->assertArrayHasKey('modifiedDate', $result);
            $this->assertArrayHasKey('createdByUserUid', $result);
            $this->assertArrayHasKey('modifiedByUserUid', $result);
            $this->assertArrayHasKey('firstCompletedDate', $result);
            $this->assertArrayHasKey('lastCompletedDate', $result);
            $this->assertArrayHasKey('jobStatus', $result);
            $this->assertArrayHasKey('sourceFiles', $result);
        } catch (SmartlingApiException $e) {
            $this->fail($e->getMessage());
        }
    }

    /**
     * Test for add file to job get.
     */
    public function testJobsApiAddFileToJob()
    {
        try {
            $this->fileApi->uploadFile('tests/resources/test.xml', 'test.xml', 'xml');
            $params = new AddFileToJobParameters();
            $params->setFileUri('test.xml');
            $this->jobsApi->addFileToJobSync($this->jobId, $params);
            $this->fileApi->deleteFile('test.xml');
        } catch (SmartlingApiException $e) {
            $this->fail($e->getMessage());
        }
    }

    /**
     * Test for jobs search.
     */
    public function testJobsApiSearchJob()
    {
        try {
            $searchParameters = new SearchJobsParameters();
            $searchParameters->setFileUris([
                'some_file_to_search.xml',
            ]);
            $result = $this->jobsApi->searchJobs($searchParameters);

            $this->assertArrayHasKey('totalCount', $result);
            $this->assertArrayHasKey('items', $result);
        } catch (SmartlingApiException $e) {
            $this->fail($e->getMessage());
        }
    }

    /**
     * Test for job authorize.
     */
    public function testJobsApiAuthorizeJob()
    {
        try {
            $this->fileApi->uploadFile('tests/resources/test.xml', 'test.xml', 'xml');
            $params = new AddFileToJobParameters();
            $params->setFileUri('test.xml');
            $this->jobsApi->addFileToJobSync($this->jobId, $params);
            $this->jobsApi->authorizeJob($this->jobId);
            $this->fileApi->deleteFile('test.xml');
        } catch (SmartlingApiException $e) {
            $this->fail($e->getMessage());
        }
    }

    /**
     * Test for add locale to job get.
     */
    public function testJobsApiAddLocaleToJob()
    {
        try {
            $params = new AddLocaleToJobParameters();
            $params->setSyncContent(false);
            $this->jobsApi->addLocaleToJobSync($this->jobId, 'fr-FR', $params);
        } catch (SmartlingApiException $e) {
            $this->fail($e->getMessage());
        }
    }

    /**
     * Test checks status of async process.
     */
    public function testJobsApiCheckAsynchronousProcessingStatus()
    {
        try {
            $this->fileApi->uploadFile('tests/resources/test.xml', 'test.xml', 'xml');

            $params = new AddLocaleToJobParameters();
            $params->setSyncContent(false);
            $this->jobsApi->addLocaleToJobSync($this->jobId, 'fr-FR', $params);

            $params = new AddFileToJobParameters();
            $params->setTargetLocales(['fr-FR']);
            $params->setFileUri('test.xml');
            $this->jobsApi->addFileToJobSync($this->jobId, $params);

            $params = new AddLocaleToJobParameters();
            $params->setSyncContent(true);
            $this->jobsApi->addLocaleToJobSync($this->jobId, 'de-DE', $params);

            $this->fileApi->deleteFile('test.xml');
        } catch (SmartlingApiException $e) {
            $this->fail($e->getMessage());
        }
    }

}
