<?php
/**
 * Frontend: Lock City and Postcode fields on Checkout (classic + blocks).
 *
 * Makes city and postcode non-editable by customers so that address is
 * controlled exclusively by the Address Changer system.
 *
 * @package FoodOrd
 */

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

/**
 * Class Foodord_Checkout_Lock_Address
 */
class Foodord_Checkout_Lock_Address {
	/**
	 * Bootstrap hooks (frontend only).
	 */
	public function init(): void {
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ), 30 );
		add_filter( 'woocommerce_checkout_fields', array( $this, 'lock_classic_checkout_fields' ), 20 );
		add_filter( 'woocommerce_default_address_fields', array( $this, 'relax_default_address_fields' ), 20 );
		add_filter( 'woocommerce_blocks_checkout_fields', array( $this, 'filter_blocks_checkout_fields' ), 20 );
		add_filter( 'body_class', array( $this, 'add_pickup_body_class' ) );
		add_action( 'woocommerce_checkout_init', array( $this, 'seed_pickup_customer_address' ), 5 );
		add_filter( 'woocommerce_store_api_checkout_update_customer_from_request', array( $this, 'ensure_pickup_customer_address_for_store_api' ), 10, 2 );
	}

	/**
	 * Enqueue CSS/JS only on checkout page.
	 */
	public function enqueue_assets(): void {
		if ( is_admin() ) {
			return;
		}
		if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
			return;
		}

		// Enqueue shared frontend styles.
		if ( function_exists( 'foodord_enqueue_frontend_styles' ) ) {
			foodord_enqueue_frontend_styles();
		}
		wp_enqueue_script(
			'foodord-checkout-lock-address',
			defined( 'FOODORD_URL' ) ? FOODORD_URL . 'public/js/foodord-checkout-lock-address.js' : plugin_dir_url( __FILE__ ) . 'js/foodord-checkout-lock-address.js',
			array(),
			FOODORD_VERSION,
			true
		);

		// Get WooCommerce store address for pickup defaults.
		$store_address  = get_option( 'woocommerce_store_address', '' );
		$store_address2 = get_option( 'woocommerce_store_address_2', '' );
		$store_city     = get_option( 'woocommerce_store_city', '' );
		$store_postcode = get_option( 'woocommerce_store_postcode', '' );

		// Combine address lines if needed.
		$full_address = trim( $store_address );
		if ( ! empty( $store_address2 ) ) {
			$full_address .= ' ' . trim( $store_address2 );
		}

		// Pass English tooltip strings to JS.
		wp_localize_script(
			'foodord-checkout-lock-address',
			'foodord_lock_vars',
			array(
				'tooltip'       => __( 'To change your city and postal code, please go back to the order page and use the Address Changer.', 'foodord' ),
				'iconLabel'     => __( 'Locked field', 'foodord' ),
				'mode'          => $this->is_pickup_mode() ? 'pickup' : 'delivery',
				'debug'         => defined( 'WP_DEBUG' ) && WP_DEBUG,
				'storeAddress'  => $full_address,
				'storeCity'     => $store_city,
				'storePostcode' => $store_postcode,
			)
		);
	}

	/**
	 * Classic (shortcode) checkout: mark fields as readonly and style them.
	 *
	 * @param array $fields Checkout fields.
	 * @return array
	 */
	public function lock_classic_checkout_fields( array $fields ): array {
		$pickup_mode   = $this->is_pickup_mode();
		$groups        = array( 'billing', 'shipping' );
		$lockable_keys = array( 'city' );
		$hidden_keys   = array( 'address_1', 'address_2', 'city', 'postcode', 'state' );

		foreach ( $groups as $group ) {
			if ( ! isset( $fields[ $group ] ) || ! is_array( $fields[ $group ] ) ) {
				continue;
			}

			if ( $pickup_mode ) {
				foreach ( $hidden_keys as $hide_key ) {
					$field_key = $group . '_' . $hide_key;
					if ( isset( $fields[ $group ][ $field_key ] ) ) {
						unset( $fields[ $group ][ $field_key ] );
					}
				}
				continue;
			}

			foreach ( $lockable_keys as $key ) {
				$field_key = $group . '_' . $key;
				if ( isset( $fields[ $group ][ $field_key ] ) && is_array( $fields[ $group ][ $field_key ] ) ) {
					if ( ! isset( $fields[ $group ][ $field_key ]['custom_attributes'] ) || ! is_array( $fields[ $group ][ $field_key ]['custom_attributes'] ) ) {
						$fields[ $group ][ $field_key ]['custom_attributes'] = array();
					}
					$fields[ $group ][ $field_key ]['custom_attributes']['readonly']      = 'readonly';
					$fields[ $group ][ $field_key ]['custom_attributes']['aria-readonly'] = 'true';

					if ( ! isset( $fields[ $group ][ $field_key ]['class'] ) || ! is_array( $fields[ $group ][ $field_key ]['class'] ) ) {
						$fields[ $group ][ $field_key ]['class'] = array();
					}
					if ( ! isset( $fields[ $group ][ $field_key ]['input_class'] ) || ! is_array( $fields[ $group ][ $field_key ]['input_class'] ) ) {
						$fields[ $group ][ $field_key ]['input_class'] = array();
					}
					$fields[ $group ][ $field_key ]['class'][]       = 'foodord-locked-field';
					$fields[ $group ][ $field_key ]['input_class'][] = 'foodord-locked-input';
				}
			}
		}
		return $fields;
	}

	/**
	 * Ensure address fields are optional in pickup mode (classic + blocks helpers).
	 *
	 * @param array $fields Default address fields.
	 * @return array
	 */
	public function relax_default_address_fields( array $fields ): array {
		if ( is_admin() || ! $this->is_pickup_mode() ) {
			return $fields;
		}

		$keys = array( 'address_1', 'address_2', 'city', 'postcode', 'state' );
		foreach ( $keys as $key ) {
			if ( isset( $fields[ $key ] ) && is_array( $fields[ $key ] ) ) {
				$fields[ $key ]['required'] = false;
			}
		}

		return $fields;
	}

	/**
	 * WooCommerce Blocks checkout: drop address fields entirely when pickup is active.
	 *
	 * @param array $fields Blocks checkout fields schema.
	 * @return array
	 */
	public function filter_blocks_checkout_fields( array $fields ): array {
		if ( is_admin() || ! $this->is_pickup_mode() ) {
			return $fields;
		}

		$keys    = array( 'address_1', 'address_2', 'city', 'postcode', 'state' );
		$address = $this->get_pickup_address_seed();
		$mapping = array(
			'city'      => $address['city'],
			'postcode'  => $address['postcode'],
			'address_1' => $address['address_1'],
			'address_2' => $address['address_2'],
			'state'     => $address['state'],
		);
		foreach ( array( 'billing', 'shipping' ) as $section ) {
			if ( ! isset( $fields[ $section ] ) || ! is_array( $fields[ $section ] ) ) {
				continue;
			}
			foreach ( $keys as $key ) {
				if ( ! isset( $fields[ $section ][ $key ] ) || ! is_array( $fields[ $section ][ $key ] ) ) {
					continue;
				}
				$fields[ $section ][ $key ]['required'] = false;
				if ( isset( $fields[ $section ][ $key ]['validation'] ) && is_array( $fields[ $section ][ $key ]['validation'] ) ) {
					$fields[ $section ][ $key ]['validation'] = array_values(
						array_filter(
							$fields[ $section ][ $key ]['validation'],
							static function ( $rule ) {
								return 'required' !== $rule;
							}
						)
					);
				}
				$fields[ $section ][ $key ]['hidden'] = true;
				if ( isset( $mapping[ $key ] ) && '' !== $mapping[ $key ] ) {
					$fields[ $section ][ $key ]['value'] = $mapping[ $key ];
				}
			}
		}

		return $fields;
	}

	/**
	 * Ensure pickup address is seeded on the customer object when checkout initializes.
	 *
	 * @param WC_Checkout $checkout Checkout instance.
	 * @return void
	 */
	public function seed_pickup_customer_address( $checkout ): void {
		unset( $checkout );
		if ( is_admin() || ! $this->is_pickup_mode() ) {
			return;
		}
		if ( ! function_exists( 'WC' ) || ! WC()->customer ) {
			return;
		}

		$seed     = $this->get_pickup_address_seed();
		$customer = WC()->customer;
		$modified = false;

		if ( '' !== $seed['city'] && $customer->get_billing_city() !== $seed['city'] ) {
			$customer->set_billing_city( $seed['city'] );
			$modified = true;
		}
		if ( '' !== $seed['postcode'] && $customer->get_billing_postcode() !== $seed['postcode'] ) {
			$customer->set_billing_postcode( $seed['postcode'] );
			$modified = true;
		}
		if ( '' !== $seed['address_1'] && $customer->get_billing_address_1() !== $seed['address_1'] ) {
			$customer->set_billing_address_1( $seed['address_1'] );
			$modified = true;
		}
		if ( '' !== $seed['address_2'] && $customer->get_billing_address_2() !== $seed['address_2'] ) {
			$customer->set_billing_address_2( $seed['address_2'] );
			$modified = true;
		}
		if ( '' !== $seed['state'] && $customer->get_billing_state() !== $seed['state'] ) {
			$customer->set_billing_state( $seed['state'] );
			$modified = true;
		}

		if ( '' !== $seed['city'] && $customer->get_shipping_city() !== $seed['city'] ) {
			$customer->set_shipping_city( $seed['city'] );
			$modified = true;
		}
		if ( '' !== $seed['postcode'] && $customer->get_shipping_postcode() !== $seed['postcode'] ) {
			$customer->set_shipping_postcode( $seed['postcode'] );
			$modified = true;
		}
		if ( '' !== $seed['address_1'] && $customer->get_shipping_address_1() !== $seed['address_1'] ) {
			$customer->set_shipping_address_1( $seed['address_1'] );
			$modified = true;
		}
		if ( '' !== $seed['address_2'] && $customer->get_shipping_address_2() !== $seed['address_2'] ) {
			$customer->set_shipping_address_2( $seed['address_2'] );
			$modified = true;
		}
		if ( '' !== $seed['state'] && $customer->get_shipping_state() !== $seed['state'] ) {
			$customer->set_shipping_state( $seed['state'] );
			$modified = true;
		}

		if ( $modified ) {
			try {
				$customer->save();
			} catch ( Exception $exception ) {
				unset( $exception );
				// Do not block checkout if customer save fails; handled silently.
			}
		}
	}

	/**
	 * Guarantee pickup addresses are present on the customer during Store API checkout updates.
	 *
	 * @param WC_Customer     $customer Customer instance.
	 * @param WP_REST_Request $request  Request data.
	 * @return WC_Customer
	 */
	public function ensure_pickup_customer_address_for_store_api( $customer, $request ) {
		unset( $request );
		if ( is_admin() || ! $this->is_pickup_mode() ) {
			return $customer;
		}
		if ( ! $customer || ! is_object( $customer ) || ! method_exists( $customer, 'get_id' ) ) {
			return $customer;
		}

		$seed = $this->get_pickup_address_seed();

		if ( '' !== $seed['city'] && '' === $customer->get_billing_city() ) {
			$customer->set_billing_city( $seed['city'] );
		}
		if ( '' !== $seed['postcode'] && '' === $customer->get_billing_postcode() ) {
			$customer->set_billing_postcode( $seed['postcode'] );
		}
		if ( '' !== $seed['address_1'] && '' === $customer->get_billing_address_1() ) {
			$customer->set_billing_address_1( $seed['address_1'] );
		}
		if ( '' !== $seed['address_2'] && '' === $customer->get_billing_address_2() ) {
			$customer->set_billing_address_2( $seed['address_2'] );
		}
		if ( '' !== $seed['state'] && '' === $customer->get_billing_state() ) {
			$customer->set_billing_state( $seed['state'] );
		}

		if ( '' !== $seed['city'] && '' === $customer->get_shipping_city() ) {
			$customer->set_shipping_city( $seed['city'] );
		}
		if ( '' !== $seed['postcode'] && '' === $customer->get_shipping_postcode() ) {
			$customer->set_shipping_postcode( $seed['postcode'] );
		}
		if ( '' !== $seed['address_1'] && '' === $customer->get_shipping_address_1() ) {
			$customer->set_shipping_address_1( $seed['address_1'] );
		}
		if ( '' !== $seed['address_2'] && '' === $customer->get_shipping_address_2() ) {
			$customer->set_shipping_address_2( $seed['address_2'] );
		}
		if ( '' !== $seed['state'] && '' === $customer->get_shipping_state() ) {
			$customer->set_shipping_state( $seed['state'] );
		}

		return $customer;
	}

	/**
	 * Resolve the pickup address seed using session data with store defaults as fallback.
	 *
	 * @return array
	 */
	private function get_pickup_address_seed(): array {
		$seed = array(
			'address_1' => '',
			'address_2' => '',
			'city'      => '',
			'postcode'  => '',
			'state'     => '',
		);

		if ( class_exists( 'Foodord_Location_Service' ) ) {
			$session = Foodord_Location_Service::get_session();
			if ( ! empty( $session['allowed'] ) ) {
				$seed['city']     = (string) ( $session['city'] ?? '' );
				$seed['postcode'] = (string) ( $session['postal'] ?? '' );
			}
		}

		if ( '' === $seed['city'] || '' === $seed['postcode'] ) {
			$seed['city'] = (string) get_option( 'woocommerce_store_city', '' );
			$wc           = function_exists( 'WC' ) ? WC() : null;
			if ( $wc && isset( $wc->countries ) ) {
				$countries = $wc->countries;
				if ( '' === $seed['city'] && $countries && method_exists( $countries, 'get_base_city' ) ) {
					$seed['city'] = (string) $countries->get_base_city();
				}
				if ( $countries && method_exists( $countries, 'get_base_postcode' ) ) {
					$seed['postcode'] = (string) $countries->get_base_postcode();
				}
			}
			if ( '' === $seed['postcode'] ) {
				$seed['postcode'] = (string) get_option( 'woocommerce_store_postcode', '' );
			}
		}

		$raw_state = (string) get_option( 'woocommerce_default_country', '' );
		if ( '' !== $raw_state && strpos( $raw_state, ':' ) !== false ) {
			list( , $raw_state ) = explode( ':', $raw_state );
		}
		$seed['state'] = $raw_state;

		$seed['address_1'] = (string) get_option( 'woocommerce_store_address', '' );
		$seed['address_2'] = (string) get_option( 'woocommerce_store_address_2', '' );

		foreach ( $seed as $key => $value ) {
			$seed[ $key ] = sanitize_text_field( $value );
		}

		return $seed;
	}


	/**
	 * Add pickup mode marker to body classes for simple front-end toggles.
	 *
	 * @param array $classes Body classes.
	 * @return array
	 */
	public function add_pickup_body_class( array $classes ): array {
		if ( is_admin() ) {
			return $classes;
		}

		if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
			return $classes;
		}

		if ( $this->is_pickup_mode() && ! in_array( 'foodord-pickup-mode', $classes, true ) ) {
			$classes[] = 'foodord-pickup-mode';
		}

		return $classes;
	}

	/**
	 * Detect whether current order mode is pickup.
	 *
	 * @return bool
	 */
	private function is_pickup_mode(): bool {
		if ( function_exists( 'foodord_get_order_mode' ) ) {
			return ( 'pickup' === foodord_get_order_mode() );
		}
		if ( function_exists( 'WC' ) && WC()->session ) {
			$mode = (string) WC()->session->get( 'foodord_order_mode', 'delivery' );
			if ( in_array( $mode, array( 'delivery', 'pickup' ), true ) ) {
				return ( 'pickup' === $mode );
			}
		}
		return false;
	}
}
