<?php
/**
 * Readabler
 * Web accessibility for Your WordPress site.
 * Exclusively on https://1.envato.market/readabler
 *
 * @encoding        UTF-8
 * @version         2.0.12
 * @copyright       (C) 2018-2025 Merkulove ( https://merkulov.design/ ). All rights reserved.
 * @license         Envato License https://1.envato.market/KYbje
 * @contributors    Dmytro Merkulov (dmitry@merkulov.design)
 * @support         help@merkulov.design
 **/

namespace Merkulove\Readabler\Unity;

use WP_REST_Server;

/** Exit if accessed directly. */
if ( ! defined( 'ABSPATH' ) ) {
    header( 'Status: 403 Forbidden' );
    header( 'HTTP/1.1 403 Forbidden' );
    exit;
}

/**
 * Class adds admin js scripts.
 *
 * @since 1.0.0
 *
 **/
final class Rest {

	/**
	 * The one true Rest.
	 * @var Rest
	 **/
	private static $instance;

	/**
	 * Sets up a new REST instance.
	 * @access public
	 **/
	private function __construct() {

		add_action( 'rest_api_init', function () {

			register_rest_route(

				untrailingslashit( 'readabler/v2' ),
				'/(?P<action>\w+)/',
				array(
					'methods' => WP_REST_Server::ALLMETHODS,
					'callback' => [ $this, 'callback' ],
					'permission_callback' => '__return_true',
				)
			);

		} );

	}

	/**
	 * Rest callback
	 *
	 * @param $params
	 *
	 * @return void
	 */
	public function callback( $params ) {

		// Sanitize
		$action = isset( $_POST['action'] ) ? sanitize_text_field( wp_unslash( $_POST['action'] ) ) : null;

		switch ( $action ) {

			case 'subscribe':

				// Gert name and email from request
				$name = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : null;
				$email = isset( $_POST['mail'] ) ? sanitize_email( wp_unslash( $_POST['mail'] ) ) : null;
				if ( empty( $name ) || empty( $email ) ) {
					wp_send_json_error(
						[
							'status'  => 'error',
							'message' => esc_html__( 'Name and email are required.', 'readabler' ),
						]
					);
					break;
				}

				// Remote request to subscribe user
				$remote = wp_remote_post(
					EnvatoItem::$host . '/api/v2/subscribe',
					[
						'timeout'    => 30,
						'user-agent' => 'readabler-user-agent',
						'sslverify'  => Settings::get_instance()->options[ 'check_ssl' ] === 'on',
						'headers'    => [
							'Accept'       => 'application/json',
						],
						'body'       => [
							'name'   => $name,
							'email'   => $email,
							'plugin' => Plugin::get_slug() ?? '',
							'domain' => $this->clear_url(),
						]
					]
				);

				// Check for errors
				if ( is_wp_error( $remote ) ) {
					wp_send_json_error(
						[
							'status'  => 'error',
							'message' => $remote->get_error_message(),
						]
					);
					break;
				}

				// Check for response code
				$body = wp_remote_retrieve_body( $remote );
				if ( empty( $body ) ) {
					wp_send_json_error(
						[
							'status'  => 'error',
							'message' => esc_html__( 'Empty response from server.', 'readabler' ),
						]
					);
					break;
				}

				// If body is not json
				$data = json_decode( $body, true );
				if ( ! is_array( $data ) ) {
					wp_send_json_error(
						[
							'status'  => 'error',
							'message' => esc_html__( 'Invalid response from server.', 'readabler' ),
						]
					);
					break;
				}

				// If status is error
				if ( ($data[ 'status' ] ?? 'error') === 'error' ) {
					wp_send_json_error(
						[
							'status'  => 'error',
							'message' => $data[ 'message' ] ?? esc_html__( 'Unknown error.', 'readabler' ),
						]
					);
					break;
				}

				// If status is already exists
				if ( $data[ 'status' ] === 'already_exists' ) {
					wp_send_json_error(
						[
							'status'  => 'already_exists',
							'message' => esc_html__( 'You are already subscribed.', 'readabler' ),
						]
					);
					break;
				}

				// Decode response
				wp_send_json_success(
					[
						'status'  => 'success',
						'message' => esc_html__( 'You have been successfully subscribed.', 'readabler' ),
					]
				);
				break;

            case 'dashboard':

                $data = $this->unity_dashboard_callback( $params );
                echo json_encode( $data );
                break;

			default:
				break;

		}

	}

