<?php

namespace GOS\GravityOps\Core\SuiteCore\Admin;

use GOS\GravityOps\Core\SuiteCore\SuiteCore;
use Throwable;

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

/**
 * Handles displaying and processing the standard GravityOps survey prompt.
 */
class SurveyPrompter {

	/**
	 * Prefix used for option keys and field names.
	 *
	 * @var string
	 */
	private $prefix;

	/**
	 * Plugin title for display in the survey payload.
	 *
	 * @var string
	 */
	private $plugin_title;

	/**
	 * Plugin version to record with the survey submission.
	 *
	 * @var string
	 */
	private $plugin_version;

	/**
	 * Callback used to resolve the plan name (free/premium/etc.) or string with plan name.
	 *
	 * @var callable|string
	 */
	private $plan_or_resolver;

	/**
	 * Capability required to view the prompt.
	 *
	 * @var string
	 */
	private $capability;

	/**
	 * Survey endpoint URL.
	 *
	 * @var string
	 */
	private $endpoint;

	/**
	 * Delay (in seconds) before scheduling the first survey prompt.
	 *
	 * @var int
	 */
	private $delay;

	/**
     * SurveyPrompter constructor.
     *
	 * @param string          $prefix        Option and field prefix.
	 * @param string          $plugin_title  Plugin title.
	 * @param string          $plugin_version Plugin version.
	 * @param callable|string $plan_resolver Callable returning the current plan name or string with plan name.
	 * @param string          $capability    Capability required to view the survey.
	 * @param string          $endpoint      Endpoint to post survey submissions to.
	 * @param int             $delay         Delay in seconds before showing the survey.
	 */
	public function __construct(
		$prefix,
		$plugin_title,
		$plugin_version,
		$plan_resolver,
		$capability = 'manage_options',
		$endpoint = 'https://brightleafdigital.io/wp-json/gf/v2/forms/31/submissions',
		$delay = 5 * DAY_IN_SECONDS
	) {
		$this->prefix           = $prefix;
		$this->plugin_title     = $plugin_title;
		$this->plugin_version   = $plugin_version;
		$this->plan_or_resolver = $plan_resolver;
		$this->capability       = $capability;
		$default_endpoint       = 'https://brightleafdigital.io/wp-json/gf/v2/forms/31/submissions';
		$this->endpoint         = $endpoint;
		if ( $endpoint === $default_endpoint ) {
			$this->endpoint = SuiteCore::instance()->config()->get_survey_endpoint();
		}
		$this->delay = $delay;
	}

	/**
	 * Registers hooks to process and display the survey.
	 *
	 * @return void
	 */
	public function init() {
		$this->handle_submission();
		$this->maybe_schedule();
		add_action( "{$this->prefix}survey", [ $this, 'maybe_render_notice' ] );
	}

