<?php
/**
 * Checkout validation for minimum order amounts
 *
 * @package FoodOrd
 */

defined( 'ABSPATH' ) || exit;

/**
 * Class Foodord_Checkout_Validator
 *
 * Handles minimum order amount validation for checkout page
 */
class Foodord_Checkout_Validator {

	/**
	 * Initialize the class and set its properties.
	 */
	public function init() {
		// Add hooks for checkout validation.
		add_action( 'woocommerce_check_cart_items', array( $this, 'validate_minimum_order_amount' ) );
		add_action( 'woocommerce_checkout_process', array( $this, 'validate_checkout_minimum_amount' ) );
		add_filter( 'woocommerce_order_button_html', array( $this, 'modify_place_order_button' ), 10, 1 );
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_checkout_scripts' ) );
		add_action( 'woocommerce_before_checkout_form', array( $this, 'display_minimum_order_notice' ), 5 );

		// Block-based checkout support.
		add_action( 'woocommerce_blocks_checkout_block_registration', array( $this, 'register_checkout_blocks' ) );
		add_filter( 'woocommerce_store_api_checkout_update_order_from_request', array( $this, 'validate_block_checkout' ), 10, 2 );
		// Use a more reliable hook for block scripts.
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_block_checkout_scripts' ), 100 );
	}

	/**
	 * Get the minimum order amount based on delivery location
	 *
	 * @return float|false Minimum order amount or false if not set
	 */
	private function get_minimum_order_amount() {
		// Table ordering (dine-in) should not enforce delivery minimum amounts.
		if ( $this->is_table_order_context() ) {
			return false;
		}

		// Check if delivery is selected.
		$order_mode = 'delivery';
		if ( function_exists( 'foodord_get_order_mode' ) ) {
			$order_mode = foodord_get_order_mode();
		} elseif ( function_exists( 'WC' ) && WC()->session ) {
			$order_mode = (string) WC()->session->get( 'foodord_order_mode', 'delivery' );
		}

		// If pickup is selected, no minimum order amount.
		if ( 'pickup' === $order_mode ) {
			return false;
		}

		// Get delivery locations settings.
		$delivery_locations = get_option( 'foodord_delivery_locations', array() );
		$configured_mode    = class_exists( 'Foodord_Location_Service' ) ? Foodord_Location_Service::get_delivery_mode() : 'postal';

		// Get customer's city/postal from customer data.
		$customer_city        = '';
		$customer_postal_code = '';
		if ( WC()->customer ) {
			$customer_city        = WC()->customer->get_shipping_city();
			$customer_postal_code = WC()->customer->get_shipping_postcode();
			if ( empty( $customer_city ) ) {
				$customer_city = WC()->customer->get_billing_city();
			}
			if ( empty( $customer_postal_code ) ) {
				$customer_postal_code = WC()->customer->get_billing_postcode();
			}
		}

		$session_minimum = null;
		$session_allowed = false;
		// Pull persisted selection from custom session keys if present.
		if ( WC()->session ) {
			$session_city        = WC()->session->get( class_exists( 'Foodord_Location_Service' ) ? Foodord_Location_Service::SESSION_CITY_KEY : 'foodord_location_city' );
			$session_postal      = WC()->session->get( class_exists( 'Foodord_Location_Service' ) ? Foodord_Location_Service::SESSION_POSTAL_KEY : 'foodord_location_postal' );
			$session_minimum_raw = WC()->session->get( class_exists( 'Foodord_Location_Service' ) ? Foodord_Location_Service::SESSION_MINIMUM_KEY : 'foodord_location_minimum' );
			if ( null !== $session_minimum_raw && '' !== $session_minimum_raw ) {
				$session_minimum = (float) $session_minimum_raw;
			}
			$session_allowed_value = WC()->session->get( class_exists( 'Foodord_Location_Service' ) ? Foodord_Location_Service::SESSION_ALLOWED_KEY : 'foodord_location_allowed' );
			$session_allowed       = ( 'yes' === $session_allowed_value || true === $session_allowed_value || 1 === $session_allowed_value );
			if ( ! empty( $session_city ) ) {
				$customer_city = $session_city;
			}
			if ( ! empty( $session_postal ) ) {
				$customer_postal_code = $session_postal;
			}
		}

		if ( $session_allowed && null !== $session_minimum ) {
			$session_minimum = max( 0.0, (float) $session_minimum );
			if ( $session_minimum > 0 ) {
				return $session_minimum;
			}
		}

		// Legacy selected location payload (kept for backward compatibility with older modals).
		$selected_location = WC()->session ? WC()->session->get( 'foodord_selected_location' ) : null;
		if ( is_array( $selected_location ) ) {
			if ( isset( $selected_location['city'] ) && ! empty( $selected_location['city'] ) ) {
				$customer_city = $selected_location['city'];
			}
			if ( isset( $selected_location['postal_code'] ) && ! empty( $selected_location['postal_code'] ) ) {
				$customer_postal_code = $selected_location['postal_code'];
			}
		}

		// Attempt to resolve by city (and postal when available) to avoid clashes.
		if ( 'postal' === $configured_mode && class_exists( 'Foodord_Location_Service' ) && ! empty( $customer_city ) ) {
			$matched_location = Foodord_Location_Service::find_location( (string) $customer_city, (string) $customer_postal_code );
			if ( is_array( $matched_location ) ) {
				if ( isset( $matched_location['minimum'] ) && '' !== $matched_location['minimum'] && is_numeric( $matched_location['minimum'] ) ) {
					return (float) $matched_location['minimum'];
				}
				// Şehir & posta eşleşti ancak minimum değeri tanımlı değilse veya boşsa, posta-kodu fallback'ine düşmeyelim.
				return false;
			}
		}

		// Fall back to postal-only lookup for legacy data sets when city is unknown.
		if ( 'postal' === $configured_mode && empty( $customer_city ) && ! empty( $customer_postal_code ) && is_array( $delivery_locations ) ) {
			foreach ( $delivery_locations as $location ) {
				if ( isset( $location['postal_code'] ) && $location['postal_code'] === $customer_postal_code ) {
					if ( isset( $location['minimum'] ) && is_numeric( $location['minimum'] ) ) {
						return (float) $location['minimum'];
					}
				}
			}
		}

		// Return default minimum if no location match (optional).
		// You can set a global minimum here if needed.
		return false;
	}