	/**
	 * Prepare args for cURL request
	 * @return array
	 */
	private function get_ssl_args() {

		return [
			'timeout'    => 30,
			'user-agent' => 'readabler-user-agent',
			'sslverify'  => Settings::get_instance()->options[ 'check_ssl' ] === 'on'
		];

	}

    /**
     * Make url safe for queries
     * @return array|string|string[]
     */
    private function clear_url() {

        $protocols  = array( 'http://', 'http://www.', 'https://', 'https://www.', 'www.' );
        $url        = str_replace( $protocols, '', get_site_url() );

        return str_replace( '/', '-', $url );

    }

    /**
     * UPD dashboard handler
     * @return array|bool
     */
    private function unity_dashboard_callback( $params ) {

		$nonce = $params[ 'nonce' ] ?? '';
		check_ajax_referer( 'mdp-dashboard', $nonce );

        $result = false;
        $ask = $params[ 'ask' ] ?? '';
        switch ( $ask ) {

            case 'license':

                $result = $this->get_license_status( $params );
                break;

            case 'update':

                $cached = $this->get_update_status( $params );
                $result = json_decode( $cached, true )[ 'version' ] ?? '';
                break;

            default:
                break;

        }

        return $result;

    }

    /**
     * Get plugin table name of the cache table
     *
     * @param $plugin
     *
     * @return array|string
     */
    private function get_plugin_table_name( $plugin ) {

        global $wpdb;

        $table_name = str_replace( '-', '_', $plugin ) . '_cache';
        return esc_sql( $wpdb->prefix . $table_name );

    }

    /**
     * Fetch cached value from DB
     *
     * @param $plugin
     * @param $key
     *
     * @return int|bool
     */
    private function fetch_cached_value( $plugin, $key  ) {

        global $wpdb;

        // Check is table exists
        $table_name = $this->get_plugin_table_name( $plugin );
        $table_exists = $wpdb->get_var(
            $wpdb->prepare( "SHOW TABLES LIKE %s", $table_name )
        );
        if( ! $table_exists ) { return false; }

        // Check is row exists
        $cache_row = $wpdb->get_row(
            $wpdb->prepare( "SELECT `data` FROM $table_name WHERE `key` = '%s'", $key ),
            ARRAY_A
        );
        if ( ! is_array( $cache_row ) || ! isset( $cache_row[ 'data' ] ) ) { return false; }

        // Check is data exists
        $cache = json_decode( $cache_row[ 'data' ], true );

        return $cache[ $key ] ?? false;

    }

    /**
     * Get license status
     *
     * @param $params
     *
     * @return bool
     */
    private function get_license_status( $params ) {

        // Get params from request
        $plugin = $params[ 'plugin' ] ?? '';
        if ( empty( $plugin ) ) { return false; }

        // Get cached value
        $plugin_id = $this->fetch_cached_value( $plugin, 'mdp_'. $plugin .'_envato_id' );
        if ( ! $plugin_id  ) { return false; }

	    $pid = Plugin::get_purchase_code();
	    if ( ! $pid ) { return false; }

        return $this->fetch_cached_value( $plugin, 'activation_'. $pid );

    }

    private function get_update_status( $params ) {

        // Get params from request
        $plugin = $params[ 'plugin' ] ?? '';
        if ( empty( $plugin ) ) { return false; }

        // Get cached value
        $plugin_id = $this->fetch_cached_value( $plugin, 'mdp_'. $plugin .'_envato_id' );
        if ( ! $plugin_id  ) { return false; }

        $plugin_info = $this->fetch_cached_value( $plugin, 'mdp_'. str_replace( '-', '_', $plugin ) . '_plugin_info' );
        return $plugin_info[ 'body' ] ?? false;

    }

	/**
	 * Main Rest Instance.
	 * Insures that only one instance of Rest exists in memory at any one time.
	 *
	 * @static
	 * @return Rest
	 **/
	public static function get_instance() {

        /** @noinspection SelfClassReferencingInspection */
        if ( ! isset( self::$instance ) && ! ( self::$instance instanceof Rest ) ) {

			self::$instance = new Rest;

		}

		return self::$instance;

	}

}