	/**
	 * Renders the survey notice if the current user is allowed.
	 *
	 * @return void
	 */
	public function maybe_render_notice() {
		if ( ! current_user_can( $this->capability ) ) {
			delete_option( "{$this->prefix}survey_status" );
			return;
		}

		$star_class       = "{$this->prefix}star";
		$rating_input_id  = "{$this->prefix}rating_input";
		$rating_field     = "{$this->prefix}rating";
		$like_field       = "{$this->prefix}like";
		$dislike_field    = "{$this->prefix}dislike";
		$recommend_field  = "{$this->prefix}recommend";
		$find_field       = "{$this->prefix}find";
		$nonce_field_name = "{$this->prefix}survey_nonce";
		$submit_field     = "{$this->prefix}survey_submit";
		$nonce_action     = "{$this->prefix}do_survey";

        $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-info is-dismissible';
        if ( $is_gops_page ) {
            $notice_classes .= ' inline';
        }
		$affiliate_url = SuiteCore::instance()->config()->get_affiliate_url();
		add_action(
			'admin_notices',
			function () use ( $star_class, $rating_input_id, $rating_field, $like_field, $dislike_field, $recommend_field, $find_field, $nonce_field_name, $submit_field, $nonce_action, $notice_classes, $affiliate_url ) {
				?>
				<div class="<?= esc_attr( $notice_classes ); ?>">
					<h3>We value your feedback!</h3>
                    <h4>Thank you for using <?= esc_html( $this->plugin_title ); ?>!</h4>
					<p>If you can spare one minute, we would love to hear your thoughts on how we can improve it.</p>
					<form method="post" action="">
						<?php wp_nonce_field( $nonce_action, $nonce_field_name ); ?>

						<ol>
							<li>
								<p>How do you like the plugin?</p>
								<div class="iawgf-rating-container">
									<style>
										.<?php echo esc_attr( $star_class ); ?> {
											font-size: 25px;
											color: #ccc;
											cursor: pointer;
											line-height: 1;
											margin-right: 2px;
										}
										.<?php echo esc_attr( $star_class ); ?>.filled {
											color: #ffb900;
										}
									</style>
									<?php for ( $i = 1; $i <= 5; $i++ ) : ?>
										<span class="<?php echo esc_attr( $star_class ); ?>" data-value="<?php echo esc_attr( $i ); ?>">☆</span>
									<?php endfor; ?>
									<input type="hidden" name="<?php echo esc_attr( $rating_field ); ?>" id="<?php echo esc_attr( $rating_input_id ); ?>">
									<script>
										(function() {
											const stars = document.querySelectorAll('.<?php echo esc_js( $star_class ); ?>');
											const input = document.getElementById('<?php echo esc_js( $rating_input_id ); ?>');
											let rating = 0;

											stars.forEach(function(star) {
												star.addEventListener('mouseover', function() {
													highlight(this.getAttribute('data-value'));
												});
												star.addEventListener('mouseout', function() {
													highlight(rating);
												});
												star.addEventListener('click', function() {
													rating = this.getAttribute('data-value');
													input.value = rating;
													highlight(rating);
												});
											});

											function highlight(value) {
												stars.forEach(function(s) {
													if (s.getAttribute('data-value') <= value) {
														s.textContent = '★';
														s.classList.add('filled');
													} else {
														s.textContent = '☆';
														s.classList.remove('filled');
													}
												});
											}
										})();
									</script>
								</div>
							</li>
							<li>
								<label>
									What do you like most about the plugin?<br>
									<textarea name="<?php echo esc_attr( $like_field ); ?>"></textarea>
								</label>
							</li>
							<li>
								<label>
									What do you like least about the plugin?<br>
									Have you experienced any issues, bugs, or friction while using the plugin?<br>
									<textarea name="<?php echo esc_attr( $dislike_field ); ?>"></textarea>
								</label>
							</li>
							<li>
								<label>
									How likely are you to recommend the plugin to a friend or colleague?<br>
									<input type="radio" name="<?php echo esc_attr( $recommend_field ); ?>" value="1"> Probably not <br>
									<input type="radio" name="<?php echo esc_attr( $recommend_field ); ?>" value="2"> If it comes up <br>
									<input type="radio" name="<?php echo esc_attr( $recommend_field ); ?>" value="3"> Very likely <small>(Did you know we have an <a href="<?php echo esc_url( $affiliate_url ); ?>" target="_blank" rel="noreferrer">affiliate program?</a>)</small><br>
								</label>
							</li>
							<li>
								<label>
									How did you find out about this plugin?<br>
									<input type="text" name="<?php echo esc_attr( $find_field ); ?>">
								</label>
							</li>
						</ol>

						<button class="button button-primary" type="submit" name="<?php echo esc_attr( $submit_field ); ?>" value="done">Submit</button>
						<button class="button button-secondary" type="submit" name="<?php echo esc_attr( $submit_field ); ?>" value="remind">Remind Me Later</button>
						<button class="button button-secondary" type="submit" name="<?php echo esc_attr( $submit_field ); ?>" value="skip">Not Interested</button>
					</form>

				</div>
				<?php
			}
		);
	}

