<?php
/**
 * Admin Tour
 *
 * @author    Wpayme <hi@wpayme.com>
 * @copyright 2024-2025 Wpayme
 * @license   GPL-3.0-or-later
 * @package   Wpayme\WordPress\Pay\Admin
 */

namespace Wpayme\WordPress\Pay\Admin;

use Wpayme\WordPress\Pay\Plugin;

/**
 * WordPress admin tour
 *
 * @author  Remco Tolsma
 * @version 2.4.0
 * @since   1.0.0
 */
class AdminTour {
	/**
	 * Plugin.
	 *
	 * @var Plugin
	 */
	private $plugin;

	/**
	 * Constructs and initializes an pointers object.
	 *
	 * @link https://github.com/WordPress/WordPress/blob/4.2.4/wp-includes/js/wp-pointer.js
	 * @link https://github.com/WordPress/WordPress/blob/4.2.4/wp-admin/includes/template.php#L1955-L2016
	 * @link https://github.com/Yoast/wordpress-seo/blob/2.3.4/admin/class-pointers.php
	 *
	 * @param Plugin $plugin Plugin.
	 */
	public function __construct( Plugin $plugin ) {
		$this->plugin = $plugin;

		// Add dashboard CSS to all admin pages
		\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_dashboard_styles' ] );

		// Actions.
		add_action( 'admin_init', [ $this, 'handle_ignore_tour_request' ] );
		add_action( 'admin_init', [ $this, 'handle_force_tour_request' ] );
		add_action( 'admin_init', [ $this, 'maybe_show_admin_tour' ] );
	}

