<?php

namespace GOS\GravityOps\Core\SuiteCore\Admin;

use GOS\GravityOps\Core\SuiteCore\SuiteCore;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class ReviewPrompter
 *
 * This class is responsible for prompting users to leave a review for the plugin. It manages
 * the display of admin notices, user actions in response to the notice, and tracks whether
 * the review request has already been made or postponed.
 */
class ReviewPrompter {

	/**
	 * Tracks whether the review prompt was postponed during the current request.
	 *
	 * @var bool
	 */
	private bool $rating_postponed = false;

    /**
     * Prefix used for naming or identification purposes.
     *
     * @var string
     */
    private $prefix;
    /**
     * Title or name of the plugin.
     *
     * @var string
     */
    private $plugin_title;
    /**
     * URL directing to the review page or section.
     *
     * @var string|array
     */
    private $review_url_or_params;

    /**
     * Constructor method to initialize the class properties.
     *
     * @param string       $prefix A unique prefix used for options and notices.
     * @param string       $plugin_title The title of the plugin.
     * @param string|array $review_url_or_params The URL for submitting a review.
     */
	public function __construct( $prefix, $plugin_title, $review_url_or_params ) {
		$this->prefix               = $prefix;
		$this->plugin_title         = $plugin_title;
		$this->review_url_or_params = $review_url_or_params;
	}

	/**
	 * Initialize the hooks.
	 */
	public function init() {
		$this->handle_review_action();
	}

	/**
	 * Checks conditions and adds the admin notice if met.
	 *
	 * @param int $current_count The current usage count (e.g., tasks created).
	 * @param int $threshold     The number to exceed before showing the notice (e.g., 50).
	 */
	public function maybe_show_review_request( $current_count, $threshold ) {
		$rating_asked = get_option( $this->prefix . 'rating_asked' );

		// Check if already asked or if "remind me later" cookie exists
		if ( $rating_asked || isset( $_COOKIE[ $this->prefix . 'suspend_notice' ] ) || $this->rating_postponed ) {
			return;
		}

		if ( $current_count > $threshold ) {
			$this->render_notice();
		}
	}

	/**
	 * Handles the POST action when a user clicks a button in the notice.
	 */
	private function handle_review_action() {
		$action_key = $this->prefix . 'rating_action';
		$nonce_key  = $this->prefix . 'rating_nonce';
		$submitted  = isset( $_POST[ $action_key ] ) ? sanitize_text_field( wp_unslash( $_POST[ $action_key ] ) ) : false;

		if ( $submitted ) {
			$nonce = isset( $_POST[ $nonce_key ] ) ? sanitize_text_field( wp_unslash( $_POST[ $nonce_key ] ) ) : '';

			if ( wp_verify_nonce( $nonce, $this->prefix . 'rating_asked' ) ) {
				if ( 'remind' === $submitted ) {
					$cookie_name   = $this->prefix . 'suspend_notice';
					$cookie_value  = '1';
					$cookie_expiry = time() + ( 2 * 24 * 60 * 60 ); // 2 days from now

					if ( ! headers_sent() ) {
						$cookie_args = [
							'expires'  => $cookie_expiry,
							'path'     => defined( 'COOKIEPATH' ) && COOKIEPATH ? COOKIEPATH : '/',
							'secure'   => is_ssl(),
							'httponly' => true,
							'samesite' => 'Lax',
						];
						if ( defined( 'COOKIE_DOMAIN' ) && COOKIE_DOMAIN ) {
							$cookie_args['domain'] = COOKIE_DOMAIN;
						}
						setcookie( $cookie_name, $cookie_value, $cookie_args );
					}
					$this->rating_postponed = true;
				} elseif ( 'done' === $submitted ) {
					update_option( $this->prefix . 'rating_asked', true );
				}
			}
		}
	}

	/**
	 * Renders the actual HTML admin notice.
	 */
	public function render_notice() {
        if ( is_string( $this->review_url_or_params ) ) {
            $url = $this->review_url_or_params;
        } else {
            $url = $this->get_url();
        }
        if ( empty( $url ) ) {
            return;
        }

        $nonce_field  = $this->prefix . 'rating_nonce';
        $action_field = $this->prefix . 'rating_action';
        $nonce_action = $this->prefix . 'rating_asked';
        $plugin_title = $this->plugin_title;

		$nonce = wp_create_nonce( $nonce_action );

        $current_page   = isset( $_GET['page'] ) ? sanitize_key( $_GET['page'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $is_gops_page   = ( 'gravity_ops' === $current_page || SuiteCore::instance()->shell()->has_page( $current_page ) );
        $notice_classes = 'notice notice-success is-dismissible';
        if ( $is_gops_page ) {
            $notice_classes .= ' inline';
        }
        add_action(
            'admin_notices',
            function () use ( $nonce, $action_field, $nonce_field, $plugin_title, $url, $notice_classes ) {
				?>
            <div class="<?= esc_attr( $notice_classes ); ?>">
                <h3>Thank you for using <?php echo esc_html( $plugin_title ); ?>! I noticed you've used it a lot!</h3>
                <h4>
                    If you like the plugin and find it helpful, can you do us a big favor and <a
                            href="<?php echo esc_url( $url ); ?>"
                            target="_blank" rel="noreferrer">rate it</a> with ⭐⭐⭐⭐⭐?
                    It helps us spread the word and boost our motivation.
                </h4>
                <form method="post" action="">
                    <input type="hidden" name="<?php echo esc_attr( $nonce_field ); ?>" value="<?php echo esc_attr( $nonce ); ?>">
                    <button class="button" type="submit" name="<?php echo esc_attr( $action_field ); ?>" value="remind">Remind me later</button>
                    <button class="button" type="submit" name="<?php echo esc_attr( $action_field ); ?>" value="done">Done!</button>
                    <button class="button" type="submit" name="<?php echo esc_attr( $action_field ); ?>" value="done">Not Interested</button>
                </form>
            </div>
				<?php
			}
            );
	}

    /**
     * Retrieves a URL from an external endpoint.
     *
     * This method sends a GET request to a specified endpoint using provided parameters,
     * then extracts and returns the URL from the JSON response. If the request fails
     * or the response is invalid, an empty string is returned.
     *
     * @return string The retrieved URL or an empty string if the request fails or the response is invalid.
     */
    private function get_url() {
        $endpoint = SuiteCore::instance()->config()->get_review_endpoint();
        $params   = $this->review_url_or_params;
        if ( ! is_array( $params ) ) {
            $params = [];
        }
        if ( isset( $params['license_key'] ) ) {
            $params['license_key'] = rawurlencode( $params['license_key'] );
        }
        $url      = add_query_arg( $params, $endpoint );
        $response = wp_safe_remote_get( $url );
        if ( is_wp_error( $response ) ) {
            return '';
        }
        $body = wp_remote_retrieve_body( $response );
        if ( empty( $body ) ) {
            return '';
        }
        $data = json_decode( $body, true );
        return $data['url'] ?? '';
    }
}
