<?php
/**
 * @author WP Cloud Plugins
 * @copyright Copyright (c) 2023, WP Cloud Plugins
 *
 * @since       2.11
 * @see https://www.wpcloudplugins.com
 */

namespace TheLion\ShareoneDrive;

use ReCaptcha\ReCaptcha;

defined('ABSPATH') || exit;

class AjaxRequest
{
    /**
     * The single instance of the class.
     *
     * @var AjaxRequest
     */
    protected static $_instance;

    public function __construct()
    {
        $this->set_hooks();
    }

    /**
     * AjaxRequest Instance.
     *
     * Ensures only one instance is loaded or can be loaded.
     *
     * @return AjaxRequest - AjaxRequest instance
     *
     * @static
     */
    public static function instance()
    {
        if (is_null(self::$_instance)) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }

    public function set_hooks()
    {
        // Ajax calls
        add_action('wp_ajax_nopriv_shareonedrive-get-filelist', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-get-filelist', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-search', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-search', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-get-gallery', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-get-gallery', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-proofing', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-proofing', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-upload-file', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-upload-file', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-delete-entries', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-delete-entries', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-rename-entry', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-rename-entry', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-move-entries', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-move-entries', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-copy-entries', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-copy-entries', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-edit-description-entry', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-edit-description-entry', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-create-entry', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-create-entry', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-get-playlist', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-get-playlist', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-create-zip', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-create-zip', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-download', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-download', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-stream', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-stream', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-preview', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-preview', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-edit', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-edit', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-folder-thumbnail', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-folder-thumbnail', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-thumbnail', [$this, 'create_thumbnail']);
        add_action('wp_ajax_shareonedrive-thumbnail', [$this, 'create_thumbnail']);

        add_action('wp_ajax_nopriv_shareonedrive-check-recaptcha', [$this, 'check_recaptcha']);
        add_action('wp_ajax_shareonedrive-check-recaptcha', [$this, 'check_recaptcha']);

        add_action('wp_ajax_nopriv_shareonedrive-create-link', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-create-link', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-embedded', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-shorten-url', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-shorten-url', [$this, 'do_action']);

        add_action('wp_ajax_shareonedrive-getpopup', [$this, 'get_popup']);
        add_action('wp_ajax_shareonedrive-module-preview', [$this, 'preview_shortcode']);

        add_action('wp_ajax_nopriv_shareonedrive-import-entries', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-import-entries', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-getads', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-getads', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-module-login', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-module-login', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-module-lead', [$this, 'do_action']);
        add_action('wp_ajax_shareonedrive-module-lead', [$this, 'do_action']);

        add_action('wp_ajax_nopriv_shareonedrive-embed-image', [$this, 'embed_image']);
        add_action('wp_ajax_shareonedrive-embed-image', [$this, 'embed_image']);

        add_action('wp_ajax_nopriv_shareonedrive-embed-redirect', [$this, 'embed_redirect']);
        add_action('wp_ajax_shareonedrive-embed-redirect', [$this, 'embed_redirect']);

        add_action('wp_ajax_shareonedrive-linkusertofolder', [$this, 'user_folder_link']);
        add_action('wp_ajax_shareonedrive-unlinkusertofolder', [$this, 'user_folder_unlink']);
        add_action('wp_ajax_shareonedrive-rating-asked', [$this, 'rating_asked']);
    }

    public function do_action()
    {
        if (!isset($_REQUEST['action'])) {
            return false;
        }

        require_once ABSPATH.'wp-includes/pluggable.php';
        Processor::instance()->start_process();

        exit;
    }

    public function check_recaptcha()
    {
        if (!isset($_REQUEST['action']) || !isset($_REQUEST['response'])) {
            echo json_encode(['verified' => false]);

            exit;
        }

        check_ajax_referer($_REQUEST['action']);

        require_once SHAREONEDRIVE_ROOTDIR.'/vendors/reCAPTCHA/autoload.php';

        $secret = Settings::get('recaptcha_secret');
        $recaptcha = new ReCaptcha($secret);

        $resp = $recaptcha->setExpectedAction('wpcloudplugins')
            ->setScoreThreshold(0.5)
            ->verify($_REQUEST['response'], Helpers::get_user_ip())
        ;

        if ($resp->isSuccess()) {
            echo json_encode(['verified' => true]);
        } else {
            echo json_encode(['verified' => false, 'msg' => $resp->getErrorCodes()]);
        }

        exit;
    }

