<?php

namespace Rtc\PlantShopWC\Frontend\Controllers;

use Rtc\PlantShopWC\Admin\Models\GeneralSettingsModel;
use WC_Order;

class CheckoutClassicController {
    private const ISO_WEEK_CODE_FORMAT = '%04d-W%02d';


	public function register_hooks(): void {
		// Modify classic (shortcode-based) checkout fields.
		add_filter( 'woocommerce_checkout_fields', array( $this, 'changeCheckoutFields' ), 9999 );
		// Validate custom fields.
		add_action( 'woocommerce_after_checkout_validation', array( $this, 'validateCheckoutFields' ), 10, 2 );
		// Persist custom field to the order when created.
		add_action( 'woocommerce_checkout_create_order', array( $this, 'updateCheckoutFields' ), 9, 2 );
		// Show selected shipping week in the order review.
		add_action( 'woocommerce_review_order_after_order_total', array( $this, 'render_shipping_week_review_row' ) );
	}

	/**
	 * Add a required consent checkbox to classic checkout.
	 *
	 * @param array $fields
	 * @return array
	 */
	public function changeCheckoutFields( array $fields ): array {
		// Ensure the 'order' group exists.
		if ( ! isset( $fields['order'] ) || ! is_array( $fields['order'] ) ) {
			$fields['order'] = array();
		}

		$opts    = get_option( GeneralSettingsModel::get_option_key(), array() );
		$enabled = isset( $opts['enable_equivalent_replacement'] ) && (string) $opts['enable_equivalent_replacement'] === '1';

		if ( $enabled ) {
			// Optional description/link from settings.
			$opts        = get_option( GeneralSettingsModel::get_option_key(), array() );
			$info_url    = isset( $opts['equivalent_replacement_info_url'] ) ? (string) $opts['equivalent_replacement_info_url'] : '';
			$description = '';
			$label       = __( 'I agree to receive an equivalent replacement if an ordered plant is unavailable', 'plantshop-wc' );
			if ( ! empty( $info_url ) ) {
				$label .= ' ' . sprintf(
					'<a href="%1$s" target="_blank" rel="noopener">%2$s</a>',
					esc_url( $info_url ),
					esc_html__( 'Learn more about equivalent replacements', 'plantshop-wc' )
				);
			}

			$fields['order']['plantshop_equivalent_replacement_consent'] = array(
				'type'        => 'checkbox',
				'label'       => $label,
				'description' => $description,
				'required'    => false,
				'default'     => 0, // Pre-check by default in classic checkout.
				'class'       => array( 'form-row-wide' ),
				'priority'    => 55, // After the default order_comments (50).
			);
		}

		// Shipping periods field when enabled
		$enabled = isset( $opts['enable_shipping_periods'] ) && (string) $opts['enable_shipping_periods'] === '1';
		if ( $enabled ) {
			$weeks = $this->compute_allowed_weeks( $opts );
			if ( ! empty( $weeks ) ) {
				// Build options as value => label
				$options = array();
				foreach ( $weeks as $wk ) {
					$label          = $this->human_week_label( $wk );
					$options[ $wk ] = $label;
				}
				$fields['order']['plantshop_shipping_week'] = array(
					'type'     => 'select',
					'label'    => __( 'Desired shipping week', 'plantshop-wc' ),
					'required' => true,
					'class'    => array( 'form-row-wide' ),
					'priority' => 54,
					'options'  => $options,
					'default'  => array_key_first( $options ),
				);
			}
		}

		return $fields;
	}

	/**
	 * Save posted custom field into order meta.
	 *
	 * @param WC_Order $order
	 * @param array|null $checkout_data Checkout data (not strictly needed here).
	 */
	public function updateCheckoutFields( WC_Order $order, $checkout_data ): void {
		unset( $checkout_data );
		$opts          = get_option( GeneralSettingsModel::get_option_key(), array() );
		$enabled       = isset( $opts['enable_equivalent_replacement'] ) && (string) $opts['enable_equivalent_replacement'] === '1';
		$raw           = '';
		$shipping_week = '';
		$nonce_valid   = (
			isset( $_POST['woocommerce-process-checkout-nonce'] ) &&
			wp_verify_nonce(
				sanitize_text_field( wp_unslash( $_POST['woocommerce-process-checkout-nonce'] ) ),
				'woocommerce-process_checkout'
			)
		);
		if ( $nonce_valid ) {
			if ( $enabled && isset( $_POST['plantshop_equivalent_replacement_consent'] ) ) {
				$raw = sanitize_text_field( wp_unslash( $_POST['plantshop_equivalent_replacement_consent'] ) );
			}
			if ( isset( $_POST['plantshop_shipping_week'] ) ) {
				$shipping_week = sanitize_text_field( wp_unslash( $_POST['plantshop_shipping_week'] ) );
			}
		}

		if ( $enabled && $nonce_valid ) {
			$flag = wc_string_to_bool( $raw ) ? '1' : '0';
			$order->update_meta_data( '_plantshop_equivalent_replacement_consent', $flag );
		}

		if ( $shipping_week !== '' && $nonce_valid ) {
			$order->update_meta_data( '_plantshop_shipping_week', $shipping_week );
		}
	}

