<?php
/**
 * B2B checkout capture — DUAL implementation (block + classic) writing unified
 * HPOS-safe order meta: _fepw_customer_type, _fepw_siren, _fepw_tva.
 *
 * Validation is fully LOCAL (Luhn SIREN incl. the La Poste 356000000 exception;
 * FR TVA key = (12 + 3*(SIREN mod 97)) mod 97). No external service is called.
 *
 * @package FEPW
 */

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

/**
 * Class FEPW_Checkout
 */
class FEPW_Checkout {

	/**
	 * Singleton.
	 *
	 * @var FEPW_Checkout|null
	 */
	private static $instance = null;

	/**
	 * Instance.
	 *
	 * @return FEPW_Checkout
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Constructor: register both checkout stacks.
	 */
	private function __construct() {
		// --- Block checkout (Additional Checkout Fields API, Woo 8.9+). ---
		add_action( 'woocommerce_init', array( $this, 'register_block_fields' ) );
		add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'unify_block_meta' ) );

		// --- Classic shortcode checkout. ---
		add_filter( 'woocommerce_checkout_fields', array( $this, 'register_classic_fields' ) );
		add_action( 'woocommerce_after_checkout_validation', array( $this, 'validate_classic' ), 10, 2 );
		add_action( 'woocommerce_checkout_create_order', array( $this, 'save_classic_meta' ), 10, 2 );

		// Admin order screen: show captured values.
		add_action( 'woocommerce_admin_order_data_after_billing_address', array( $this, 'render_admin_order_fields' ) );
	}

	// ------------------------------------------------------------ Block stack.

	/**
	 * Register block-checkout fields.
	 */
	public function register_block_fields() {
		if ( ! function_exists( 'woocommerce_register_additional_checkout_field' ) ) {
			return;
		}

		woocommerce_register_additional_checkout_field(
			array(
				'id'       => 'fepw/customer-type',
				'label'    => __( 'I am ordering as', 'buildsbyluke-facture-electronique-for-woocommerce' ),
				'location' => 'contact',
				'type'     => 'select',
				'options'  => array(
					array(
						'value' => 'b2c',
						'label' => __( 'An individual (particulier)', 'buildsbyluke-facture-electronique-for-woocommerce' ),
					),
					array(
						'value' => 'b2b',
						'label' => __( 'A business (professionnel)', 'buildsbyluke-facture-electronique-for-woocommerce' ),
					),
				),
			)
		);
		woocommerce_register_additional_checkout_field(
			array(
				'id'                => 'fepw/siren',
				'label'             => __( 'SIREN (9 digits, businesses)', 'buildsbyluke-facture-electronique-for-woocommerce' ),
				'location'          => 'contact',
				'type'              => 'text',
				'sanitize_callback' => array( $this, 'sanitize_siren' ),
				'validate_callback' => array( $this, 'validate_siren_field' ),
			)
		);
		woocommerce_register_additional_checkout_field(
			array(
				'id'                => 'fepw/tva',
				'label'             => __( 'VAT number (optional, e.g. FRXX123456789)', 'buildsbyluke-facture-electronique-for-woocommerce' ),
				'location'          => 'contact',
				'type'              => 'text',
				'sanitize_callback' => array( $this, 'sanitize_tva' ),
				'validate_callback' => array( $this, 'validate_tva_field' ),
			)
		);
	}

	/**
	 * Copy block-API storage into the unified meta keys.
	 *
	 * @param WC_Order $order Order.
	 */
	public function unify_block_meta( $order ) {
		if ( ! is_a( $order, 'WC_Order' ) ) {
			return;
		}
		$map = array(
			'fepw/customer-type' => '_fepw_customer_type',
			'fepw/siren'         => '_fepw_siren',
			'fepw/tva'           => '_fepw_tva',
		);
		foreach ( $map as $field_id => $meta_key ) {
			$value = '';
			if ( class_exists( '\Automattic\WooCommerce\Blocks\Package' ) && function_exists( 'wc_get_container' ) ) {
				try {
					$fields = wc_get_container()->get( \Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields::class );
					$value  = (string) $fields->get_field_from_object( $field_id, $order, 'other' );
				} catch ( Throwable $e ) {
					$value = '';
				}
			}
			if ( '' !== $value ) {
				$order->update_meta_data( $meta_key, $value );
			}
		}
		$order->save();
	}

	// ---------------------------------------------------------- Classic stack.

	/**
	 * Register classic-checkout fields.
	 *
	 * @param array $fields Checkout fields.
	 * @return array
	 */
	public function register_classic_fields( $fields ) {
		$fields['billing']['fepw_customer_type'] = array(
			'type'     => 'select',
			'label'    => __( 'I am ordering as', 'buildsbyluke-facture-electronique-for-woocommerce' ),
			'required' => false,
			'options'  => array(
				'b2c' => __( 'An individual (particulier)', 'buildsbyluke-facture-electronique-for-woocommerce' ),
				'b2b' => __( 'A business (professionnel)', 'buildsbyluke-facture-electronique-for-woocommerce' ),
			),
			'priority' => 120,
		);
		$fields['billing']['fepw_siren'] = array(
			'type'     => 'text',
			'label'    => __( 'SIREN (9 digits, businesses)', 'buildsbyluke-facture-electronique-for-woocommerce' ),
			'required' => false,
			'priority' => 121,
		);
		$fields['billing']['fepw_tva'] = array(
			'type'     => 'text',
			'label'    => __( 'VAT number (optional)', 'buildsbyluke-facture-electronique-for-woocommerce' ),
			'required' => false,
			'priority' => 122,
		);
		return $fields;
	}

	/**
	 * Classic validation.
	 *
	 * @param array    $data   Posted data.
	 * @param WP_Error $errors Errors.
	 */
	public function validate_classic( $data, $errors ) {
		$type  = isset( $data['fepw_customer_type'] ) ? $data['fepw_customer_type'] : 'b2c';
		$siren = isset( $data['fepw_siren'] ) ? $this->sanitize_siren( $data['fepw_siren'] ) : '';
		$tva   = isset( $data['fepw_tva'] ) ? $this->sanitize_tva( $data['fepw_tva'] ) : '';

		$settings = get_option( 'fepw_settings', array() );

		if ( 'b2b' === $type && '' === $siren && ! empty( $settings['require_siren_b2b'] ) ) {
			$errors->add( 'fepw_siren', __( 'Please provide your SIREN (9 digits) for a business order — it is required on French e-invoices.', 'buildsbyluke-facture-electronique-for-woocommerce' ) );
		}
		if ( '' !== $siren && ! self::is_valid_siren( $siren ) ) {
			$errors->add( 'fepw_siren', __( 'This SIREN does not look valid (9 digits, checksum failed).', 'buildsbyluke-facture-electronique-for-woocommerce' ) );
		}
		if ( '' !== $tva && ! self::is_plausible_tva( $tva, $siren ) ) {
			$errors->add( 'fepw_tva', __( 'This VAT number does not look valid.', 'buildsbyluke-facture-electronique-for-woocommerce' ) );
		}
	}

	/**
	 * Persist classic fields into unified meta.
	 *
	 * @param WC_Order $order Order.
	 * @param array    $data  Posted data.
	 */
	public function save_classic_meta( $order, $data ) {
		if ( isset( $data['fepw_customer_type'] ) && in_array( $data['fepw_customer_type'], array( 'b2b', 'b2c' ), true ) ) {
			$order->update_meta_data( '_fepw_customer_type', $data['fepw_customer_type'] );
		}
		if ( ! empty( $data['fepw_siren'] ) ) {
			$order->update_meta_data( '_fepw_siren', $this->sanitize_siren( $data['fepw_siren'] ) );
		}
		if ( ! empty( $data['fepw_tva'] ) ) {
			$order->update_meta_data( '_fepw_tva', $this->sanitize_tva( $data['fepw_tva'] ) );
		}
	}

	// ------------------------------------------------------------- Validation.

	/**
	 * Sanitize SIREN: digits only.
	 *
	 * @param string $value Raw.
	 * @return string
	 */
	public function sanitize_siren( $value ) {
		return preg_replace( '/\D/', '', (string) $value );
	}

	/**
	 * Sanitize TVA: uppercase alnum.
	 *
	 * @param string $value Raw.
	 * @return string
	 */
	public function sanitize_tva( $value ) {
		return strtoupper( preg_replace( '/[^A-Za-z0-9]/', '', (string) $value ) );
	}

	/**
	 * Block-API SIREN validation.
	 *
	 * @param string $value Value.
	 * @return WP_Error|true
	 */
	public function validate_siren_field( $value ) {
		$value = $this->sanitize_siren( $value );
		if ( '' !== $value && ! self::is_valid_siren( $value ) ) {
			return new WP_Error( 'fepw_siren', __( 'This SIREN does not look valid (9 digits, checksum failed).', 'buildsbyluke-facture-electronique-for-woocommerce' ) );
		}
		return true;
	}

	/**
	 * Block-API TVA validation.
	 *
	 * @param string $value Value.
	 * @return WP_Error|true
	 */
	public function validate_tva_field( $value ) {
		$value = $this->sanitize_tva( $value );
		if ( '' !== $value && ! self::is_plausible_tva( $value, '' ) ) {
			return new WP_Error( 'fepw_tva', __( 'This VAT number does not look valid.', 'buildsbyluke-facture-electronique-for-woocommerce' ) );
		}
		return true;
	}

	/**
	 * Luhn check for SIREN (with the documented La Poste exception).
	 *
	 * @param string $siren 9-digit string.
	 * @return bool
	 */
	public static function is_valid_siren( $siren ) {
		if ( ! preg_match( '/^\d{9}$/', $siren ) ) {
			return false;
		}
		if ( '356000000' === $siren ) {
			return true; // La Poste: legally valid, violates Luhn.
		}
		$sum = 0;
		for ( $i = 0; $i < 9; $i++ ) {
			$digit = (int) $siren[ $i ];
			if ( 1 === $i % 2 ) {
				$digit *= 2;
				if ( $digit > 9 ) {
					$digit -= 9;
				}
			}
			$sum += $digit;
		}
		return 0 === $sum % 10;
	}

	/**
	 * Plausibility check for a VAT number; for FR numbers, cross-check the key
	 * against the SIREN when we have it: key = (12 + 3 * (SIREN mod 97)) mod 97.
	 *
	 * @param string $tva   VAT number (sanitized).
	 * @param string $siren SIREN when known ('' otherwise).
	 * @return bool
	 */
	public static function is_plausible_tva( $tva, $siren = '' ) {
		if ( ! preg_match( '/^[A-Z]{2}[A-Z0-9]{2,12}$/', $tva ) ) {
			return false;
		}
		if ( 0 !== strpos( $tva, 'FR' ) ) {
			return true; // Non-FR EU number: format-plausible; VIES soft-check is optional.
		}
		if ( ! preg_match( '/^FR([0-9A-Z]{2})(\d{9})$/', $tva, $m ) ) {
			return false;
		}
		$fr_siren = $m[2];
		if ( '' !== $siren && $siren !== $fr_siren ) {
			return false;
		}
		if ( ctype_digit( $m[1] ) ) {
			$expected = ( 12 + 3 * ( (int) $fr_siren % 97 ) ) % 97;
			return (int) $m[1] === $expected;
		}
		return true; // Alphanumeric keys exist for special cases; accept format.
	}

	/**
	 * Read the unified fields from an order.
	 *
	 * @param WC_Order $order Order.
	 * @return array{type:string,siren:string,tva:string}
	 */
	public static function get_order_fields( $order ) {
		return array(
			'type'  => (string) $order->get_meta( '_fepw_customer_type' ) ? (string) $order->get_meta( '_fepw_customer_type' ) : 'b2c',
			'siren' => (string) $order->get_meta( '_fepw_siren' ),
			'tva'   => (string) $order->get_meta( '_fepw_tva' ),
		);
	}

	/**
	 * Admin order screen display.
	 *
	 * @param WC_Order $order Order.
	 */
	public function render_admin_order_fields( $order ) {
		$fields = self::get_order_fields( $order );
		if ( 'b2b' !== $fields['type'] && '' === $fields['siren'] ) {
			return;
		}
		echo '<p><strong>' . esc_html__( 'French e-invoicing', 'buildsbyluke-facture-electronique-for-woocommerce' ) . ':</strong> ';
		echo esc_html(
			sprintf(
				/* translators: 1: customer type, 2: SIREN, 3: VAT number. */
				__( 'Type: %1$s · SIREN: %2$s · VAT: %3$s', 'buildsbyluke-facture-electronique-for-woocommerce' ),
				'b2b' === $fields['type'] ? 'B2B' : 'B2C',
				$fields['siren'] ? $fields['siren'] : '—',
				$fields['tva'] ? $fields['tva'] : '—'
			)
		) . '</p>';
	}
}