	/**
	 * Get effective cart total after discounts, fees, and shipping.
	 *
	 * @return float
	 */
	private function get_effective_cart_total() {
		if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
			return 0.0;
		}

		$totals = WC()->cart->get_totals();
		if ( isset( $totals['total'] ) ) {
			return max( 0.0, (float) $totals['total'] );
		}

		$cart_subtotal   = (float) WC()->cart->get_subtotal();
		$fees_total      = 0.0;
		$registered_fees = WC()->cart->get_fees();
		if ( ! empty( $registered_fees ) ) {
			foreach ( $registered_fees as $fee_obj ) {
				if ( isset( $fee_obj->amount ) ) {
					$fees_total += (float) $fee_obj->amount;
				}
			}
		}

		$shipping_total = 0.0;
		if ( method_exists( WC()->cart, 'get_shipping_total' ) ) {
			$shipping_total += (float) WC()->cart->get_shipping_total();
		}
		if ( method_exists( WC()->cart, 'get_shipping_tax' ) ) {
			$shipping_total += (float) WC()->cart->get_shipping_tax();
		}

		$discount_total = method_exists( WC()->cart, 'get_discount_total' ) ? (float) WC()->cart->get_discount_total() : 0.0;

		return max( 0.0, ( $cart_subtotal - $discount_total ) + $fees_total + $shipping_total );
	}

	/**
	 * Determine if current visitor is in table ordering (dine-in) context.
	 *
	 * @return bool
	 */
	private function is_table_order_context() {
		$source = '';
		if ( function_exists( 'WC' ) && WC()->session ) {
			$source = (string) WC()->session->get( 'foodord_order_source', '' );
		}
		if ( 'table' === $source ) {
			return true;
		}

		$cookie = filter_input( INPUT_COOKIE, 'foodord_table_id', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
		$cookie = is_string( $cookie ) ? sanitize_text_field( wp_unslash( $cookie ) ) : '';
		return '' !== $cookie;
	}

	/**
	 * Validate minimum order amount on cart page
	 */
	public function validate_minimum_order_amount() {
		// Only run on cart and checkout pages.
		if ( ! function_exists( 'is_cart' ) || ! function_exists( 'is_checkout' ) ) {
			return;
		}

		if ( ! is_cart() && ! is_checkout() ) {
			return;
		}

		// Skip for order received page.
		if ( is_checkout() && is_order_received_page() ) {
			return;
		}

		$minimum = $this->get_minimum_order_amount();
		if ( false === $minimum || $minimum <= 0 ) {
			return;
		}

		$cart_total = $this->get_effective_cart_total();

		if ( $cart_total < $minimum ) {
			$message = sprintf(
				/* translators: 1: current order total, 2: minimum order amount. */
				__( 'Your current order total is %1$s — you must have an order with a minimum of %2$s to place your order.', 'foodord' ),
				wp_strip_all_tags( wc_price( $cart_total ) ),
				wp_strip_all_tags( wc_price( $minimum ) )
			);

			if ( is_cart() ) {
				wc_print_notice( esc_html( $message ), 'error' );
			}
		}
	}

	/**
	 * Validate minimum order amount during checkout process
	 */
	public function validate_checkout_minimum_amount() {
		if ( class_exists( 'Foodord_Business_Hours' ) && ! \Foodord_Business_Hours::is_open() ) {
			wc_add_notice( esc_html__( 'We are currently closed.', 'foodord' ), 'error' );
			return;
		}
		$minimum = $this->get_minimum_order_amount();
		if ( false === $minimum || $minimum <= 0 ) {
			return;
		}

		$cart_total = $this->get_effective_cart_total();

		if ( $cart_total < $minimum ) {
			$message = sprintf(
				/* translators: 1: current order total, 2: minimum order amount. */
				__( 'Your current order total is %1$s — you must have an order with a minimum of %2$s to place your order.', 'foodord' ),
				wp_strip_all_tags( wc_price( $cart_total ) ),
				wp_strip_all_tags( wc_price( $minimum ) )
			);

			wc_add_notice( esc_html( $message ), 'error' );
		}
	}

	/**
	 * Modify place order button if minimum not met
	 *
	 * @param string $button_html Original button HTML.
	 * @return string Modified button HTML.
	 */
	public function modify_place_order_button( $button_html ) {
		$minimum    = $this->get_minimum_order_amount();
		$cart_total = $this->get_effective_cart_total();

		if ( false === $minimum || $minimum <= 0 || $cart_total >= $minimum ) {
			// Ensure button is re-enabled when minimum is cleared or reached.
			$button_html = preg_replace( '/\sdisabled="disabled"/i', '', $button_html );
			$button_html = preg_replace( '/\sdisabled(?![a-z0-9_-])/i', '', $button_html );
			$button_html = str_replace( ' foodord-disabled-checkout', '', $button_html );
			$button_html = str_replace( 'foodord-disabled-checkout ', '', $button_html );
			$button_html = str_replace( ' foodord-disabled-checkout ', ' ', $button_html );
			$button_html = str_replace( 'foodord-disabled-checkout', '', $button_html );
			return $button_html;
		}

		// Minimum exists and cart is below threshold, enforce disabled state.
		$button_html = str_replace(
			'<button type="submit"',
			'<button type="submit" disabled="disabled"',
			$button_html
		);
		$button_html = str_replace(
			'class="button',
			'class="button foodord-disabled-checkout',
			$button_html
		);

		return $button_html;
	}

	/**
	 * Display minimum order notice on checkout page
	 */
	public function display_minimum_order_notice() {
		// Check if we're on checkout page using WooCommerce's method.
		if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
			return;
		}

		// Also skip for order received page.
		if ( is_order_received_page() ) {
			return;
		}

		$minimum = $this->get_minimum_order_amount();
		if ( false === $minimum || $minimum <= 0 ) {
			return;
		}

		$cart_total = $this->get_effective_cart_total();

		if ( $cart_total < $minimum ) {
			$remaining = $minimum - $cart_total;
			$message   = sprintf(
				/* translators: %s: remaining amount needed */
				__( 'Add %s more to your cart to meet the minimum order requirement.', 'foodord' ),
				wp_strip_all_tags( wc_price( $remaining ) )
			);

			wc_print_notice( esc_html( $message ), 'notice' );
		}
	}

	/**
	 * Enqueue scripts and styles for checkout validation
	 */
	public function enqueue_checkout_scripts() {
		// Check if we're on checkout page using WooCommerce's method.
		if ( ! function_exists( 'is_checkout' ) || ! is_checkout() || is_order_received_page() ) {
			return;
		}

		// Enqueue custom checkout validation styles.
		wp_enqueue_style(
			'foodord-checkout-validation',
			FOODORD_URL . 'public/css/wrc-checkout-validation.css',
			array(),
			FOODORD_VERSION,
			'all'
		);

		// Enqueue custom checkout validation script.
		wp_enqueue_script(
			'foodord-checkout-validation',
			FOODORD_URL . 'public/js/wrc-checkout-validation.js',
			array( 'jquery', 'wc-checkout' ),
			FOODORD_VERSION,
			true
		);

		// Pass data to JavaScript.
		$minimum = $this->get_minimum_order_amount();
		wp_localize_script(
			'foodord-checkout-validation',
			'foodord_checkout_params',
			array(
				'minimum_order_amount' => $minimum ? $minimum : 0,
				'currency_symbol'      => get_woocommerce_currency_symbol(),
				/* translators: %s: minimum order amount. */
				'message_template'     => __( 'Minimum order amount is %s', 'foodord' ),
			)
		);
	}

	/**
	 * Register checkout blocks support
	 *
	 * @param object $integration_registry Block integration registry.
	 */
	public function register_checkout_blocks( $integration_registry ) {
		// This method is called when blocks are being registered.
		// We use it as a hook point for block-based checkout.
	}

	/**
	 * Validate minimum order for block-based checkout
	 *
	 * @param \WC_Order        $order Order object.
	 * @param \WP_REST_Request $request Request object.
	 * @throws \Exception When minimum order amount is not met.
	 */
	public function validate_block_checkout( $order, $request ) {
		// Suppress unused parameters warning.
		unset( $order, $request );
		if ( class_exists( 'Foodord_Business_Hours' ) && ! \Foodord_Business_Hours::is_open() ) {
			throw new \Exception( esc_html__( 'We are currently closed.', 'foodord' ) );
		}
		$minimum = $this->get_minimum_order_amount();
		if ( false === $minimum || $minimum <= 0 ) {
			return;
		}

		$cart_total = $this->get_effective_cart_total();

		if ( $cart_total < $minimum ) {
			$message = sprintf(
				/* translators: 1: current order total, 2: minimum order amount. */
				__( 'Your current order total is %1$s — you must have an order with a minimum of %2$s to place your order.', 'foodord' ),
				wp_strip_all_tags( wc_price( $cart_total ) ),
				wp_strip_all_tags( wc_price( $minimum ) )
			);

			throw new \Exception( esc_html( $message ) );
		}
	}

	/**
	 * Enqueue scripts for block-based checkout
	 */
	public function enqueue_block_checkout_scripts() {
		// Check if we're on checkout page using WooCommerce's method.
		if ( ! function_exists( 'is_checkout' ) || ! is_checkout() || is_order_received_page() ) {
			return;
		}

		// Check if block checkout is actually being used.
		global $post;
		if ( ! $post || ! has_block( 'woocommerce/checkout', $post ) ) {
			return;
		}

		// Enqueue block checkout validation script.
		wp_enqueue_script(
			'foodord-block-checkout-validation',
			FOODORD_URL . 'public/js/wrc-block-checkout-validation.js',
			array( 'jquery' ),
			FOODORD_VERSION,
			true
		);

		// Pass data to JavaScript.
		$minimum    = $this->get_minimum_order_amount();
		$cart_total = $this->get_effective_cart_total();
		wp_localize_script(
			'foodord-block-checkout-validation',
			'foodord_block_checkout_params',
			array(
				'minimum_order_amount' => $minimum ? $minimum : 0,
				'cart_total'           => $cart_total,
				'currency_symbol'      => get_woocommerce_currency_symbol(),
				/* translators: %s: minimum order amount. */
				'message_template'     => __( 'Minimum order amount is %s', 'foodord' ),
				/* translators: %s: remaining amount */
				'add_more_message'     => __( 'Add %s more to meet the minimum order requirement.', 'foodord' ),
			)
		);
	}
}