	/**
	 * Validate custom fields.
	 */
	public function validateCheckoutFields( $data, $errors ): void {
		$opts    = get_option( GeneralSettingsModel::get_option_key(), array() );
		$enabled = isset( $opts['enable_shipping_periods'] ) && (string) $opts['enable_shipping_periods'] === '1';
		if ( $enabled ) {
			$weeks = $this->compute_allowed_weeks( $opts );
			if ( ! empty( $weeks ) ) {
				$posted = '';
				if (
					isset( $_POST['woocommerce-process-checkout-nonce'], $_POST['plantshop_shipping_week'] ) &&
					wp_verify_nonce(
						sanitize_text_field( wp_unslash( $_POST['woocommerce-process-checkout-nonce'] ) ),
						'woocommerce-process_checkout'
					)
				) {
					$posted = sanitize_text_field( wp_unslash( $_POST['plantshop_shipping_week'] ) );
				}
				if ( $posted === '' || ! in_array( $posted, $weeks, true ) ) {
					if ( function_exists( 'wc_add_notice' ) ) {
						wc_add_notice( __( 'Please select a desired shipping week.', 'plantshop-wc' ), 'error' );
					}
				}
			}
		}
	}

	/**
	 * Render a row in order review showing selected shipping week with a yellow warning icon.
	 */
	public function render_shipping_week_review_row(): void {
		if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
			return;
		}
		$opts    = get_option( GeneralSettingsModel::get_option_key(), array() );
		$enabled = isset( $opts['enable_shipping_periods'] ) && (string) $opts['enable_shipping_periods'] === '1';
		if ( ! $enabled ) {
			return;
		}
		$current = '';
		if (
			isset( $_POST['woocommerce-process-checkout-nonce'], $_POST['plantshop_shipping_week'] ) &&
			wp_verify_nonce(
				sanitize_text_field( wp_unslash( $_POST['woocommerce-process-checkout-nonce'] ) ),
				'woocommerce-process_checkout'
			)
		) {
			$current = sanitize_text_field( wp_unslash( $_POST['plantshop_shipping_week'] ) );
		}
		$label = $current !== '' ? $this->human_week_label( $current ) : __( 'Not selected', 'plantshop-wc' );
		echo '<tr class="shipping-week-review">
                <th colspan="1" style="color:#a07900;">
                    <span aria-hidden="true">&#9888;&#65039;</span> ' . esc_html__( 'Desired shipping week', 'plantshop-wc' ) . '
                </th>
                <td class="plantshop-shipping-week-display">' . esc_html( $label ) . '</td>
            </tr>';
		$handle = 'plantshop-wc-shipping-week-review';
		if ( ! wp_script_is( $handle, 'enqueued' ) ) {
			if ( ! wp_script_is( $handle, 'registered' ) ) {
				wp_register_script( $handle, '', array(), defined( 'PLANTSHOP_WC_PLUGIN_VERSION' ) ? PLANTSHOP_WC_PLUGIN_VERSION : null, true );
			}
			wp_enqueue_script( $handle );
			wp_add_inline_script(
				$handle,
				'(function(){
            var sel = document.querySelector("select[name=plantshop_shipping_week]");
            var target = document.querySelector(".plantshop-shipping-week-display");
            if(!sel || !target){return;}
            var upd = function(){ var opt = sel.options[sel.selectedIndex]; target.textContent = opt ? opt.text : ""; };
            sel.addEventListener("change", upd);
            document.addEventListener("wc-updated", upd);
        })();'
			);
		}
	}

	/**
	 * Compute allowed weeks from settings array. Returns list like ["2025-W12", ...] sorted ascending.
	 */
	private function compute_allowed_weeks( array $opts ): array {
		$raw = isset( $opts['shipping_week_ranges'] ) ? (string) $opts['shipping_week_ranges'] : '';
		if ( $raw === '' ) {
			return array();
		}
		$lines          = preg_split( '/\n+/', str_replace( array( "\r\n", "\r" ), "\n", $raw ) );
		$set            = array();
		$currentIsoYear = (int) gmdate( 'o' );
		$currentIsoWeek = (int) gmdate( 'W' );
		foreach ( $lines as $line ) {
			$line = trim( $line );
			if ( $line === '' ) {
				continue; }
			// Accept formats: Wnn or ranges Wnn-Wnn (and legacy Wnn..Wnn)
			if ( preg_match( '/^W(\d{1,2})(?:\-{1}|\.{2})W(\d{1,2})$/i', $line, $m ) ) {
				$w1 = max( 1, min( 53, intval( $m[1] ) ) );
				$w2 = max( 1, min( 53, intval( $m[2] ) ) );
				if ( $w1 > $w2 ) {
					[$w1, $w2] = array( $w2, $w1 ); }
				for ( $w = $w1; $w <= $w2; $w++ ) {
					$targetYear = ( $w >= $currentIsoWeek ) ? $currentIsoYear : ( $currentIsoYear + 1 );
					$yy         = $this->find_valid_iso_year_for_week( $targetYear, $w );
					if ( $yy !== null ) {
						$set[ sprintf( self::ISO_WEEK_CODE_FORMAT, $yy, $w ) ] = true;
					}
				}
			} elseif ( preg_match( '/^W(\d{1,2})$/i', $line, $m ) ) {
				$w          = max( 1, min( 53, intval( $m[1] ) ) );
				$targetYear = ( $w >= $currentIsoWeek ) ? $currentIsoYear : ( $currentIsoYear + 1 );
				$yy         = $this->find_valid_iso_year_for_week( $targetYear, $w );
				if ( $yy !== null ) {
					$set[ sprintf( self::ISO_WEEK_CODE_FORMAT, $yy, $w ) ] = true;
				}
			}
		}
		$weeks = array_keys( $set );
		sort( $weeks, SORT_STRING );
		return $weeks;
	}

	/**
	 * Expand inclusive ISO week range into accumulator set.
	 * @param int $y1
	 * @param int $w1
	 * @param int $y2
	 * @param int $w2
	 * @param array<string,bool> $acc
	 */
	private function expand_week_range( int $y1, int $w1, int $y2, int $w2, array &$acc ): void {
		// Normalize order
		$start = new \DateTime();
		$start->setISODate( $y1, $w1, 1 );
		$end = new \DateTime();
		$end->setISODate( $y2, $w2, 1 );
		if ( $start > $end ) {
			[$start, $end] = array( $end, $start );
		}
		$cur = clone $start;
		while ( $cur <= $end ) {
			$y = (int) $cur->format( 'o' ); // ISO year
			$w = (int) $cur->format( 'W' );
			$acc[ sprintf( self::ISO_WEEK_CODE_FORMAT, $y, $w ) ] = true;
			$cur->modify( '+1 week' );
		}
	}

	/**
	 * Find a valid ISO year for a given week number starting from startYear moving forward.
	 * Returns null if a matching year is not found within the next few years.
	 */
	private function find_valid_iso_year_for_week( int $startYear, int $week ): ?int {
		if ( $week < 1 || $week > 53 ) {
			return null; }
		for ( $i = 0; $i < 6; $i++ ) {
			$y = $startYear + $i;
			try {
				$dt = new \DateTime();
				$dt->setISODate( $y, $week, 1 );
				$yy = (int) $dt->format( 'o' );
				$ww = (int) $dt->format( 'W' );
				if ( $yy === $y && $ww === $week ) {
					return $y;
				}
			} catch ( \Throwable $e ) {
				continue;
			}
		}
		return null;
	}

	private function human_week_label( string $code ): string {
		if ( ! preg_match( '/^(\d{4})-W(\d{2})$/', $code, $m ) ) {
			return $code;
		}
		$y = intval( $m[1] );
		$w = intval( $m[2] );
		// translators: 1: ISO week number, 2: ISO year.
		return sprintf( __( 'Week %1$d, %2$d', 'plantshop-wc' ), $w, $y ) . ' (' . $code . ')';
	}
}
