<?php

declare( strict_types=1 );

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

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching

/**
 * Main plugin singleton. Bootstraps all modules and registers hooks.
 */
final class Playard {

	private static ?Playard $instance = null;

	public static function instance(): self {
		if ( null === self::$instance ) {
			self::$instance = new self();
			self::$instance->init();
		}
		return self::$instance;
	}

	private function __construct() {}
	private function __clone() {}

	private function init(): void {
		do_action( 'playard_before_init' );

		$this->load_dependencies();
		$this->init_hooks();

		do_action( 'playard_init',   $this );
		do_action( 'playard_loaded', $this );
	}

	private function load_dependencies(): void {
		require_once PLAYARD_PATH . 'includes/Modules/class-playard-facility.php';
		require_once PLAYARD_PATH . 'includes/Modules/class-playard-field.php';
		require_once PLAYARD_PATH . 'includes/Modules/class-playard-booking.php';
		require_once PLAYARD_PATH . 'includes/Modules/class-playard-payment.php';
		require_once PLAYARD_PATH . 'includes/Modules/class-playard-slot.php';
		require_once PLAYARD_PATH . 'includes/Modules/class-playard-customer.php';
		require_once PLAYARD_PATH . 'includes/Modules/class-playard-notification.php';
		require_once PLAYARD_PATH . 'includes/Modules/class-playard-report.php';
		require_once PLAYARD_PATH . 'includes/class-playard-shortcodes.php';
		require_once PLAYARD_PATH . 'includes/class-playard-blocks.php';
		require_once PLAYARD_PATH . 'api/class-playard-api-auth.php';
		require_once PLAYARD_PATH . 'api/class-playard-api-admin.php';
		require_once PLAYARD_PATH . 'api/class-playard-api-fields.php';
		require_once PLAYARD_PATH . 'api/class-playard-api-bookings.php';
		require_once PLAYARD_PATH . 'api/class-playard-api-payments.php';
		require_once PLAYARD_PATH . 'api/class-playard-api-availability.php';
		require_once PLAYARD_PATH . 'api/class-playard-api-customers.php';
		require_once PLAYARD_PATH . 'admin/class-playard-admin.php';

		do_action( 'playard_load_dependencies' );
	}

	private function init_hooks(): void {
		// Admin
		( new Playard_Admin() )->init();

		// REST API
		add_action( 'rest_api_init', [ $this, 'register_routes' ] );

		// Roles & capabilities — run on every init so existing installs get updated without reactivation
		add_action( 'init', [ 'Playard_Install', 'setup_roles' ] );

		// Frontend
		add_action( 'init',             [ $this, 'register_shortcodes' ] );
		add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_frontend_assets' ] );

		// Gutenberg block
		( new Playard_Blocks() )->register();

		// Cron
		add_action( 'playard_cleanup_stale_bookings',   [ 'Playard_Slot',    'cleanup_stale_bookings'     ] );
		add_action( 'playard_cleanup_otp',              [ 'Playard_Slot',    'cleanup_expired_otp'        ] );
		add_action( 'playard_auto_complete_bookings',   [ 'Playard_Booking', 'auto_complete_past_bookings' ] );

		// Customer stats — increment after every confirmed booking
		add_action( 'playard_booking_created',          [ $this, 'update_customer_stats' ] );
		add_action( 'playard_booking_confirmed',         [ $this, 'update_customer_stats' ] );
		// Walk-in Stripe: stats are not incremented at booking creation (no playard_booking_confirmed fires).
		// They increment here when the customer completes payment and the webhook fires.
		add_action( 'playard_stripe_payment_received',  [ $this, 'update_customer_stats' ] );

		// Notifications — constructor self-registers all email hooks
		new Playard_Notification();

		// Cancel page — intercept ?playard_action=cancel URLs from email links
		add_action( 'template_redirect', [ $this, 'handle_cancel_request' ] );

	}

