<?php
/**
 * Storzen Module — Pre-Order (Pro)
 *
 * Lets merchants flag products as pre-orderable. Customers can buy them even
 * when out of stock; checkout works normally; admin sees a custom note.
 *
 * Implementation strategy:
 *   • Per-product meta on the WC product edit screen (Inventory tab):
 *       _storzen_preorder_enabled   — '1' when pre-order is on
 *       _storzen_preorder_ship_date — Y-m-d expected ship date (optional)
 *       _storzen_preorder_deposit   — int percent for partial deposit (Pro)
 *   • Hooks:
 *       woocommerce_is_purchasable  — return true even when stock is 0
 *       woocommerce_get_availability — display "Pre-order — ships {date}" message
 *       woocommerce_product_*_add_to_cart_text — button label override
 *       woocommerce_after_shop_loop_item_title — pre-order badge on shop card
 *       storzen_shop_card_badges — same for Storzen-imported templates
 *       woocommerce_email_after_order_table — note about pre-order in confirmation email
 *
 * Loaded only when STORZEN_IS_PRO === 'yes' (license active).
 *
 * @package storzen
 * @since   1.5.3
 */

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

if ( ! class_exists( 'Storzen_Module_Preorder' ) ) {

	class Storzen_Module_Preorder {

		const META_ENABLED   = '_storzen_preorder_enabled';
		const META_SHIP_DATE = '_storzen_preorder_ship_date';
		const META_DEPOSIT   = '_storzen_preorder_deposit';
		const NONCE          = 'storzen_preorder_meta_nonce';

		/** @var array|null */
		private $settings = null;

		public function __construct() {
			if ( ! function_exists( 'WC' ) ) {
				return;
			}

			// Frontend: assets + display hooks.
			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) );

			// Make pre-order products purchasable even when out of stock.
			add_filter( 'woocommerce_is_purchasable', array( $this, 'filter_is_purchasable' ), 20, 2 );
			add_filter( 'woocommerce_variation_is_purchasable', array( $this, 'filter_is_purchasable' ), 20, 2 );

			// Override the "out of stock" message with a pre-order one.
			add_filter( 'woocommerce_get_availability', array( $this, 'filter_availability' ), 20, 2 );

			// Override the "Add to cart" button text.
			add_filter( 'woocommerce_product_single_add_to_cart_text', array( $this, 'filter_button_text' ), 20, 2 );
			add_filter( 'woocommerce_product_add_to_cart_text',        array( $this, 'filter_button_text' ), 20, 2 );

			// Render pre-order badge.
			$s = $this->get_settings();
			if ( $s['show_on_cards'] ) {
				add_action( 'woocommerce_before_shop_loop_item_title', array( $this, 'render_card_badge' ), 9 );
				add_action( 'storzen_shop_card_badges',            array( $this, 'render_card_badge' ), 11, 1 );
			}
			if ( $s['show_on_single'] ) {
				add_action( 'woocommerce_single_product_summary',         array( $this, 'render_single_badge' ), 6 );
				add_action( 'storzen_product_single_after_price',     array( $this, 'render_single_badge' ), 12, 1 );
			}

			// Order email note + admin order page badge.
			add_action( 'woocommerce_email_after_order_table', array( $this, 'email_preorder_notice' ), 10, 4 );
			add_action( 'woocommerce_admin_order_data_after_order_details', array( $this, 'admin_order_preorder_notice' ) );

			// Admin: product edit metabox + save handler.
			if ( is_admin() ) {
				add_action( 'woocommerce_product_options_inventory_product_data', array( $this, 'render_product_meta_fields' ) );
				add_action( 'woocommerce_admin_process_product_object', array( $this, 'save_product_meta_fields' ) );
			}
		}

		// ─────────────────────────────────────────────────────────────────
		// Settings
		// ─────────────────────────────────────────────────────────────────

		private function get_settings() {
			if ( null !== $this->settings ) {
				return $this->settings;
			}

			$btn   = (string) storzen_module_setting( 'preorder', 'button_label' );
			$badge = (string) storzen_module_setting( 'preorder', 'badge_text' );
			$avail = (string) storzen_module_setting( 'preorder', 'availability_message' );
			$fmt   = (string) storzen_module_setting( 'preorder', 'date_format' );
			if ( ! in_array( $fmt, array( 'wp', 'mdY', 'dmY', 'iso', 'words' ), true ) ) {
				$fmt = 'wp';
			}

			$this->settings = array(
				'button_label'         => $btn   !== '' ? $btn   : __( 'Pre-order', 'storzen' ),
				'badge_text'           => $badge !== '' ? $badge : __( 'Pre-order', 'storzen' ),
				'availability_message' => $avail !== '' ? $avail : __( 'Available for pre-order — ships {date}', 'storzen' ),
				'date_format'          => $fmt,
				'show_on_cards'        => (bool) storzen_module_setting( 'preorder', 'show_on_cards' ),
				'show_on_single'       => (bool) storzen_module_setting( 'preorder', 'show_on_single' ),
				'allow_backorder'      => (bool) storzen_module_setting( 'preorder', 'allow_backorder' ),
				'partial_deposit_pct'  => max( 0, min( 100, (int) storzen_module_setting( 'preorder', 'partial_deposit_pct' ) ) ),
				'email_confirmation'   => (bool) storzen_module_setting( 'preorder', 'email_confirmation' ),
			);
			return $this->settings;
		}

		// ─────────────────────────────────────────────────────────────────
		// Per-product helpers
		// ─────────────────────────────────────────────────────────────────

		/**
		 * Is the product flagged as pre-order?
		 *
		 * For variable products: returns true if ANY visible variation has
		 * the flag — single-product page UX shows the badge / message.
		 *
		 * @param WC_Product $product
		 * @return bool
		 */
		private function is_preorder( $product ) {
			if ( ! $product instanceof WC_Product ) {
				return false;
			}
			if ( 'yes' === $product->get_meta( self::META_ENABLED, true ) ) {
				return true;
			}
			// Variable: check any variation.
			if ( $product->is_type( 'variable' ) ) {
				foreach ( $product->get_visible_children() as $vid ) {
					$v = wc_get_product( $vid );
					if ( $v && 'yes' === $v->get_meta( self::META_ENABLED, true ) ) {
						return true;
					}
				}
			}
			return false;
		}

		/**
		 * Get ship date (raw Y-m-d string or empty).
		 *
		 * @param WC_Product $product
		 * @return string
		 */
		private function get_ship_date( $product ) {
			if ( ! $product instanceof WC_Product ) {
				return '';
			}
			$d = (string) $product->get_meta( self::META_SHIP_DATE, true );
			return $d;
		}

		/**
		 * Format a Y-m-d date per the module setting.
		 *
		 * @param string $ymd
		 * @return string Pretty-printed date or empty string if not parseable.
		 */
		private function format_date( $ymd ) {
			if ( '' === $ymd ) {
				return '';
			}
			$ts = strtotime( $ymd );
			if ( ! $ts ) {
				return '';
			}
			$s = $this->get_settings();
			switch ( $s['date_format'] ) {
				case 'mdY':   return date_i18n( 'F j, Y', $ts );
				case 'dmY':   return date_i18n( 'j F Y', $ts );
				case 'iso':   return date_i18n( 'Y-m-d', $ts );
				case 'words': return human_time_diff( time(), $ts ) . ' ' . __( 'from now', 'storzen' );
				case 'wp':
				default:      return date_i18n( get_option( 'date_format' ), $ts );
			}
		}

		// ─────────────────────────────────────────────────────────────────
		// Filters: purchasability + availability + button label
		// ─────────────────────────────────────────────────────────────────

		/**
		 * Force purchasability when pre-order is enabled, regardless of stock.
		 *
		 * @param bool       $purchasable
		 * @param WC_Product $product
		 * @return bool
		 */
		public function filter_is_purchasable( $purchasable, $product ) {
			if ( $purchasable ) {
				return true;
			}
			if ( $this->is_preorder( $product ) ) {
				// WC also requires a price set; respect that.
				return '' !== $product->get_price();
			}
			return $purchasable;
		}

		/**
		 * Replace the "Out of stock" availability with our pre-order message.
		 *
		 * @param array      $availability
		 * @param WC_Product $product
		 * @return array
		 */
		public function filter_availability( $availability, $product ) {
			if ( ! $this->is_preorder( $product ) ) {
				return $availability;
			}

			$s        = $this->get_settings();
			$ship_raw = $this->get_ship_date( $product );
			$ship_fmt = $this->format_date( $ship_raw );

			$msg = $s['availability_message'];
			if ( $ship_fmt ) {
				$msg = str_replace( '{date}', $ship_fmt, $msg );
			} else {
				// No date set — strip the "{date}" placeholder + trailing dash if any.
				$msg = preg_replace( '/\s*[—-]?\s*\{date\}.*$/u', '', $msg );
				$msg = trim( $msg );
			}

			$availability['availability'] = $msg;
			$availability['class']        = 'storzen-preorder-availability';
			return $availability;
		}

		/**
		 * Replace "Add to cart" / "Read more" with the configured pre-order label.
		 *
		 * @param string     $text
		 * @param WC_Product $product
		 * @return string
		 */
		public function filter_button_text( $text, $product ) {
			if ( ! $this->is_preorder( $product ) ) {
				return $text;
			}
			$s = $this->get_settings();
			return $s['button_label'];
		}

		// ─────────────────────────────────────────────────────────────────
		// Badge rendering
		// ─────────────────────────────────────────────────────────────────

		public function render_card_badge( $product_arg = null ) {
			$product = ( $product_arg instanceof WC_Product ) ? $product_arg : ( $GLOBALS['product'] ?? null );
			if ( ! $product instanceof WC_Product || ! $this->is_preorder( $product ) ) {
				return;
			}
			if ( class_exists( '\Elementor\Storzen_Archive_Grid' ) && false === \Elementor\Storzen_Archive_Grid::is_module_active( 'preorder' ) ) {
				return;
			}
			$s = $this->get_settings();
			printf(
				'<span class="storzen-preorder-badge storzen-preorder-badge--card">%s</span>',
				esc_html( $s['badge_text'] )
			);
		}

		public function render_single_badge( $product_arg = null ) {
			$product = ( $product_arg instanceof WC_Product ) ? $product_arg : ( $GLOBALS['product'] ?? null );
			if ( ! $product instanceof WC_Product || ! $this->is_preorder( $product ) ) {
				return;
			}
			$s        = $this->get_settings();
			$ship_raw = $this->get_ship_date( $product );
			$ship_fmt = $this->format_date( $ship_raw );
			?>
			<div class="storzen-preorder-notice">
				<span class="storzen-preorder-badge storzen-preorder-badge--single">
					<?php echo esc_html( $s['badge_text'] ); ?>
				</span>
				<?php if ( $ship_fmt ) : ?>
					<span class="storzen-preorder-ship">
						<?php
						/* translators: %s: expected ship date */
						printf( esc_html__( 'Expected to ship: %s', 'storzen' ), esc_html( $ship_fmt ) );
						?>
					</span>
				<?php endif; ?>
			</div>
			<?php
		}

		// ─────────────────────────────────────────────────────────────────
		// Order / email integration
		// ─────────────────────────────────────────────────────────────────

		/**
		 * Append a pre-order summary to confirmation emails when the order
		 * contains pre-orderable items. Setting-gated.
		 */
		public function email_preorder_notice( $order, $sent_to_admin, $plain_text, $email ) {
			$s = $this->get_settings();
			if ( ! $s['email_confirmation'] || ! $order instanceof WC_Order ) {
				return;
			}

			$preorder_items = array();
			foreach ( $order->get_items() as $item ) {
				$p = $item->get_product();
				if ( $this->is_preorder( $p ) ) {
					$ship = $this->format_date( $this->get_ship_date( $p ) );
					$preorder_items[] = sprintf(
						'%s — %s',
						$p->get_name(),
						$ship ?: __( 'Date TBD', 'storzen' )
					);
				}
			}
			if ( empty( $preorder_items ) ) {
				return;
			}

			echo '<div style="background:#fef3c7;border:1px solid #fcd34d;padding:14px 18px;margin:20px 0;border-radius:6px;color:#92400e">';
			echo '<strong style="display:block;margin-bottom:6px">' . esc_html__( 'Pre-Order Items in this order:', 'storzen' ) . '</strong>';
			echo '<ul style="margin:0;padding-left:18px">';
			foreach ( $preorder_items as $line ) {
				echo '<li>' . esc_html( $line ) . '</li>';
			}
			echo '</ul>';
			echo '<p style="margin:8px 0 0;font-size:13px">' . esc_html__( "We'll notify you separately when these ship.", 'storzen' ) . '</p>';
			echo '</div>';
		}

		/**
		 * Admin order edit screen: small notice when any line item is pre-order.
		 *
		 * @param WC_Order $order
		 */
		public function admin_order_preorder_notice( $order ) {
			if ( ! $order instanceof WC_Order ) {
				return;
			}
			foreach ( $order->get_items() as $item ) {
				if ( $this->is_preorder( $item->get_product() ) ) {
					echo '<p style="background:#fef3c7;border-left:4px solid #f59e0b;padding:8px 12px;margin:10px 0;font-weight:500"><strong>' . esc_html__( 'Pre-order:', 'storzen' ) . '</strong> ' . esc_html__( 'This order contains pre-order items.', 'storzen' ) . '</p>';
					break;
				}
			}
		}

		// ─────────────────────────────────────────────────────────────────
		// Admin: product edit screen metabox
		// ─────────────────────────────────────────────────────────────────

		/**
		 * Add pre-order fields to the WC product edit screen, Inventory section.
		 */
		public function render_product_meta_fields() {
			global $post;
			if ( ! $post ) return;

			$enabled   = get_post_meta( $post->ID, self::META_ENABLED, true );
			$ship_date = get_post_meta( $post->ID, self::META_SHIP_DATE, true );
			$deposit   = (int) get_post_meta( $post->ID, self::META_DEPOSIT, true );
			$s         = $this->get_settings();

			echo '<div class="options_group storzen-preorder-options" style="border-top:1px solid #eee;padding-top:6px">';

			wp_nonce_field( self::NONCE, '_storzen_preorder_nonce' );

			woocommerce_wp_checkbox( array(
				'id'          => self::META_ENABLED,
				'label'       => __( 'Storzen Pre-Order', 'storzen' ),
				'description' => __( 'Allow customers to buy this product before it is in stock.', 'storzen' ),
				'value'       => $enabled === 'yes' ? 'yes' : 'no',
			) );

			woocommerce_wp_text_input( array(
				'id'                => self::META_SHIP_DATE,
				'label'             => __( 'Expected Ship Date', 'storzen' ),
				'description'       => __( 'Optional. Shown to customers and included in confirmation emails.', 'storzen' ),
				'desc_tip'          => true,
				'type'              => 'date',
				'value'             => esc_attr( $ship_date ),
				'wrapper_class'     => 'storzen-preorder-field',
			) );

			if ( $s['partial_deposit_pct'] > 0 ) {
				woocommerce_wp_text_input( array(
					'id'                => self::META_DEPOSIT,
					'label'             => sprintf(
						/* translators: %d default deposit pct */
						__( 'Deposit %% (override, default %d)', 'storzen' ),
						$s['partial_deposit_pct']
					),
					'description'       => __( 'Optional per-product override. Leave blank to use module-wide default.', 'storzen' ),
					'desc_tip'          => true,
					'type'              => 'number',
					'custom_attributes' => array( 'min' => 0, 'max' => 100, 'step' => 1 ),
					'value'             => $deposit ?: '',
				) );
			}

			echo '</div>';
		}

		/**
		 * Persist the pre-order fields when the product is saved.
		 *
		 * @param WC_Product $product
		 */
		public function save_product_meta_fields( $product ) {
			if ( ! $product instanceof WC_Product ) {
				return;
			}
			if ( ! current_user_can( 'edit_product', $product->get_id() ) ) {
				return;
			}
			// WC fires this on its own product-save flow which already verifies
			// the main post nonce. We re-check the specific nonce too for safety.
			if ( ! isset( $_POST['_storzen_preorder_nonce'] ) ||
				 ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_storzen_preorder_nonce'] ) ), self::NONCE ) ) {
				return;
			}

			$enabled = isset( $_POST[ self::META_ENABLED ] ) ? 'yes' : 'no';
			$product->update_meta_data( self::META_ENABLED, $enabled );

			$ship = isset( $_POST[ self::META_SHIP_DATE ] )
				? sanitize_text_field( wp_unslash( $_POST[ self::META_SHIP_DATE ] ) )
				: '';
			// Validate as Y-m-d.
			if ( $ship && ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $ship ) ) {
				$ship = '';
			}
			$product->update_meta_data( self::META_SHIP_DATE, $ship );

			$deposit = isset( $_POST[ self::META_DEPOSIT ] )
				? max( 0, min( 100, absint( wp_unslash( $_POST[ self::META_DEPOSIT ] ) ) ) )
				: 0;
			$product->update_meta_data( self::META_DEPOSIT, $deposit );
		}

		// ─────────────────────────────────────────────────────────────────
		// Assets
		// ─────────────────────────────────────────────────────────────────

		public function enqueue_assets() {
			wp_enqueue_style(
				'storzen-preorder',
				STORZEN_ROOT_URL . 'assets/css/modules/preorder.css',
				array(),
				STORZEN_VERSION
			);
		}

	} // end class

} // end class_exists
