<?php

namespace PaymentPage;

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

class AdminController {

	/**
	 * @var null|AdminController;
	 */
	protected static $_instance = null;

	/**
	 * @return AdminController
	 */
	public static function instance(): AdminController {
		if ( self::$_instance === null ) {
			self::$_instance = new self();
		}

		return self::$_instance;
	}

	private $_action_map = array(
		'force-db-table-integrity' => '_action_force_db_table_integrity',
	);

	public function setup() {
		$latest_notification = API\Notification::instance()->get_latest_notification();

		if ( $latest_notification !== null && isset( $latest_notification['id'] ) ) {
			add_action( 'admin_notices', array( $this, '_admin_notice' ) );
		}

		if ( get_transient( \PaymentPage\Stripe\ConnectWebhookProvisioner::FAILURE_TRANSIENT ) ) {
			add_action( 'admin_notices', array( $this, '_stripe_webhook_provision_notice' ) );
		}

		add_action( 'admin_menu', array( $this, '_register_menu' ) );
		add_filter( 'display_post_states', array( $this, '_post_states' ), 1000, 2 );

		if ( Request::instance()->is_request_type( 'admin' ) ) {
			add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ), 5 );
		}

		if ( Settings::instance()->get_flag( 'configuration-setup-rules-flushed' ) === false ) {
			add_action( 'init', array( $this, '_setup_rules_flush_action_init' ), 7 );
		}

		if ( isset( $_GET[ PAYMENT_PAGE_PREFIX . '-action' ] ) ) {
			$action_key = sanitize_text_field( wp_unslash( $_GET[ PAYMENT_PAGE_PREFIX . '-action' ] ) );
			if ( isset( $this->_action_map[ $action_key ] ) ) {
				add_action( 'init', array( $this, $this->_action_map[ $action_key ] ) );
			}
		}
	}

	public function _admin_notice() {
		if ( ! current_user_can( PAYMENT_PAGE_ADMIN_CAP ) ) {
			return;
		}

		$latest_notification = API\Notification::instance()->get_latest_notification();

		if ( intval( get_user_meta( get_current_user_id(), PAYMENT_PAGE_ALIAS . '_last_notification_id', true ) ) === intval( $latest_notification['id'] ) ) {
			return;
		}

		// (Audit F008) Dropped data: protocol from the allowed-protocols list. The
		// Notification API at api.paymentpageplugin.com is first-party but represents a
		// supply-chain single-point-of-failure: if compromised, an attacker could push a
		// notification with embedded data:image/svg+xml;base64,... that renders inside the
		// admin <img> context with executable JavaScript (Firefox/Safari historically allow
		// script-in-SVG in some <img> contexts). With data: removed, the worst-case payload
		// is an attacker-controlled hyperlink (still bounded by wp_kses + admin trust).
		$protocols = wp_allowed_protocols();

		$content = wp_kses( $latest_notification['content'], payment_page_content_allowed_html_tags(), $protocols );

		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $content already sanitized by wp_kses() above against the default allowed-protocols list (1.5.0 dropped the data: protocol allowance per Audit F008).
		echo '<div id="payment-page-notification-container" class="notice notice-info is-dismissible">
            <h2>' . esc_html( $latest_notification['title'] ) . '</h2>
            ' . $content . '
          </div>';
	}

	public function _stripe_webhook_provision_notice() {
		if ( ! current_user_can( PAYMENT_PAGE_ADMIN_CAP ) ) {
			return;
		}

		$payload = get_transient( \PaymentPage\Stripe\ConnectWebhookProvisioner::FAILURE_TRANSIENT );
		if ( ! is_array( $payload ) ) {
			return;
		}

		$reason = isset( $payload['reason'] ) ? (string) $payload['reason'] : 'unknown';

		$headline = ( $reason === 'permission' || $reason === 'authentication' )
			? __( 'Payment Page could not auto-create a Stripe webhook on your connected account because the OAuth token lacks webhook-write permission. Your connection is otherwise active.', 'payment-page' )
			: __( 'Payment Page could not auto-create the Stripe webhook on your connected account.', 'payment-page' );

		echo '<div class="notice notice-warning is-dismissible"><p><strong>' . esc_html__( 'Payment Page — Stripe webhook auto-provision skipped', 'payment-page' ) . '</strong></p><p>' . esc_html( $headline ) . ' ' . esc_html__( 'You can paste the webhook signing secret manually from your Stripe dashboard to enable payment notifications.', 'payment-page' ) . '</p></div>';
	}

	public function _register_menu() {
		add_menu_page(
			PAYMENT_PAGE_NAME,
			PAYMENT_PAGE_NAME,
			PAYMENT_PAGE_ADMIN_CAP,
			PAYMENT_PAGE_MENU_SLUG,
			false,
			'data:image/svg+xml;base64,' . base64_encode( file_get_contents( PAYMENT_PAGE_BASE_PATH . '/interface/img/icon.svg' ) ),
			100
		);

    payment_page_admin_register_menu(
      PAYMENT_PAGE_NAME,
      __( "Payment Gateways", 'payment-page' ),
      PAYMENT_PAGE_ADMIN_CAP,
      PAYMENT_PAGE_MENU_SLUG,
      array( $this, '_display_dashboard' ),
      5
    );
	}

	public function _post_states( $states, $post ) {
		if ( ! class_exists( '\Elementor\Plugin' ) ) {
			return $states;
		}

		$elementor_document = \Elementor\Plugin::instance()->documents->get( $post->ID );

		if ( ! $elementor_document->is_built_with_elementor() ) {
			return $states;
		}

		$test = json_encode( $elementor_document->get_elements_data() );

		if ( strpos( $test, '"widgetType":"payment-form"' ) !== false ) {
			$states[] = PAYMENT_PAGE_NAME;
		}

		return $states;
	}

  public function admin_enqueue_scripts() {
    payment_page_register_universal_interface();

    if( ( get_current_screen()->id ?? null ) === 'pp_payment_form' ) {
      wp_enqueue_media();
      wp_enqueue_script( 'media-grid' );
      wp_enqueue_script( 'media' );
      wp_enqueue_style( 'media');
      wp_enqueue_script( 'media-upload' );
      wp_enqueue_script( 'thickbox' );
    }
  }

	public function _display_dashboard() {
		Template::load_template( 'component-dashboard.php' );
	}

	public function _setup_rules_flush_action_init() {
		if ( Request::instance()->is_request_type( 'ajax' ) ) {
			return;
		}

		_payment_page_refresh_rewrite_rules_and_capabilities();

		Settings::instance()->update(
			array(
				'configuration-setup-rules-flushed' => 1,
			)
		);

		add_action(
			'init',
			function () {
				payment_page_redirect( Request::instance()->get_current_url() );
				exit;
			},
			500
		);
	}

	public function _action_force_db_table_integrity() {
		if ( ! current_user_can( PAYMENT_PAGE_ADMIN_CAP ) ) {
			exit( esc_html__( 'Invalid Request', 'payment-page' ) );
		}

		// (Audit F011) Require a valid nonce. Previously cap-gated only — but a CSRF
		// auto-submit could trigger this handler in an active admin's session and run
		// ALTER TABLE / dbDelta operations mid-migration. The operations are idempotent
		// but a CSRF during a real migration could produce duplicate-column errors or
		// partial schema state. The Site Health page's "Fix Table Integrity" link is
		// the canonical trigger; it now emits the nonce alongside the action param.
		check_admin_referer( 'payment_page_force_db_table_integrity' );

		$response = Migration::instance()->fix_table_structure( true );

		if ( is_array( $response ) ) {
			payment_page_debug_dump( base64_decode( $response['table_query_b64'] ) );

			exit( esc_html__( 'Did not manage to fix Table Structure', 'payment-page' ) );
		}

		payment_page_redirect( get_admin_url( null, 'site-health.php' ), 302 );
		exit;
	}

}