	/**
	 * Maybe show admin tour.
	 *
	 * @return void
	 */
	public function maybe_show_admin_tour() {
		$screen = \get_current_screen();
		$screen_id = $screen ? $screen->id : 'unknown';
		$user_id = \get_current_user_id();
		
		// error_log( 'Wpayme Tour: Checking if tour should show for user ' . $user_id . ' on screen ' . $screen_id );
		
		// Check for any tour parameter in URL
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_GET['tour'] ) ) {
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$tour_action = sanitize_text_field( wp_unslash( $_GET['tour'] ) );
			// error_log( 'Wpayme Tour: URL parameter tour=' . $tour_action );
			
			if ( in_array( $tour_action, array( 'start', 'continue' ), true ) ) {
				// error_log( 'Wpayme Tour: Showing tour based on tour URL parameter' );
				\add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
				return;
			}
		}
		
		// Force show tour if reset was requested
		if ( \get_user_meta( $user_id, 'wpayme_pay_show_tour', true ) ) {
			// Clear the flag after reading it
			\delete_user_meta( $user_id, 'wpayme_pay_show_tour' );
			
			// Log the action
			// error_log( 'Wpayme Tour: Showing tour based on show_tour user meta' );
			
			// Add the enqueue action
			\add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
			return;
		}
		
		// Check for tour completion
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset( $_GET['tour_complete'] ) && 'true' === $_GET['tour_complete'] ) {
			// Verify nonce for state change
			if ( isset( $_GET['wpayme_pay_nonce'] ) && \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_GET['wpayme_pay_nonce'] ) ), 'wpayme_pay_tour_complete' ) ) {
				// error_log( 'Wpayme Tour: Tour completed' );
				// Update user meta to indicate tour completion
				\update_user_meta( $user_id, 'wpayme_pay_ignore_tour', true );
			}
			return;
		}
		
		// Check URL parameters (for direct links to tour pages)
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( isset($_GET['page']) && 'wpayme' === $_GET['page'] && 
			 isset($_GET['wpayme_pay_ignore_tour']) && 'false' === $_GET['wpayme_pay_ignore_tour'] ) {
			// Log the action
			// error_log( 'Wpayme Tour: Showing tour based on ignore=false URL parameter' );
			
			// Add the enqueue action
			\add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
			return;
		}
	
		// Ignore tour if user has closed it
		if ( \get_user_meta( $user_id, 'wpayme_pay_ignore_tour', true ) ) {
			// error_log( 'Wpayme Tour: Not showing tour - user has ignore_tour meta set' );
			return;
		}

		// Installation date.
		$installation_date = (string) \get_option( 'wpayme_pay_installation_date', '' );

		if ( '' !== $installation_date ) {
			try {
				$installation_date = new \DateTimeImmutable( $installation_date );
				$day_ago = new \DateTimeImmutable( '-1 day' );

				if ( $installation_date < $day_ago ) {
					// error_log( 'Wpayme Tour: Not showing tour - installation date is more than 1 day old' );
					return;
				}
			} catch ( \Exception $e ) {
				// Nothing to do, ignore invalid installation date.
				// error_log( 'Wpayme Tour: Invalid installation date - ' . $e->getMessage() );
			}
		}

		// error_log( 'Wpayme Tour: Showing tour - no reason to skip found' );
		\add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
	}

	/**
	 * Handle ignore tour request.
	 *
	 * @return void
	 */
	public function handle_ignore_tour_request() {
		if ( ! \array_key_exists( 'wpayme_pay_ignore_tour', $_GET ) ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( ! \array_key_exists( 'wpayme_pay_nonce', $_GET ) ) {
			// Log the missing nonce for debugging
			// error_log('Wpayme Tour Ignore: Missing nonce parameter');
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$nonce = \sanitize_text_field( \wp_unslash( $_GET['wpayme_pay_nonce'] ) );

		if ( ! \wp_verify_nonce( $nonce, 'wpayme_pay_ignore_tour' ) ) {
			// Log the invalid nonce for debugging
			// error_log('Wpayme Tour Ignore: Invalid nonce');
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$value = \sanitize_text_field( \wp_unslash( $_GET['wpayme_pay_ignore_tour'] ) );

		// Set the ignore tour flag based on the value
		$result = \update_user_meta( \get_current_user_id(), 'wpayme_pay_ignore_tour', ( 'true' === $value ) );
		
		// If starting tour (false value), set the show tour flag
		if ( 'false' === $value ) {
			\update_user_meta( \get_current_user_id(), 'wpayme_pay_show_tour', true );
			
			// Log the action for debugging
			// error_log('Wpayme Tour Start: Meta update result: ' . ($result ? 'Success' : 'Failed'));
			
			// Redirect to the first tour page (dashboard)
			wp_safe_redirect( add_query_arg( 'page', 'wpayme', admin_url( 'admin.php' ) ) );
			exit;
		}
	}

	/**
	 * Handle force tour request.
	 *
	 * @return void
	 */
	public function handle_force_tour_request() {
		if ( ! \array_key_exists( 'wpayme_pay_force_tour', $_GET ) ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( ! \array_key_exists( 'wpayme_pay_nonce', $_GET ) ) {
			// Log the missing nonce for debugging
			// error_log('Wpayme Tour Force: Missing nonce parameter');
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$nonce = \sanitize_text_field( \wp_unslash( $_GET['wpayme_pay_nonce'] ) );

		if ( ! \wp_verify_nonce( $nonce, 'wpayme_pay_force_tour' ) ) {
			// Log the invalid nonce for debugging
			// error_log('Wpayme Tour Force: Invalid nonce');
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$value = \sanitize_text_field( \wp_unslash( $_GET['wpayme_pay_force_tour'] ) );

		if ( 'true' === $value ) {
			$user_id = \get_current_user_id();
			
			// Always reset the tour state
			// error_log('Wpayme Tour Force: Starting tour for user ' . $user_id);
			
			// Clear ALL existing tour-related user meta
			\delete_user_meta( $user_id, 'wpayme_pay_ignore_tour' );
			\delete_user_meta( $user_id, 'wpayme_pay_dismiss_tour' );
			\delete_user_meta( $user_id, 'wpayme_pay_hide_tour' );
			\delete_user_meta( $user_id, 'wpayme_pay_completed_tour' );
			
			// Set a positive flag to explicitly show the tour
			\update_user_meta( $user_id, 'wpayme_pay_show_tour', true );
			
			// Add a unique timestamp parameter to avoid caching issues
			$redirect_url = add_query_arg( 
				array(
					'page' => 'wpayme',
					'tour' => 'start',
					'_ts' => time(), 
				), 
				admin_url( 'admin.php' ) 
			);
			
			// Force redirect to the dashboard
			// error_log('Wpayme Tour Force: Redirecting to: ' . $redirect_url);
			wp_safe_redirect( $redirect_url );
			exit;
		}
	}

	/**
	 * Enqueue dashboard styles for all admin pages.
	 *
	 * @return void
	 */
	public function enqueue_dashboard_styles() {
		$min = \SCRIPT_DEBUG ? '' : '.min';

		// Dashboard styles
		wp_register_style(
			'wpayme-pay-dashboard',
			plugins_url( '../../css/dashboard' . $min . '.css', __FILE__ ),
			[],
			$this->plugin->get_version()
		);

		// Enqueue dashboard styles
		wp_enqueue_style( 'wpayme-pay-dashboard' );
	}

	/**
	 * Admin enqueue scripts.
	 *
	 * @return void
	 */
	public function admin_enqueue_scripts() {
		$min = \SCRIPT_DEBUG ? '' : '.min';
		
		// Log which pointers we're going to show
		$pointers = $this->get_pointers();
		// error_log( 'Wpayme Tour: Enqueuing scripts for ' . count( $pointers ) . ' pointers' );
		
		/*
		foreach ( $pointers as $index => $pointer ) {
			error_log( 'Wpayme Tour: Pointer ' . $index . ' targeting "' . $pointer['selector'] . '"' );
		}
		*/

		// Pointers.
		wp_register_style(
			'wpayme-pay-admin-tour',
			plugins_url( '../../css/admin-tour' . $min . '.css', __FILE__ ),
			[
				'wp-pointer',
			],
			$this->plugin->get_version()
		);

		// Dashboard styles already registered and enqueued in enqueue_dashboard_styles()

		// Add timestamp to bust cache
		$current_time = time();
		
		// Generate nonces for tour buttons
		$ignore_tour_nonce = wp_create_nonce( 'wpayme_pay_ignore_tour' );
		$force_tour_nonce = wp_create_nonce( 'wpayme_pay_force_tour' );
		
		// Tour settings
		wp_register_script(
			'wpayme-pay-admin-tour-settings',
			plugins_url( '../../js/dist/admin-tour-settings' . $min . '.js', __FILE__ ),
			[
				'jquery',
			],
			$this->plugin->get_version() . '.' . $current_time,
			true
		);

		// Add dashboard URL settings for the tour
		wp_localize_script(
			'wpayme-pay-admin-tour-settings',
			'wpaymeAdminTourSettings',
			[
				'dashboardUrl' => add_query_arg( 'page', 'wpayme', admin_url( 'admin.php' ) ),
				'timestamp' => $current_time,
				'ignoreTourNonce' => $ignore_tour_nonce,
				'forceTourNonce' => $force_tour_nonce,
				'startTourText' => __( 'Start Tour', 'wpayme' ),
			]
		);
		
		// Main tour script
		wp_register_script(
			'wpayme-pay-admin-tour',
			plugins_url( '../../js/dist/admin-tour' . $min . '.js', __FILE__ ),
			[
				'jquery',
				'wp-pointer',
				'wpayme-pay-admin-tour-settings',
			],
			$this->plugin->get_version() . '.' . $current_time,
			true
		);

		wp_localize_script(
			'wpayme-pay-admin-tour',
			'wpaymePayAdminTour',
			[
				'pointers' => $pointers,
				'timestamp' => $current_time,
			]
		);

		// Enqueue tour-specific styles and scripts
		wp_enqueue_style( 'wpayme-pay-admin-tour' );
		wp_enqueue_script( 'wpayme-pay-admin-tour-settings' );
		wp_enqueue_script( 'wpayme-pay-admin-tour' );
		
		// error_log( 'Wpayme Tour: Scripts and styles enqueued successfully. Timestamp: ' . $current_time );
	}

	/**
	 * Get pointer content.
	 *
	 * @param string $pointer Pointer key.
	 * @return string
	 * @throws \Exception When output buffering is not active.
	 */
	private function get_content( $pointer ) {
		$content = '';

		$path = __DIR__ . '/../../views/pointer-' . $pointer . '.php';

		if ( is_readable( $path ) ) {
			ob_start();

			$admin_tour = $this;

			include $path;

			$content = '';

			$output = ob_get_clean();

			if ( false !== $output ) {
				$content .= $output;
			}

			$content .= $this->get_navigation( $pointer );
		}

		return $content;
	}

	/**
	 * Get pointers.
	 *
	 * @return array
	 */
	private function get_pointers() {
		$pointers = [];

		$screen = get_current_screen();
		// error_log('Current screen: ' . print_r($screen, true));

		// Default pointer for the start page
		if (empty($pointers)) {
			$pointers = [
				[
					'selector' => '#adminmenuwrap', // Target the admin menu to show it's clickable
					'options'  => (object) [
						'content'      => $this->get_content( 'start' ),
						'position'     => (object) [
							'edge'  => 'left',
							'align' => 'center',
						],
						'pointerWidth' => 400,
					],
				],
			];
		}

		// Check which screen we're on and show the appropriate pointer
		if (null !== $screen) {
			switch ($screen->id) {
				case 'toplevel_page_wpayme':
					$pointers = [
						[
							'selector' => '#wpbody-content .wrap h1', 
							'options'  => (object) [
								'content'      => $this->get_content( 'dashboard' ),
								'position'     => (object) [
									'edge'  => 'top',
									'align' => 'left',
								],
								'pointerWidth' => 400,
							],
						],
					];
					break;

				case 'edit-wpayme_payment':
					$pointers = [
						[
							'selector' => '#wpbody-content .wrap h1',
							'options'  => (object) [
								'content'      => $this->get_content( 'payments' ),
								'position'     => (object) [
									'edge'  => 'top',
									'align' => 'left',
								],
								'pointerWidth' => 400,
							],
						],
					];
					break;

				case 'edit-wpayme_gateway':
					$pointers = [
						[
							'selector' => '#wpbody-content .wrap h1',
							'options'  => (object) [
								'content'      => $this->get_content( 'gateways' ),
								'position'     => (object) [
									'edge'  => 'top',
									'align' => 'left',
								],
								'pointerWidth' => 400,
							],
						],
					];
					break;

				case 'edit-wpayme_pay_form':
					$pointers = [
						[
							'selector' => '#wpbody-content .wrap h1',
							'options'  => (object) [
								'content'      => $this->get_content( 'forms' ),
								'position'     => (object) [
									'edge'  => 'top',
									'align' => 'left',
								],
								'pointerWidth' => 400,
							],
						],
					];
					break;
			}
		}

		// Check if we're on specific admin pages
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';
		
		switch ($page) {
			case 'wpayme_pay_settings':
				$pointers = [
					[
						'selector' => '#wpbody-content .wrap h1',
						'options'  => (object) [
							'content'      => $this->get_content( 'settings' ),
							'position'     => (object) [
								'edge'  => 'top',
								'align' => 'left',
							],
							'pointerWidth' => 400,
						],
					],
				];
				break;

			case 'wpayme_pay_reports':
				$pointers = [
					[
						'selector' => '#wpbody-content .wrap h1',
						'options'  => (object) [
							'content'      => $this->get_content( 'reports' ),
							'position'     => (object) [
								'edge'  => 'top',
								'align' => 'left',
							],
							'pointerWidth' => 400,
						],
					],
				];
				break;
		}

		return $pointers;
	}

	/**
	 * Get tour close URL.
	 *
	 * @return string
	 */
	public function get_close_url() {
		return wp_nonce_url(
			add_query_arg(
				[
					'wpayme_pay_ignore_tour' => 'true',
				]
			),
			'wpayme_pay_ignore_tour',
			'wpayme_pay_nonce'
		);
	}

	/**
	 * Get pages.
	 *
	 * @return string[]
	 */
	private function get_pages() {
		$modules = \apply_filters( 'wpayme_pay_modules', [] );

		$pages = [
			'start'     => \add_query_arg( 'page', 'wpayme', \admin_url( 'admin.php' ) ),
			'dashboard' => \add_query_arg( 'page', 'wpayme', \admin_url( 'admin.php' ) ),
			'payments'  => \add_query_arg( 'post_type', 'wpayme_payment', \admin_url( 'edit.php' ) ),
			'gateways'  => \add_query_arg( 'post_type', 'wpayme_gateway', \admin_url( 'edit.php' ) ),
			'settings'  => \add_query_arg( 'page', 'wpayme_pay_settings', \admin_url( 'admin.php' ) ),
		];

		if ( \in_array( 'forms', $modules, true ) ) {
			$pages['forms'] = \add_query_arg( 'post_type', 'wpayme_pay_form', \admin_url( 'edit.php' ) );
		}

		if ( \in_array( 'reports', $modules, true ) ) {
			$pages['reports'] = \add_query_arg( 'page', 'wpayme_pay_reports', \admin_url( 'admin.php' ) );
		}

		// error_log( 'Tour pages sequence: ' . print_r($pages, true) );
		return $pages;
	}

	/**
	 * Get navigation.
	 *
	 * @param string $current Current page.
	 * @return string
	 */
	private function get_navigation( $current ) {
		$content = '<div class="wp-pointer-buttons pp-pointer-buttons">';

		$previous_url = $this->get_previous_page( $current );

		if ( false !== $previous_url ) {
			$content .= \sprintf(
				'<a href="%s" class="button-secondary pp-pointer-button-prev">%s</a>',
				\esc_url( $previous_url ),
				\esc_html__( 'Previous', 'wpayme' )
			);

			$content .= ' ';
		}

		$content .= '<span class="pp-pointer-buttons-right">';

		$next_url = $this->get_next_page( $current );

		if ( false !== $next_url ) {
			// Add timestamp to avoid caching
			$next_url = add_query_arg( '_ts', time(), $next_url );
			
			// Add a tour parameter to force show the tour on the next page
			$next_url = add_query_arg( 'tour', 'continue', $next_url );
			
			$content .= \sprintf(
				'<a href="%s" class="button-primary pp-pointer-button-next">%s</a>',
				\esc_url( $next_url ),
				\esc_html__( 'Next', 'wpayme' )
			);

			$content .= ' ';
		} else {
			// On the last page or when there's no next page
			$dashboard_url = wp_nonce_url(
				add_query_arg( 
					array(
						'page' => 'wpayme',
						'tour_complete' => 'true',
						'_ts' => time(), 
					), 
					admin_url( 'admin.php' ) 
				),
				'wpayme_pay_tour_complete',
				'wpayme_pay_nonce'
			);
			
			$content .= \sprintf(
				'<a href="%s" class="button-primary pp-pointer-button-finish">%s</a>',
				\esc_url( $dashboard_url ),
				\esc_html__( 'Finish Tour', 'wpayme' )
			);

			$content .= ' ';
		}

		$close_url = $this->get_close_url();
		// Add timestamp to avoid caching
		$close_url = add_query_arg( '_ts', time(), $close_url );
		
		$content .= \sprintf(
			'<a href="%s" class="button-secondary pp-pointer-button-close">%s</a>',
			\esc_url( $close_url ),
			\esc_html__( 'Close', 'wpayme' )
		);

		$content .= '</span>';

		$content .= '</div>';

		return $content;
	}

	/**
	 * Get next page URL.
	 *
	 * @param string $current Current page key.
	 * @return string|false
	 */
	private function get_next_page( $current ) {
		$pages = $this->get_pages();
		$keys = array_keys($pages);
		$current_index = array_search($current, $keys, true);
		
		if (false !== $current_index && isset($keys[$current_index + 1])) {
			$next_key = $keys[$current_index + 1];
			return $pages[$next_key];
		}
		
		return false;
	}

	/**
	 * Get previous page URL.
	 *
	 * @param string $current Current page key.
	 * @return string|false
	 */
	private function get_previous_page( $current ) {
		$pages = $this->get_pages();
		$keys = array_keys($pages);
		$current_index = array_search($current, $keys, true);
		
		if (false !== $current_index && $current_index > 0) {
			$prev_key = $keys[$current_index - 1];
			return $pages[$prev_key];
		}
		
		return false;
	}
}
