<?php

namespace WPStaging\Framework\Job\Ajax;

use WPStaging\Core\WPStaging;
use WPStaging\Framework\Adapter\Directory;
use WPStaging\Framework\Filesystem\Filesystem;
use WPStaging\Framework\Job\ProcessLock;
use WPStaging\Framework\Logger\SseEventCache;
use WPStaging\Framework\Security\Auth;

abstract class PrepareJob
{
    /** @var Auth */
    protected $auth;

    /** @var Filesystem */
    protected $filesystem;

    /** @var Directory */
    protected $directory;

    /** @var ProcessLock */
    protected $processLock;

    /** @var string */
    protected $queueId = '';

    public function __construct(Filesystem $filesystem, Directory $directory, Auth $auth, ProcessLock $processLock)
    {
        $this->directory   = $directory;
        $this->filesystem  = $filesystem;
        $this->auth        = $auth;
        $this->processLock = $processLock;
    }

    abstract public function prepare($data = null);

    abstract public function ajaxPrepare($data);

    abstract public function persist(): bool;

    abstract public function getJob();

    abstract public function validateAndSanitizeData($data): array;

    /**
     * Template method that runs the subclass-defined `setupInitialData` and
     * then persists the resulting job state.
     *
     * Persist synchronously instead of relying on the WP `shutdown` hook. On
     * some hosts (aggressive request termination, Object Cache Pro drop-in
     * ordering, plugins that die() earlier in shutdown) the hook never fires
     * and the init=true DTO never reaches disk, so the next processing
     * request sees an empty DTO. An explicit persist here guarantees the
     * freshly-hydrated state is written before we respond.
     *
     * @param mixed ...$args Forwarded verbatim to `setupInitialData` so
     *                       subclasses with extra parameters (e.g. PreparePush)
     *                       keep working unchanged.
     * @return array
     * @throws \Exception Propagated from `setupInitialData`; persist does not
     *                    run when setup throws.
     */
    protected function setupInitialJob(...$args): array
    {
        $sanitizedData = $this->setupInitialData(...$args);
        $this->persist();

        return $sanitizedData;
    }

    protected function clearCacheFolder()
    {
        $this->filesystem->setExcludePaths(['*.*', '!*.cache.php', '!*.cache', '!*.wpstg']);
        $this->filesystem->delete($this->directory->getCacheDirectory(), $deleteSelf = false);
        $this->filesystem->setExcludePaths([]);
        $this->filesystem->mkdir($this->directory->getCacheDirectory(), true);
    }

    /**
     * @return void
     */
    protected function deleteSseCacheFiles()
    {
        /** @var SseEventCache */
        $sseCacheEvents = WPStaging::make(SseEventCache::class);
        $sseCacheEvents->deleteSseCacheFiles();
    }

    public function setQueueId(string $queueId)
    {
        $this->queueId = $queueId;
    }

    /**
     * @param mixed $value A value that we want to detect if it's true or false.
     *
     * @return bool A PHP boolean interpretation of this value.
     */
    protected function jsBoolean($value)
    {
        return $value === 'true' || $value === true;
    }

    /**
     * @param array|null $sanitizedData
     * @return array
     */
    abstract protected function setupInitialData($sanitizedData): array;
}
