<?php
namespace DevOwl\RealPhysicalMedia;

use DevOwl\RealPhysicalMedia\base\Core as BaseCore;
use DevOwl\RealPhysicalMedia\configuration\ExcludeFolder;
use DevOwl\RealPhysicalMedia\configuration\Lockfile;
use DevOwl\RealPhysicalMedia\configuration\MetaSupText;
use DevOwl\RealPhysicalMedia\configuration\Options;
use DevOwl\RealPhysicalMedia\configuration\SkipToFirstShortcut;
use DevOwl\RealPhysicalMedia\handler\Handler as HandlerHandler;
use DevOwl\RealPhysicalMedia\listener\FolderListener;
use DevOwl\RealPhysicalMedia\listener\Listener;
use DevOwl\RealPhysicalMedia\misc\Seo as MiscSeo;
use DevOwl\RealPhysicalMedia\misc\SpecialCharacters;
use DevOwl\RealPhysicalMedia\misc\UploadDir;
use DevOwl\RealPhysicalMedia\misc\WpPosts;
use DevOwl\RealPhysicalMedia\queue\Queue as QueueQueue;
use DevOwl\RealPhysicalMedia\rest\Handler;
use DevOwl\RealPhysicalMedia\rest\Queue;
use DevOwl\RealPhysicalMedia\rest\Seo;
use DevOwl\RealPhysicalMedia\rest\Service;
use DevOwl\RealPhysicalMedia\view\AdminBar;
use DevOwl\RealPhysicalMedia\view\CustomField;
use MatthiasWeb\Utils\Service as UtilsService;
use MatthiasWeb\Utils\ServiceNoStore;

// @codeCoverageIgnoreStart
defined('ABSPATH') or die('No script kiddies please!'); // Avoid direct file request
// @codeCoverageIgnoreEnd

/**
 * Singleton core class which handles the main system for plugin. It includes
 * registering of the autoload, all hooks (actions & filters) (see BaseCore class).
 */
class Core extends BaseCore {
    /**
     * Singleton instance.
     */
    private static $me;

    /**
     * See RpmInitiator.
     *
     * @var RpmInitiator
     */
    private $rpmInitiator;

    /**
     * Application core constructor.
     */
    protected function __construct() {
        parent::__construct();

        // Enable `no-store` for our relevant WP REST API endpoints
        ServiceNoStore::hook('/' . UtilsService::getNamespace($this));

        Localization::enableAssetsDotDevowlIoLanguagePacksDownload(RPM_SLUG);

        // Register all your before init hooks here.
        // Note: At this point isn't sure if RML is installed and the min version is reached.
        // It is not recommend to use UtilsProvider::isRMLVersionReached() here, you should use it in
        // all your hook implementations.
        add_action('RML/Activate', [$this->getActivator(), 'rmlActivate']);

        // We need to listen to `wp` hook cause e.g. RankMath does a redirection here, too
        add_action('wp', [MiscSeo::getInstance(), 'template_redirect'], 1);

        Options::getInstance()->uploads_use_yearmonth_folders();

        $this->rpmInitiator = new RpmInitiator();
        $this->rpmInitiator->start();

        (new AdInitiator())->start();
    }

