<?php

namespace WPStaging\Pro\Backup\Task\Tasks\JobImport;

use WPStaging\Framework\Queue\FinishedQueueException;
use WPStaging\Framework\Queue\SeekableQueueInterface;
use WPStaging\Pro\Backup\Dto\StepsDto;
use WPStaging\Pro\Backup\Exceptions\DiskNotWritableException;
use WPStaging\Pro\Backup\Task\ImportTask;
use WPStaging\Vendor\Psr\Log\LoggerInterface;
use WPStaging\Framework\Utils\Cache\Cache;
use WPStaging\Pro\Backup\Service\Extractor;

class ExtractFilesTask extends ImportTask
{
    /** @var Extractor */
    protected $extractorService;

    protected $start;

    public function __construct(Extractor $extractor, LoggerInterface $logger, Cache $cache, StepsDto $stepsDto, SeekableQueueInterface $taskQueue)
    {
        parent::__construct($logger, $cache, $stepsDto, $taskQueue);
        $this->extractorService = $extractor;
    }

    public static function getTaskName()
    {
        return 'backup_restore_extract';
    }

    public static function getTaskTitle()
    {
        return 'Extracting Files';
    }

    public function execute()
    {
        $this->stepsDto->setTotal($this->jobDataDto->getBackupMetadata()->getTotalFiles());

        $this->extractorService->inject($this->jobDataDto, $this->logger);

        $this->start = microtime(true);

        try {
            $this->extractorService->extract();
        } catch (DiskNotWritableException $e) {
            // No-op, just stop execution
        } catch (FinishedQueueException $e) {
            if ($this->jobDataDto->getExtractorFilesExtracted() !== $this->stepsDto->getTotal()) {
                // Unexpected finish. Log the difference and continue.
                $this->logger->warning(sprintf('Expected to find %d files in Backup, but found %d files instead.', $this->stepsDto->getTotal(), $this->jobDataDto->getExtractorFilesExtracted()));
                // Force the completion to avoid a loop.
                $this->jobDataDto->setExtractorFilesExtracted($this->stepsDto->getTotal());
            }
        }

        $this->stepsDto->setCurrent($this->jobDataDto->getExtractorFilesExtracted());

        $this->logger->info(sprintf('Extracted %d/%d files (%s)', $this->stepsDto->getCurrent(), $this->stepsDto->getTotal(), $this->getExtractSpeed()));

        if ($this->stepsDto->isFinished() && $this->jobDataDto->getBackupMetadata()->getIsExportingUploads()) {
            $this->logger->info(__('Restored Media Library', 'wp-staging'));
        }

        return $this->generateResponse(false);
    }

    protected function getExtractSpeed()
    {
        $elapsed = microtime(true) - $this->start;
        $bytesPerSecond = min(10 * GB_IN_BYTES, absint($this->extractorService->getBytesWrittenInThisRequest() / $elapsed));

        if ($bytesPerSecond === 10 * GB_IN_BYTES) {
            return '10GB/s+';
        }

        return size_format($bytesPerSecond) . '/s';
    }
}
