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

/**
 * Registers the [tukiflow] shortcode.
 */
class TFDC_Shortcode {

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

	/** @var bool Whether the current shortcode render is using native checkout. */
	private $is_shortcode_checkout = false;

	/** @var int Product prepared for the current shortcode checkout request. */
	private $prepared_product_id = 0;

	/** @var int Quantity prepared for the current shortcode checkout request. */
	private $prepared_quantity = 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_shortcode( 'tukiflow', array( $this, 'render' ) );
		add_action( 'wp', array( $this, 'maybe_prepare_shortcode_checkout' ), 6 );
		add_filter( 'woocommerce_is_checkout', array( $this, 'filter_is_checkout' ) );
	}

	/**
	 * Prepare normal product shortcode pages early enough for WooCommerce assets.
	 */
	public function maybe_prepare_shortcode_checkout() {
		if ( is_admin() || wp_doing_ajax() || ! is_singular() ) {
			return;
		}

		if ( class_exists( 'TFDC_Landing_Checkout' ) && TFDC_Landing_Checkout::get_instance()->is_landing_checkout() ) {
			return;
		}

		$post = get_post();
		if ( ! $post || ! has_shortcode( $post->post_content, 'tukiflow' ) ) {
			return;
		}

		$atts = $this->get_first_shortcode_atts( $post->post_content );
		if ( empty( $atts['product_id'] ) ) {
			return;
		}

		$product_id = absint( $atts['product_id'] );
		$quantity   = max( 1, absint( $atts['quantity'] ?? 1 ) );
		$product    = wc_get_product( $product_id );

		if ( ! $this->is_product_available( $product ) ) {
			return;
		}

		$this->is_shortcode_checkout = true;

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

		$this->prepare_cart( $product, $quantity );
	}

	/**
	 * Render the checkout shortcode.
	 *
	 * @param array|string $atts Shortcode attributes.
	 * @return string HTML output.
	 */
	public function render( $atts ) {
		if ( class_exists( 'TFDC_Landing_Checkout' ) && TFDC_Landing_Checkout::get_instance()->is_landing_checkout() ) {
			return TFDC_Landing_Checkout::get_instance()->render_native_checkout();
		}

		$config = shortcode_atts( array(
			'product_id'    => 0,
			'quantity'      => 1,
		), $atts, 'tukiflow' );

		// Sanitize.
		$config['product_id'] = absint( $config['product_id'] );
		$config['quantity']   = max( 1, absint( $config['quantity'] ) );

		if ( ! $config['product_id'] ) {
			return $this->render_shortcode_notice(
				__( 'TukiFlow could not load the checkout form because no product ID was provided.', 'tukiflow-direct-checkout-woocommerce' )
			);
		}

		$product = wc_get_product( $config['product_id'] );

		if ( ! $this->is_product_available( $product ) ) {
			return $this->render_shortcode_notice( $this->get_unavailable_product_message( $config['product_id'] ) );
		}

		$this->is_shortcode_checkout = true;

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

		if (
			(int) $this->prepared_product_id !== (int) $product->get_id()
			|| (int) $this->prepared_quantity !== (int) $config['quantity']
		) {
			$this->prepare_cart( $product, $config['quantity'] );
		}

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

		return do_shortcode( '[woocommerce_checkout]' );
	}

	/**
	 * Treat shortcode renders 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_shortcode_checkout;
	}

	/**
	 * Whether the product can be checked out.
	 *
	 * @param WC_Product|false|null $product Product instance.
	 * @return bool
	 */
	private function is_product_available( $product ) {
		return $product && $product->is_purchasable() && $product->is_in_stock();
	}

	/**
	 * Extract the first [tukiflow] shortcode attributes from post content.
	 *
	 * @param string $content Post content.
	 * @return array
	 */
	private function get_first_shortcode_atts( $content ) {
		$pattern = get_shortcode_regex( array( 'tukiflow' ) );
		if ( ! preg_match_all( '/' . $pattern . '/s', $content, $matches, PREG_SET_ORDER ) ) {
			return array();
		}

		foreach ( $matches as $shortcode ) {
			if ( 'tukiflow' !== $shortcode[2] ) {
				continue;
			}

			$atts = shortcode_parse_atts( $shortcode[3] );
			return is_array( $atts ) ? $atts : array();
		}

		return array();
	}

	/**
	 * Get a user-facing reason when the shortcode product cannot be loaded.
	 *
	 * @param int $product_id WooCommerce product ID.
	 * @return string
	 */
	private function get_unavailable_product_message( $product_id ) {
		$product = wc_get_product( absint( $product_id ) );

		if ( ! $product ) {
			return __( 'TukiFlow could not load the checkout form because the selected product does not exist.', 'tukiflow-direct-checkout-woocommerce' );
		}

		if ( ! $product->is_purchasable() ) {
			return __( 'TukiFlow could not load the checkout form because this product is not purchasable.', 'tukiflow-direct-checkout-woocommerce' );
		}

		if ( ! $product->is_in_stock() ) {
			return __( 'TukiFlow could not load the checkout form because this product is currently out of stock.', 'tukiflow-direct-checkout-woocommerce' );
		}

		return __( 'TukiFlow could not load the checkout form for this product.', 'tukiflow-direct-checkout-woocommerce' );
	}

	/**
	 * Rebuild the WooCommerce cart for the shortcode product.
	 *
	 * @param WC_Product $product  Product to add.
	 * @param int        $quantity Product quantity.
	 */
	private function prepare_cart( $product, $quantity ) {
		$this->ensure_wc_cart_loaded();

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

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

		if ( $product->is_type( 'variation' ) ) {
			WC()->cart->add_to_cart(
				$product->get_parent_id(),
				$quantity,
				$product->get_id(),
				$product->get_variation_attributes()
			);
		} else {
			WC()->cart->add_to_cart( $product->get_id(), $quantity );
		}

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

		$this->prepared_product_id = $product->get_id();
		$this->prepared_quantity   = $quantity;
	}

	/**
	 * Ensure cart dependencies exist before rendering native checkout.
	 */
	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 simple frontend notice for shortcode errors.
	 *
	 * @param string $message Notice message.
	 * @return string
	 */
	private function render_shortcode_notice( $message ) {
		return sprintf(
			'<div class="tfdc-notice tfdc-notice-error">%s</div>',
			esc_html( $message )
		);
	}
}