    /**
     * The init function is fired even the init hook of WordPress. If possible
     * it should register all hooks to have them in one place.
     */
    public function init() {
        // Check if min Real Media Library version is reached...
        if (!$this->isRMLVersionReached()) {
            require_once RPM_INC . 'base/others/fallback-rml.php';
            return;
        }

        // Check if free add-on is used
        if (class_exists('upload_dir_real_media_library')) {
            require_once RPM_INC . 'base/others/fallback-freeaddon.php';
            return;
        }

        $folderListener = FolderListener::getInstance();
        $listener = Listener::getInstance();
        $handler = HandlerHandler::getInstance();

        // Register all your hooks here
        add_action('rest_api_init', [Seo::instance(), 'rest_api_init']);
        add_action('rest_api_init', [Handler::instance(), 'rest_api_init']);
        add_action('rest_api_init', [Queue::instance(), 'rest_api_init']);
        add_action('rest_api_init', [Service::instance(), 'rest_api_init']);
        add_action('admin_bar_menu', [AdminBar::getInstance(), 'admin_bar_menu'], 50);
        add_action('update_option_' . RPM_OPT_PREFIX . Options::OPTION_NAME_PREFIX, [
            Options::getInstance(),
            'automatic_queueing_add',
        ]);
        add_action('update_option_' . RPM_OPT_PREFIX . Options::OPTION_NAME_TO_LOWER, [
            Options::getInstance(),
            'automatic_queueing_add',
        ]);
        add_action('update_option_' . RPM_OPT_PREFIX . Options::OPTION_NAME_SPECIAL_CHARS, [
            Options::getInstance(),
            'automatic_queueing_add',
        ]);
        add_action('delete_attachment', [QueueQueue::getInstance(), 'deleteAttachment']);
        add_action('delete_attachment', [MiscSeo::getInstance(), 'deleteAttachment']);
        add_action('RPM/Queue/Added', [QueueQueue::getInstance(), 'initialProcess']);
        add_action('RML/Options/Register', [Options::getInstance(), 'register_fields']);
        add_action('RML/CustomField', [CustomField::getInstance(), 'customField'], 10, 2);
        add_action('RML/Folder/Created', [$folderListener, 'created'], 10, 4);
        add_action('RML/Folder/Predeletion', [$folderListener, 'preDeletion']);
        add_action('RML/Folder/Delete', [$listener, 'folder_delete']);
        add_action('RML/Item/MoveFinished', [$listener, 'item_move_finished'], 10, 5);
        add_action('RML/Reset/Relations', [$listener, 'wipe']);
        add_action('RML/Reset', [$listener, 'wipe']);
        add_action('RML/Folder/Rename', [$listener, 'folder_rename'], 10, 2);
        add_action('RML/Folder/Renamed', [$listener, 'folder_renamed'], 10, 2);
        add_action('RML/Folder/Move', [$listener, 'folder_move'], 10);
        add_action('RML/Folder/Moved', [$listener, 'folder_moved'], 10);
        add_action('RML/Scripts', [$this->getAssets(), 'admin_enqueue_scripts']);

        add_filter('wp_handle_upload_prefilter', [UploadDir::getInstance(), 'handle_pre_upload']);
        add_filter('wp_handle_sideload_prefilter', [UploadDir::getInstance(), 'handle_pre_upload']);
        add_filter('wp_handle_upload', [UploadDir::getInstance(), 'handle_upload']);
        add_filter('dbdelta_create_queries', [WpPosts::getInstance(), 'dbdelta_create_queries']);
        add_filter('RML/Folder/Meta/Groups', [Options::getInstance(), 'folder_meta_groups']);

        add_rml_meta_box(ExcludeFolder::UNIQUE_NAME, new ExcludeFolder(), false, 10, Options::META_BOX_GROUP);
        add_rml_meta_box(
            SkipToFirstShortcut::UNIQUE_NAME,
            new SkipToFirstShortcut(),
            false,
            10,
            Options::META_BOX_GROUP
        );
        if (current_user_can('manage_options')) {
            add_rml_meta_box(Lockfile::UNIQUE_NAME, new Lockfile(), false, 10, Options::META_BOX_GROUP);
        }
        add_rml_meta_box(MetaSupText::UNIQUE_NAME, new MetaSupText(), false, 999, Options::META_BOX_GROUP);

        // Show notice when no handler is active, or activate automatically
        if ($handler->getCurrent() === null && current_user_can('activate_plugins')) {
            add_action('admin_notices', [$this, 'admin_notices_no_handler']);
            add_action('activated_plugin', [$handler, 'activated_plugin'], 10, 3);
        }

        // Lowercase path
        if (Options::getInstance()->isToLowerCase()) {
            add_filter('sanitize_file_name', function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower'); // strtolower does not support special characters
        }

        // Special characters
        if (Options::getInstance()->isSpecialCharacters()) {
            // add_filter('RPM/Attachment/Folder/Path', [SpecialCharacters::class, 'sanitize'], 9);
            add_filter('sanitize_file_name', [SpecialCharacters::class, 'sanitize'], 9);
        }
    }

    /**
     * This notice is shown when no handler is visible.
     */
    public function admin_notices_no_handler() {
        echo '<div class="notice notice-error hidden" id="rpm-no-handler-notice"></div>';
    }

    /**
     * Get ad initiator from `real-product-manager-wp-client`.
     *
     * @codeCoverageIgnore
     */
    public function getRpmInitiator() {
        return $this->rpmInitiator;
    }

    /**
     * Get singleton core class.
     *
     * @return Core
     */
    public static function getInstance() {
        return !isset(self::$me) ? (self::$me = new Core()) : self::$me;
    }
}

/**
 * See API docs.
 *
 * @api {get} /real-physical-media/v1/plugin Get plugin information
 * @apiHeader {string} X-WP-Nonce
 * @apiName GetPlugin
 * @apiGroup Plugin
 *
 * @apiSuccessExample {json} Success-Response:
 * {
 *     Name: "My plugin",
 *     PluginURI: "https://example.com/my-plugin",
 *     Version: "0.1.0",
 *     Description: "This plugin is doing something.",
 *     Author: "<a href="https://example.com">John Smith</a>",
 *     AuthorURI: "https://example.com",
 *     TextDomain: "my-plugin",
 *     DomainPath: "/languages",
 *     Network: false,
 *     Title: "<a href="https://example.com">My plugin</a>",
 *     AuthorName: "John Smith"
 * }
 * @apiVersion 0.1.0
 */
