<?php

namespace tad\WPBrowser\Services\WP;

use tad\WPBrowser\Environment\System;

/**
 * Class Bootstrapper
 *
 * Bootstraps WordPress from wp-load file and executes requests on it.
 *
 * @package tad\WPBrowser\Services\WP
 */
class Bootstrapper
{

    /**
     * @var string
     */
    protected $bootstrapScriptFilePath;

    /**
     * @var string|null
     */
    private $wpLoadPath;

    /**
     * @var System
     */
    private $system;

    /**
     * Bootstrapper constructor.
     *
     * @param string      $wpLoadPath The path to the WordPress root directory to load.
     * @param System|null $system The system operations adapter.
     */
    public function __construct($wpLoadPath = null, System $system = null)
    {
        $this->wpLoadPath = $wpLoadPath;
        $this->bootstrapScriptFilePath = dirname(dirname(__DIR__)) . '/support/wpBootstrap.php';
        $this->system = $system ? $system : new System();
    }

    /**
     * Generates a nonce for an action for a user.
     *
     * @param string              $action      The action to generate the nonce for.
     * @param array<string,mixed> $credentials An array of credentials and cookies; usually generated by a login method.
     *
     * @return string|false Either the generated nonce, or `false` on failure.
     */
    public function createNonce($action, array $credentials)
    {
        $request = [
            'action' => $action,
            'credentials' => [
                'user_login' => $credentials['username'],
                'user_password' => $credentials['password'],
                'remember' => true
            ],
            'cookies' => [
                $credentials['authCookie']->getName() => $credentials['authCookie']->getValue(),
                $credentials['loginCookie']->getName() => $credentials['loginCookie']->getValue()
            ]
        ];

        $output = $this->bootstrapWpAndExec($request);

        return !empty($output) ? $output : false;
    }

    /**
     * Bootstraps WordPress and executes some actions.
     *
     * @param array<string,mixed> $actions The array of actions to execute.
     *
     * @return string|false Either the last line of the bootstrap output, or `false` on failure.
     *
     * @throws \RuntimeException If the bootstrap happens before the load path is set.
     */
    public function bootstrapWpAndExec(array $actions)
    {
        if (empty($this->wpLoadPath)) {
            throw new \RuntimeException('Cannot bootstrap WordPress if load path is not set.');
        }

        $command = implode(' ', [
            PHP_BINARY,
            escapeshellarg($this->bootstrapScriptFilePath),
            escapeshellarg($this->wpLoadPath),
            escapeshellarg(serialize($actions))
        ]);

        return $this->system->system($command);
    }

    /**
     * Returns the path to the WordPress directory to load.
     *
     * @return string|null The current path to the WordPress directory to load.
     */
    public function getWpLoadPath()
    {
        return $this->wpLoadPath;
    }

    /**
     * Sets the path to the WordPress directory to load.
     *
     * @param string $wpLoadPath The path to the WordPress directory to load.
     *
     * @return void
     */
    public function setWpLoadPath($wpLoadPath)
    {
        $this->wpLoadPath = $wpLoadPath;
    }

    /**
     * Returns the path to the bootstrap file.
     *
     * @return string The path to the bootstrap file to use.
     */
    public function getBootstrapScriptFilePath()
    {
        return $this->bootstrapScriptFilePath;
    }

    /**
     * Sets the path to the bootstrap file to use.
     *
     * @param string $bootsrapScriptFilePath The bootstrap file path.
     *
     * @return void
     */
    public function setBootstrapScriptFilePath($bootsrapScriptFilePath)
    {
        $this->bootstrapScriptFilePath = $bootsrapScriptFilePath;
    }
}