	/**
	 * Handles survey submissions.
	 *
	 * @return void
	 */
	private function handle_submission() {
		$action = isset( $_POST[ "{$this->prefix}survey_submit" ] ) ? sanitize_text_field( wp_unslash( $_POST[ "{$this->prefix}survey_submit" ] ) ) : '';
		if ( ! $action || 'skip' === $action ) {
			return;
		}

		if ( 'remind' === $action ) {
			delete_option( "{$this->prefix}survey_status" );
			return;
		}

		$nonce = isset( $_POST[ "{$this->prefix}survey_nonce" ] ) ? sanitize_text_field( wp_unslash( $_POST[ "{$this->prefix}survey_nonce" ] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, "{$this->prefix}do_survey" ) ) {
			return;
		}

		$rating    = $this->map_rating( absint( $_POST[ "{$this->prefix}rating" ] ?? 0 ) );
		$recommend = $this->map_recommendation( absint( $_POST[ "{$this->prefix}recommend" ] ?? 0 ) );
		$like      = sanitize_text_field( wp_unslash( $_POST[ "{$this->prefix}like" ] ?? '' ) );
		$dislike   = sanitize_text_field( wp_unslash( $_POST[ "{$this->prefix}dislike" ] ?? '' ) );
		$find      = sanitize_text_field( wp_unslash( $_POST[ "{$this->prefix}find" ] ?? '' ) );

		$plan_name = $this->resolve_plan_name();

		$data = [
			'input_1'  => get_site_url(),
			'input_3'  => $this->plugin_title,
			'input_4'  => $plan_name,
			'input_5'  => $this->plugin_version,
			'input_14' => $rating,
			'input_7'  => $like,
			'input_8'  => $dislike,
			'input_13' => $recommend,
			'input_12' => $find,
		];

		$response = wp_remote_post(
			$this->endpoint,
			[
				'method' => 'POST',
				'body'   => $data,
			]
		);

		if ( is_wp_error( $response ) ) {
			$this->handle_error();
			return;
		}

		$code = wp_remote_retrieve_response_code( $response );
		if ( $code < 200 || $code >= 300 ) {
			$this->handle_error();
			return;
		}

		$body = wp_remote_retrieve_body( $response );
		$json = json_decode( $body, true );

		if ( ! is_array( $json ) || ( isset( $json['is_valid'] ) && ! $json['is_valid'] ) ) {
			$this->handle_error();
			return;
		}

		add_action(
			'admin_notices',
			function () {
				?>
			<div class="notice notice-success is-dismissible">
				<h3>Thank you so much for your feedback!</h3>
			</div>
				<?php
			}
		);
	}

	/**
	 * Displays an error notice and clears the survey status flag.
	 *
	 * @return void
	 */
	private function handle_error() {
		add_action(
			'admin_notices',
			function () {
				?>
			<div class="notice notice-error is-dismissible">
				<h3>There was an error submitting your feedback. Please try again later.</h3>
			</div>
				<?php
			}
		);
		delete_option( "{$this->prefix}survey_status" );
	}

	/**
	 * Schedules the survey prompt if it hasn't been scheduled yet.
	 *
	 * @return void
	 */
	private function maybe_schedule() {
		$survey_status = get_option( "{$this->prefix}survey_status" );
		if ( ! $survey_status ) {
			update_option( "{$this->prefix}survey_status", true );
			if ( ! wp_next_scheduled( "{$this->prefix}survey" ) ) {
				wp_schedule_single_event( time() + $this->delay, "{$this->prefix}survey" );
			}
		}
	}

	/**
	 * Resolves the plan name using the provided callback.
	 *
	 * @return string
	 */
	private function resolve_plan_name() {

        if ( is_string( $this->plan_or_resolver ) ) {
            return $this->plan_or_resolver;
        }

        if ( is_callable( $this->plan_or_resolver ) ) {
            try {
                $plan = call_user_func( $this->plan_or_resolver );
                if ( is_object( $plan ) && isset( $plan->name ) ) {
                    return (string) $plan->name;
                }
                if ( is_string( $plan ) ) {
                    return $plan;
                }
            } catch ( Throwable $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
                // Fallback below.
            }
        }
		return 'unknown';
	}

	/**
	 * Maps the numeric rating to the star string.
	 *
	 * @param int $rating Rating value 1-5.
	 *
	 * @return string
	 */
	private function map_rating( $rating ) {
		switch ( $rating ) {
			case 1:
				return '⭐';
			case 2:
				return '⭐⭐';
			case 3:
				return '⭐⭐⭐';
			case 4:
				return '⭐⭐⭐⭐';
			case 5:
				return '⭐⭐⭐⭐⭐';
			default:
				return '';
		}
	}

	/**
	 * Maps the likelihood radio value to text.
	 *
	 * @param int $recommend Numeric value.
	 *
	 * @return string
	 */
	private function map_recommendation( $recommend ) {
		switch ( $recommend ) {
			case 1:
				return 'Probably not';
			case 2:
				return 'If it comes up';
			case 3:
				return 'Very likely';
			default:
				return '';
		}
	}
}
