<?php

namespace PaymentPage;

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

use WP_Query;

class Controller {

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

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

		return self::$_instance;
	}

	public function __construct() {
		// (Perf P4 — scoped) Lazy-load only files that are NEVER consumed by frontend
		// code. The other 5 _functions files contain helpers reached from the rendering
		// path:
		//   - general.php / utilities.php / utilities-css-render.php — frontend essentials
		//   - administration-payment-form.php — FieldMap + PricingPlans (frontend renderers)
		//     call payment_page_administration_payment_form_field_payment_frequencies(),
		//     _currencies(), _group_fields_typography(), _group_fields_border()
		//   - elementor.php — PaymentForm.php frontend renderer calls
		//     payment_page_elementor_control_pricing_frequencies()
		// administration.php is the only file that's genuinely admin-only — REST handlers
		// + dashboard glue. Lazy-loading it under is_admin() is the safe P4 scope.
		require_once PAYMENT_PAGE_BASE_PATH . '/app/_functions/general.php';
		require_once PAYMENT_PAGE_BASE_PATH . '/app/_functions/utilities.php';
		require_once PAYMENT_PAGE_BASE_PATH . '/app/_functions/utilities-css-render.php';
		require_once PAYMENT_PAGE_BASE_PATH . '/app/_functions/administration-payment-form.php';
		require_once PAYMENT_PAGE_BASE_PATH . '/app/_functions/elementor.php';

		// (1.5.1 hotfix) The 1.5.0 guard was `is_admin()` only, but `administration.php`
		// is also reached by REST handlers + AJAX (the very comment block above admits
		// this). REST requests never set `is_admin()`, so when a merchant completed
		// Stripe Connect and the callback at `/wp-json/payment-page/v1/payment-gateway/
		// connect-callback` ran `save_master_credentials_response()` → background payment
		// methods setup, it hit a fatal `Call to undefined function
		// _payment_page_stripe_payment_methods_background_setup()`. Same root cause
		// shape as the REST cookie-auth bug: a 1.5.0 hardening pass guarded too narrowly
		// for the actual surfaces that need the resource. Fix: also load under REST + AJAX.
		// `REST_REQUEST` isn't defined yet at plugin load, so we sniff the URI directly
		// (covers both `/wp-json/...` and `?rest_route=...` shapes WP supports).
		$is_rest_request = ! empty( $_SERVER['REQUEST_URI'] ) && (
			false !== strpos( wp_unslash( $_SERVER['REQUEST_URI'] ), '/wp-json/' )
			|| false !== strpos( wp_unslash( $_SERVER['REQUEST_URI'] ), 'rest_route=' )
		);

		if ( is_admin() || $is_rest_request || wp_doing_ajax() ) {
			require_once PAYMENT_PAGE_BASE_PATH . '/app/_functions/administration.php';
		}
	}

	public function setup() {
		if ( ! defined( 'PAYMENT_PAGE_EXTERNAL_API_URL' ) ) {
			define( 'PAYMENT_PAGE_EXTERNAL_API_URL', 'https://api.paymentpageplugin.com/wp-json/payment-page-api/v1/' );
		}

		if ( ! defined( 'NOTIFICATION_SYSTEM_API_URL' ) ) {
			define( 'PAYMENT_PAGE_NOTIFICATION_API_URL', 'https://api.paymentpageplugin.com/wp-json/notification-system-api/v1/' );
		} else {
			define( 'PAYMENT_PAGE_NOTIFICATION_API_URL', NOTIFICATION_SYSTEM_API_URL );
		}

		if ( ! defined( 'PAYMENT_PAGE_FEATURES_API_URL' ) ) {
			define( 'PAYMENT_PAGE_FEATURES_API_URL', 'https://api.paymentpageplugin.com/wp-json/features-api/v1/' );
		}

		// (Perf P1) Conditional frontend enqueue — only register the universal interface
		// on requests that actually render a payment form. Previously the interface was
		// enqueued on EVERY public page (~hundreds of KB JS + CSS + inline localized blob),
		// hurting LCP/TBT site-wide on non-payment pages. Detection runs at template_redirect
		// (post __construct has run, query is resolved, but render hasn't started yet).
		add_action( 'template_redirect', array( $this, '_maybe_register_universal_interface' ), 5 );
		add_action( 'admin_bar_menu', array( $this, '_admin_bar_menu' ), 999 );
		add_filter( 'template_include', array( $this, '_single_payment_form_template' ) );

		ShortCodes::register();

		if ( PAYMENT_PAGE_STRIPE_APPLE_PAY_VERIFICATION_TYPE_AUTO === Settings::instance()->get( 'stripe_apple_pay_verification_type_test' )
			 || PAYMENT_PAGE_STRIPE_APPLE_PAY_VERIFICATION_TYPE_AUTO === Settings::instance()->get( 'stripe_apple_pay_verification_type_live' ) ) {
			add_action( 'init', array( $this, '_maybe_stripe_apple_pay_domain_association' ), - 1000 );
		}
	}

	public function _admin_bar_menu( $admin_bar ) {
		if ( ! current_user_can( PAYMENT_PAGE_ADMIN_CAP ) ) {
			return;
		}

		$map = array(
			'live' => 0,
			'test' => 0,
			'none' => 0,
		);

		$integrations = array(
			'stripe' => PaymentGateway::get_integration_from_settings( 'stripe' ),
			'paypal' => PaymentGateway::get_integration_from_settings( 'paypal' ),
		);

		foreach ( $integrations as $integration ) {
			if ( ! $integration->is_configured() ) {
				$map['none'] ++;
				continue;
			}

			if ( $integration->is_live() ) {
				$map['live'] ++;
			} else {
				$map['test'] ++;
			}
		}

		if ( $map['live'] === 0 && $map['test'] === 0 ) {
			return;
		}

		$admin_bar->add_node(
			array(
				'parent' => 'top-secondary',
				'id'     => PAYMENT_PAGE_ALIAS,
				/* translators: %s: payment mode (Live, Test, or Mixed) */
				'title'  => sprintf( __( 'Payment Page %s Mode', 'payment-page' ), ( $map['live'] > 0 && $map['test'] > 0 ? 'Mixed' : ( $map['test'] === 0 ? 'Live' : 'Test' ) ) ),
				'href'   => esc_url( admin_url( 'admin.php?page=' . PAYMENT_PAGE_MENU_SLUG ) ) . '#payment-gateways',
				'meta'   => array(
					'class' => 'payment-page-top-bar-item ' . ( $map['live'] > 0 && $map['test'] > 0 ? 'is-mixed' : ( $map['test'] === 0 ? 'is-live' : 'is-test' ) ),
				),
			)
		);

		foreach ( $integrations as $integration_alias => $integration ) {
			if ( ! $integration->is_configured() ) {
				return;
			}

			$admin_bar->add_node(
				array(
					'parent' => PAYMENT_PAGE_ALIAS,
					'id'     => PAYMENT_PAGE_ALIAS . '_' . $integration_alias,
					'title'  => $integration->get_name() . ' ' . ( $integration->is_live() ? 'Live' : 'Test' ),
					'href'   => esc_url( admin_url( 'admin.php?page=' . PAYMENT_PAGE_MENU_SLUG ) ) . '#payment-gateways',
					'meta'   => array(
						'class' => 'payment-page-child-bar-item ' . ( $integration->is_live() ? 'is-live' : 'is-test' ),
					),
				)
			);
		}
	}

	/**
	 * (Perf P1) Inspect the current request and, only if a payment form will render,
	 * register the universal interface enqueue. Detection covers:
	 *   1. pp_payment_form singular (theme template loader)
	 *   2. [payment-page-payment-form] or [payment-page-success-details] shortcode in
	 *      the queried post content (or any post in the queried set)
	 *   3. Elementor payment-form widget present in the queried post's Elementor data
	 *
	 * If any detector matches, hook payment_page_register_universal_interface to
	 * wp_enqueue_scripts at priority 5 (the same priority the legacy unconditional
	 * hook used). If no detector matches, no enqueue — PP's frontend footprint is
	 * absent from non-payment pages entirely.
	 *
	 * Devs can opt back into the always-load behavior with:
	 *   add_filter( 'payment_page_force_universal_interface', '__return_true' );
	 * (useful for popup-form mounts on pages where content detection can't reach.)
	 */
	public function _maybe_register_universal_interface() {
		$should_enqueue = apply_filters( 'payment_page_force_universal_interface', false );

		if ( ! $should_enqueue && is_singular( PAYMENT_PAGE_POST_TYPE_PAYMENT_FORM ) ) {
			$should_enqueue = true;
		}

		if ( ! $should_enqueue ) {
			$post = get_post();
			if ( $post instanceof \WP_Post ) {
				$content = (string) $post->post_content;

				if ( has_shortcode( $content, 'payment-page-payment-form' )
					|| has_shortcode( $content, 'payment-page-success-details' ) ) {
					$should_enqueue = true;
				}

				if ( ! $should_enqueue ) {
					$elementor_data = get_post_meta( $post->ID, '_elementor_data', true );
					if ( is_string( $elementor_data ) && strpos( $elementor_data, '"widgetType":"payment-form"' ) !== false ) {
						$should_enqueue = true;
					}
				}
			}
		}

		if ( ! $should_enqueue ) {
			return;
		}

		add_action( 'wp_enqueue_scripts', 'payment_page_register_universal_interface', 5 );
	}

	public function _single_payment_form_template( $template ) {
		if ( ! is_singular( PAYMENT_PAGE_POST_TYPE_PAYMENT_FORM ) ) {
			return $template;
		}

		$custom_template = PAYMENT_PAGE_BASE_PATH . '/templates/single-pp_payment_form.php';

		if ( file_exists( $custom_template ) ) {
			return $custom_template;
		}

		return $template;
	}

	public function _maybe_stripe_apple_pay_domain_association() {
		$current_url = Request::instance()->get_current_url();

		if ( $current_url !== rtrim( get_site_url(), '/' ) . '/.well-known/apple-developer-merchantid-domain-association' ) {
			return;
		}

		$file = PAYMENT_PAGE_BASE_PATH . '/lib/apple-developer-merchantid-domain-association';

		header( 'Content-Description: File Transfer' );
		header( 'Content-Type: application/octet-stream' );
		header( 'Content-Disposition: attachment; filename="' . basename( $file ) . '"' );
		header( 'Expires: 0' );
		header( 'Cache-Control: must-revalidate' );
		header( 'Pragma: public' );
		header( 'Content-Length: ' . filesize( $file ) );
		readfile( $file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Streaming Apple Pay verification file to browser
		exit;
	}

}