    public function create_thumbnail()
    {
        if (!isset($_REQUEST['account_id'])) {
            // Fallback for old embed urls without account info

            $primary_account = Accounts::instance()->get_primary_account();
            if (false === $primary_account) {
                exit('-1');
            }
            $account_id = $primary_account->get_id();
        } else {
            $account_id = $_REQUEST['account_id'];
        }

        App::set_current_account_by_id($account_id);

        if (!isset($_REQUEST['drive_id'])) {
            $drive_id = App::get_primary_drive_id();
            if (null === $drive_id) {
                return false;
            }
        } else {
            $drive_id = $_REQUEST['drive_id'];
        }
        App::set_current_drive_id($drive_id);

        return Processor::instance()->create_thumbnail();
    }

    public function get_popup()
    {
        switch ($_REQUEST['type']) {
            case 'shortcodebuilder':
                ShortcodeBuilder::instance()->render();

                break;

            case 'modules':
                if (!empty($_REQUEST['module']) || !empty($_REQUEST['shortcode'])) {
                    ShortcodeBuilder::instance()->render();
                } else {
                    Modules::instance()->render();
                }

                break;

            case 'links':
                include_once SHAREONEDRIVE_ROOTDIR.'/templates/admin/documents_linker.php';

                break;

            case 'embedded':
                include_once SHAREONEDRIVE_ROOTDIR.'/templates/admin/documents_embedder.php';

                break;

            default:
                exit;
        }

        exit;
    }

    public function preview_shortcode()
    {
        check_ajax_referer('shareonedrive-module-preview');

        include_once SHAREONEDRIVE_ROOTDIR.'/templates/admin/shortcode_previewer.php';

        exit;
    }

    public function embed_image()
    {
        $entryid = $_REQUEST['id'] ?? null;

        if (empty($entryid)) {
            exit('-1');
        }

        if (!isset($_REQUEST['account_id'])) {
            // Fallback for old embed urls without account info
            $primary_account = Accounts::instance()->get_primary_account();
            if (false === $primary_account) {
                exit('-1');
            }
            $account_id = $primary_account->get_id();
        } else {
            $account_id = $_REQUEST['account_id'];
        }

        App::set_current_account_by_id($account_id);

        // Fallback for old embed urls without drive info
        if (!isset($_REQUEST['drive_id'])) {
            $drive_id = App::get_primary_drive_id();
            if (null === $drive_id) {
                return false;
            }
        } else {
            $drive_id = $_REQUEST['drive_id'];
        }
        App::set_current_drive_id($drive_id);

        Processor::instance()->embed_image($entryid);

        exit;
    }

    public function embed_redirect()
    {
        $entryid = $_REQUEST['id'] ?? null;

        if (empty($entryid)) {
            exit('-1');
        }

        if (!isset($_REQUEST['account_id'])) {
            // Fallback for old embed urls without account info
            $primary_account = Accounts::instance()->get_primary_account();
            if (false === $primary_account) {
                exit('-1');
            }
            $account_id = $primary_account->get_id();
        } else {
            $account_id = $_REQUEST['account_id'];
        }

        App::set_current_account_by_id($account_id);

        // Fallback for old embed urls without drive info
        if (!isset($_REQUEST['drive_id'])) {
            $drive_id = App::get_primary_drive_id();
            if (null === $drive_id) {
                return false;
            }
        } else {
            $drive_id = $_REQUEST['drive_id'];
        }

        App::set_current_drive_id($drive_id);

        $params = [];
        if (isset($_REQUEST['zoom'])) {
            $params['zoom'] = $_REQUEST['zoom'];
        }

        Processor::instance()->embed_redirect($entryid, $params);

        exit;
    }

    public function rating_asked()
    {
        update_option('share_one_drive_rating_asked', true);
    }

    public function user_folder_link()
    {
        check_ajax_referer('shareonedrive-create-link');

        $folder_id = sanitize_text_field(rawurldecode($_REQUEST['id']));
        $account_id = sanitize_text_field(rawurldecode($_REQUEST['account_id']));
        $drive_id = sanitize_text_field(rawurldecode($_REQUEST['drive_id']));

        $linkedto = [
            'folderid' => $folder_id,
            'accountid' => $account_id,
            'drive_id' => $drive_id,
        ];

        $userid = $_REQUEST['userid'];

        if (Helpers::check_user_role(Settings::get('permissions_link_users'))) {
            UserFolders::instance()->manually_link_folder($userid, $linkedto);
        }
    }