	public function handle_cancel_request(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- cancel link from email; nonce not applicable
		if ( empty( $_GET['playard_action'] ) || $_GET['playard_action'] !== 'cancel' ) {
			return;
		}

		$ref   = sanitize_text_field( wp_unslash( (string) ( $_GET['ref']   ?? '' ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$token = sanitize_text_field( wp_unslash( (string) ( $_GET['token'] ?? '' ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		if ( empty( $ref ) || empty( $token ) ) {
			wp_die( esc_html__( 'Invalid cancellation link.', 'playard' ) );
		}

		global $wpdb;
		$booking = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT id, booking_ref, customer_id FROM {$wpdb->prefix}playard_bookings WHERE booking_ref = %s LIMIT 1",
				$ref
			)
		);

		if ( ! $booking ) {
			wp_die( esc_html__( 'Booking not found.', 'playard' ) );
		}

		// Verify against the random transient token (set when confirmation email is sent).
		// Fall back to the legacy deterministic token for emails sent before this update.
		$stored_token = get_transient( 'playard_cancel_' . $booking->booking_ref );
		if ( $stored_token ) {
			if ( ! hash_equals( (string) $stored_token, $token ) ) {
				wp_die( esc_html__( 'Invalid cancellation link.', 'playard' ) );
			}
		} else {
			$legacy_token = wp_hash( $booking->booking_ref . $booking->customer_id );
			if ( ! hash_equals( $legacy_token, $token ) ) {
				wp_die( esc_html__( 'Invalid cancellation link.', 'playard' ) );
			}
		}

		include PLAYARD_PATH . 'public/views/cancel-booking.php';
		exit;
	}

	public function update_customer_stats( int $booking_id ): void {
		global $wpdb;

		$row = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT customer_id, amount_total FROM {$wpdb->prefix}playard_bookings WHERE id = %d LIMIT 1",
				$booking_id
			)
		);

		if ( $row && (int) $row->customer_id > 0 ) {
			( new Playard_Customer() )->increment_stats( (int) $row->customer_id, (float) $row->amount_total );
		}
	}

	public function register_shortcodes(): void {
		add_shortcode( 'playard',          [ $this, 'render_booking_shortcode'   ] );
		add_shortcode( 'playard_bookings', [ $this, 'render_bookings_shortcode'  ] );
		do_action( 'playard_register_shortcodes' );
	}

	public function render_booking_shortcode( array $atts ): string {
		$atts = shortcode_atts(
			[
				'field'    => '',      // empty = show all fields
				'field_id' => '',      // legacy alias
				'theme'    => 'light', // future: dark mode
			],
			$atts,
			'playard'
		);

		// Support both [playard field="1"] and legacy [playard field_id="1"]
		if ( $atts['field'] === '' && $atts['field_id'] !== '' ) {
			$atts['field'] = $atts['field_id'];
		}

		return ( new Playard_Shortcodes() )->render_booking_widget( $atts );
	}

	public function render_bookings_shortcode( array $atts ): string {
		return ( new Playard_Shortcodes() )->render_my_bookings();
	}

	public function register_routes(): void {
		$facility = new Playard_Facility();
		$field    = new Playard_Field();
		$payment  = new Playard_Payment();
		$booking  = new Playard_Booking();
		$slot     = new Playard_Slot();
		$customer = new Playard_Customer();

		( new Playard_API_Auth( $customer ) )->register_routes();
		( new Playard_API_Admin( $facility, $field, $payment ) )->register_routes();
		( new Playard_API_Fields( $field ) )->register_routes();
		( new Playard_API_Availability( $slot, $field ) )->register_routes();
		( new Playard_API_Bookings( $booking, $slot, $customer, $payment ) )->register_routes();
		( new Playard_API_Payments( $payment ) )->register_routes();
		( new Playard_API_Customers( $customer ) )->register_routes();

		do_action( 'playard_register_routes' );
	}

	public function enqueue_frontend_assets(): void {
		if ( ! $this->current_page_has_playard() ) {
			return;
		}

		$css_path = PLAYARD_PATH . 'assets/css/playard-frontend.css';
		$js_path  = PLAYARD_PATH . 'assets/js/playard-frontend.js';

		if ( file_exists( $css_path ) ) {
			wp_enqueue_style(
				'playard-frontend',
				PLAYARD_URL . 'assets/css/playard-frontend.css',
				[],
				(string) filemtime( $css_path )
			);
		}

		if ( file_exists( $js_path ) ) {
			wp_enqueue_script(
				'playard-frontend',
				PLAYARD_URL . 'assets/js/playard-frontend.js',
				[],
				(string) filemtime( $js_path ),
				true
			);

			wp_localize_script(
				'playard-frontend',
				'playard_public',
				apply_filters( 'playard_frontend_script_data', ( static function (): array {
					$facility          = playard_get_facility();
					$currency_code     = $facility ? (string) $facility->currency : 'USD';
					$currency_symbol   = playard_get_currency_symbol( $currency_code );
					$currency_position = (string) apply_filters( 'playard_currency_position', 'before', $currency_code );

					return [
						'rest_url'          => esc_url_raw( rest_url( 'playard/v1/' ) ),
						'nonce'             => wp_create_nonce( 'wp_rest' ),
						'version'           => PLAYARD_VERSION,
						'currency_symbol'   => $currency_symbol,
						'currency_position' => $currency_position,
					];
				} )() )
			);
		}

		do_action( 'playard_enqueue_frontend_assets' );
	}

	private function current_page_has_playard(): bool {
		global $post;

		if ( ! is_a( $post, 'WP_Post' ) ) {
			return false;
		}

		$has_block = false;
		foreach ( Playard_Blocks::BLOCKS as $slug ) {
			if ( has_block( 'playard/' . $slug, $post ) ) {
				$has_block = true;
				break;
			}
		}

		return has_shortcode( $post->post_content, 'playard' )
			|| has_shortcode( $post->post_content, 'playard_bookings' )
			|| $has_block;
	}
}
