<?php
defined( 'ABSPATH' ) || exit;

/**
 * Native WooCommerce checkout landing pages powered by page meta.
 */
class TFDC_Landing_Checkout {

	const META_ENABLED    = '_tfdc_enabled';
	const META_PRODUCTS   = '_tfdc_product_ids';
	const META_QUANTITIES = '_tfdc_quantities';
	const NONCE_ACTION    = 'tfdc_landing_checkout_meta';
	const NONCE_NAME      = 'tfdc_landing_checkout_nonce';
	const OPTION_PAGE_IDS = 'tfdc_landing_checkout_page_ids';

	/** @var self|null */
	private static $instance = null;

	/** @var bool */
	private $is_landing_checkout = false;

	/** @var int */
	private $landing_page_id = 0;

	/**
	 * Get the single instance.
	 *
	 * @return self
	 */
	public static function get_instance() {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Constructor.
	 */
	private function __construct() {
		add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
		add_action( 'save_post_page', array( $this, 'save_page_meta' ), 10, 2 );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
		add_action( 'wp', array( $this, 'maybe_prepare_landing_checkout' ), 5 );
		add_filter( 'woocommerce_is_checkout', array( $this, 'filter_is_checkout' ) );
	}

	/**
	 * Whether the current request is a TukiFlow native checkout landing page.
	 *
	 * @return bool
	 */
	public function is_landing_checkout() {
		return $this->is_landing_checkout;
	}

	/**
	 * Register the page editor metabox.
	 */
	public function add_meta_box() {
		add_meta_box(
			'tfdc-landing-checkout',
			__( 'TukiFlow Checkout', 'tukiflow-direct-checkout-woocommerce' ),
			array( $this, 'render_meta_box' ),
			'page',
			'side',
			'default'
		);
	}

	/**
	 * Enqueue WooCommerce's enhanced product select on page edit screens.
	 *
	 * @param string $hook Current admin page hook.
	 */
	public function enqueue_admin_assets( $hook ) {
		if ( ! in_array( $hook, array( 'post.php', 'post-new.php' ), true ) ) {
			return;
		}

		$screen = get_current_screen();
		if ( ! $screen || 'page' !== $screen->post_type ) {
			return;
		}

		wp_enqueue_script( 'wc-enhanced-select' );
		wp_enqueue_style( 'woocommerce_admin_styles' );
	}

	/**
	 * Render the page settings metabox.
	 *
	 * @param WP_Post $post Page post.
	 */
	public function render_meta_box( $post ) {
		wp_nonce_field( self::NONCE_ACTION, self::NONCE_NAME );

		$enabled    = self::is_enabled_for_page( $post->ID );
		$product_ids = self::get_page_product_ids( $post->ID );
		$quantities = self::get_page_quantities( $post->ID );
		?>
		<p>
			<label>
				<input type="checkbox" name="tfdc_enabled" value="yes" <?php checked( $enabled ); ?> />
				<?php esc_html_e( 'Enable checkout on this page', 'tukiflow-direct-checkout-woocommerce' ); ?>
			</label>
		</p>

		<p>
			<label for="tfdc_product_ids">
				<strong><?php esc_html_e( 'Products', 'tukiflow-direct-checkout-woocommerce' ); ?></strong>
			</label>
			<select
				id="tfdc_product_ids"
				name="tfdc_product_ids[]"
				class="wc-product-search"
				style="width:100%;"
				multiple="multiple"
				data-placeholder="<?php esc_attr_e( 'Search products...', 'tukiflow-direct-checkout-woocommerce' ); ?>"
				data-action="woocommerce_json_search_products_and_variations"
			>
				<?php foreach ( $product_ids as $product_id ) : ?>
					<?php $product = wc_get_product( $product_id ); ?>
					<?php if ( $product ) : ?>
						<option value="<?php echo esc_attr( $product_id ); ?>" selected="selected">
							<?php echo esc_html( wp_strip_all_tags( $product->get_formatted_name() ) ); ?>
						</option>
					<?php endif; ?>
				<?php endforeach; ?>
			</select>
		</p>

		<?php if ( $product_ids ) : ?>
			<div class="tfdc-product-quantities">
				<p><strong><?php esc_html_e( 'Quantities', 'tukiflow-direct-checkout-woocommerce' ); ?></strong></p>
				<?php foreach ( $product_ids as $product_id ) : ?>
					<?php $product = wc_get_product( $product_id ); ?>
					<?php if ( $product ) : ?>
						<p>
							<label for="tfdc_quantity_<?php echo esc_attr( $product_id ); ?>">
								<?php echo esc_html( $product->get_name() ); ?>
							</label>
							<input
								type="number"
								id="tfdc_quantity_<?php echo esc_attr( $product_id ); ?>"
								name="tfdc_quantities[<?php echo esc_attr( $product_id ); ?>]"
								value="<?php echo esc_attr( $quantities[ $product_id ] ?? 1 ); ?>"
								min="1"
								step="1"
								style="width:100%;"
							/>
						</p>
					<?php endif; ?>
				<?php endforeach; ?>
			</div>
		<?php endif; ?>

		<p class="description">
			<?php esc_html_e( 'Place [tukiflow] where the native WooCommerce checkout should appear. The cart is rebuilt from these products on every landing page load.', 'tukiflow-direct-checkout-woocommerce' ); ?>
		</p>
		<?php
	}

	/**
	 * Save page checkout meta.
	 *
	 * @param int     $post_id Page ID.
	 * @param WP_Post $post    Page post.
	 */
	public function save_page_meta( $post_id, $post ) {
		if ( ! isset( $_POST[ self::NONCE_NAME ] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ self::NONCE_NAME ] ) ), self::NONCE_ACTION ) ) {
			return;
		}

		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}

		if ( 'page' !== $post->post_type || ! current_user_can( 'edit_page', $post_id ) ) {
			return;
		}

		$enabled = isset( $_POST['tfdc_enabled'] ) && 'yes' === sanitize_text_field( wp_unslash( $_POST['tfdc_enabled'] ) );
		if ( $enabled ) {
			update_post_meta( $post_id, self::META_ENABLED, 'yes' );
		} else {
			delete_post_meta( $post_id, self::META_ENABLED );
		}
		self::set_page_enabled( $post_id, $enabled );

		$product_ids = array();
		if ( isset( $_POST['tfdc_product_ids'] ) && is_array( $_POST['tfdc_product_ids'] ) ) {
			$product_ids = array_values( array_filter( array_map( 'absint', wp_unslash( $_POST['tfdc_product_ids'] ) ) ) );
			$product_ids = array_values( array_unique( $product_ids ) );
		}

		$quantities = array();
		$raw_quantities = isset( $_POST['tfdc_quantities'] ) && is_array( $_POST['tfdc_quantities'] )
			? array_map( 'absint', wp_unslash( $_POST['tfdc_quantities'] ) )
			: array();

		foreach ( $product_ids as $product_id ) {
			$quantities[ $product_id ] = max( 1, absint( $raw_quantities[ $product_id ] ?? 1 ) );
		}

		update_post_meta( $post_id, self::META_PRODUCTS, $product_ids );
		update_post_meta( $post_id, self::META_QUANTITIES, $quantities );
	}

	/**
	 * Prepare the cart before the native checkout shortcode renders.
	 */
	public function maybe_prepare_landing_checkout() {
		if ( is_admin() || wp_doing_ajax() || ! is_singular( 'page' ) ) {
			return;
		}

		$page_id = get_queried_object_id();
		if ( ! $page_id || ! self::is_enabled_for_page( $page_id ) ) {
			return;
		}

		$this->is_landing_checkout = true;
		$this->landing_page_id     = $page_id;

		if ( function_exists( 'is_wc_endpoint_url' ) && ( is_wc_endpoint_url( 'order-received' ) || is_wc_endpoint_url( 'order-pay' ) ) ) {
			return;
		}

		$product_ids = self::get_page_product_ids( $page_id );
		if ( empty( $product_ids ) ) {
			return;
		}

		$this->ensure_wc_cart_loaded();

		if ( ! WC()->cart ) {
			return;
		}

		$quantities = self::get_page_quantities( $page_id );

		WC()->cart->empty_cart();

		foreach ( $product_ids as $product_id ) {
			$product = wc_get_product( $product_id );
			if ( ! $product || ! $product->is_purchasable() || ! $product->is_in_stock() ) {
				continue;
			}

			if ( $product->is_type( 'variation' ) ) {
				WC()->cart->add_to_cart(
					$product->get_parent_id(),
					$quantities[ $product_id ] ?? 1,
					$product_id,
					$product->get_variation_attributes()
				);
				continue;
			}

			WC()->cart->add_to_cart( $product_id, $quantities[ $product_id ] ?? 1 );
		}

		WC()->cart->calculate_totals();
	}

	/**
	 * Treat marked landing pages as checkout pages for WooCommerce conditionals.
	 *
	 * @param bool $is_checkout Current checkout state.
	 * @return bool
	 */
	public function filter_is_checkout( $is_checkout ) {
		return $is_checkout || $this->is_landing_checkout;
	}

	/**
	 * Render native WooCommerce checkout for the current landing page.
	 *
	 * @return string
	 */
	public function render_native_checkout() {
		if ( ! $this->is_landing_checkout ) {
			return '';
		}

		$product_ids = self::get_page_product_ids( $this->landing_page_id );
		if ( empty( $product_ids ) ) {
			return $this->render_notice( __( 'TukiFlow checkout is enabled, but no products are selected for this page.', 'tukiflow-direct-checkout-woocommerce' ) );
		}

		if ( ! WC()->cart || WC()->cart->is_empty() ) {
			return $this->render_notice( __( 'TukiFlow could not prepare the checkout cart for this page.', 'tukiflow-direct-checkout-woocommerce' ) );
		}

		return do_shortcode( '[woocommerce_checkout]' );
	}

	/**
	 * Whether a page is configured as a TukiFlow checkout landing page.
	 *
	 * @param int $page_id Page ID.
	 * @return bool
	 */
	public static function is_enabled_for_page( $page_id ) {
		return 'yes' === get_post_meta( absint( $page_id ), self::META_ENABLED, true );
	}

	/**
	 * Get enabled landing page IDs.
	 *
	 * @return int[]
	 */
	public static function get_enabled_page_ids() {
		$page_ids = get_option( self::OPTION_PAGE_IDS, null );
		if ( is_array( $page_ids ) ) {
			return array_values( array_filter( array_map( 'absint', $page_ids ) ) );
		}

		$page_ids = array();
		$pages    = get_pages(
			array(
				'post_status' => array( 'publish', 'draft', 'pending', 'private', 'future' ),
			)
		);

		foreach ( $pages as $page ) {
			if ( self::is_enabled_for_page( $page->ID ) ) {
				$page_ids[] = absint( $page->ID );
			}
		}

		update_option( self::OPTION_PAGE_IDS, $page_ids, false );

		return $page_ids;
	}

	/**
	 * Keep the landing page ID index in sync.
	 *
	 * @param int  $page_id Page ID.
	 * @param bool $enabled Whether checkout is enabled.
	 */
	public static function set_page_enabled( $page_id, $enabled ) {
		$page_id  = absint( $page_id );
		$page_ids = self::get_enabled_page_ids();

		if ( $enabled ) {
			$page_ids[] = $page_id;
		} else {
			$page_ids = array_diff( $page_ids, array( $page_id ) );
		}

		update_option( self::OPTION_PAGE_IDS, array_values( array_unique( array_filter( array_map( 'absint', $page_ids ) ) ) ), false );
	}

	/**
	 * Get selected product IDs for a page.
	 *
	 * @param int $page_id Page ID.
	 * @return int[]
	 */
	public static function get_page_product_ids( $page_id ) {
		$product_ids = get_post_meta( absint( $page_id ), self::META_PRODUCTS, true );
		if ( ! is_array( $product_ids ) ) {
			return array();
		}

		return array_values( array_filter( array_map( 'absint', $product_ids ) ) );
	}

	/**
	 * Get selected product quantities for a page.
	 *
	 * @param int $page_id Page ID.
	 * @return array<int,int>
	 */
	public static function get_page_quantities( $page_id ) {
		$quantities = get_post_meta( absint( $page_id ), self::META_QUANTITIES, true );
		if ( ! is_array( $quantities ) ) {
			return array();
		}

		$clean = array();
		foreach ( $quantities as $product_id => $quantity ) {
			$clean[ absint( $product_id ) ] = max( 1, absint( $quantity ) );
		}

		return $clean;
	}

	/**
	 * Ensure cart dependencies exist in early page lifecycle.
	 */
	private function ensure_wc_cart_loaded() {
		if ( is_null( WC()->session ) ) {
			WC()->session = new WC_Session_Handler();
			WC()->session->init();
		}

		if ( is_null( WC()->customer ) ) {
			WC()->customer = new WC_Customer( get_current_user_id(), true );
		}

		if ( is_null( WC()->cart ) ) {
			WC()->cart = new WC_Cart();
		}
	}

	/**
	 * Render a frontend notice.
	 *
	 * @param string $message Notice message.
	 * @return string
	 */
	private function render_notice( $message ) {
		return sprintf(
			'<div class="tfdc-notice tfdc-notice-error">%s</div>',
			esc_html( $message )
		);
	}
}