    public function user_folder_unlink()
    {
        check_ajax_referer('shareonedrive-create-link');

        $userid = $_REQUEST['userid'];
        $personal_folder_key = $_REQUEST['personal_folder_key'];

        if (Helpers::check_user_role(Settings::get('permissions_link_users'))) {
            UserFolders::instance()->manually_unlink_folder($userid, $personal_folder_key);
        }
    }

    public static function is_action_authorized($hook = false)
    {
        // Check if AJAX calls are coming from site own domain
        $ajax_domain_verification = ('Yes' === Settings::get('ajax_domain_verification'));
        $do_domain_verification = apply_filters('shareonedrive_do_domain_verification', $ajax_domain_verification);
        if ($do_domain_verification) {
            $refer = Helpers::get_page_url();
            if (!empty($refer)) {
                $refer_host = parse_url($refer, PHP_URL_HOST);
                $origin_host = parse_url(get_site_url(), PHP_URL_HOST);

                if (!empty($refer_host) && 0 !== strcasecmp($refer_host, $origin_host)) {
                    Helpers::log_error('AJAX request is blocked as it is sent from a different domain.', 'Processor', ['refer_host' => $refer_host, 'origin_host' => $origin_host], __LINE__);

                    exit;
                }
            }
        }

        // Nonce validation
        $nonce_verification = ('Yes' === Settings::get('nonce_validation'));
        $allow_nonce_verification = apply_filters('share_one_drive_allow_nonce_verification', $nonce_verification);

        if ($allow_nonce_verification && isset($_REQUEST['action']) && (false === $hook) && is_user_logged_in()) {
            $is_authorized = false;

            $requested_action = $_REQUEST['action'];

            switch ($requested_action) {
                case 'shareonedrive-upload-file':
                case 'shareonedrive-get-filelist':
                case 'shareonedrive-get-gallery':
                case 'shareonedrive-get-playlist':
                case 'shareonedrive-proofing':
                case 'shareonedrive-rename-entry':
                case 'shareonedrive-copy-entries':
                case 'shareonedrive-move-entries':
                case 'shareonedrive-edit-description-entry':
                case 'shareonedrive-create-entry':
                case 'shareonedrive-create-zip':
                case 'shareonedrive-delete-entries':
                case 'shareonedrive-event-log':
                case 'shareonedrive-shorten-url':
                case 'shareonedrive-module-login':
                case 'shareonedrive-module-lead':
                case 'shareonedrive-module-preview':
                case 'shareonedrive-import-entries':
                    $is_authorized = check_ajax_referer($requested_action, false, false);

                    break;

                case 'shareonedrive-create-link':
                case 'shareonedrive-embedded':
                    $is_authorized = check_ajax_referer('shareonedrive-create-link', false, false);

                    break;

                case 'shareonedrive-revoke':
                    $is_authorized = (false !== check_ajax_referer('shareonedrive-admin-action', false, false));

                    break;

                case 'shareonedrive-download':
                case 'shareonedrive-stream':
                case 'shareonedrive-preview':
                case 'shareonedrive-folder-thumbnail':
                case 'shareonedrive-edit':
                case 'shareonedrive-getpopup':
                case 'shareonedrive-getads':
                    $is_authorized = true;

                    break;

                case 'edit': // Required for WooCommerce integration
                    $is_authorized = true;

                    break;

                case 'editpost': // Required for integrations
                case 'wpseo_filter_shortcodes':
                case 'elementor':
                case 'elementor_ajax':
                case 'frm_insert_field':
                    return false;

                default:
                    $is_authorized = apply_filters('shareonedrive_nonce_verification', false, $requested_action);

                    if (false === $is_authorized) {
                        Helpers::log_error('Invalid AJAX request received.', 'Processor', ['action' => sanitize_key($requested_action)], __LINE__);

                        exit;
                    }
            }

            if (false === $is_authorized) {
                Helpers::log_error('Invalid AJAX nonce received.', 'Processor', ['action' => sanitize_key($requested_action)], __LINE__);

                exit;
            }
        }

        return true;
    }
}
