<?php
/**
 * GiveWP form rendering integration for country routing.
 *
 * @since   1.0.0
 * @package DonationRouter
 */

declare( strict_types=1 );
namespace DonationRouter;

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

/**
 * Validates submitted routing data on GiveWP's donation form validation hook.
 *
 * Hooks into GiveWP's donation form validation to:
 *   1. Confirm the submitted country code matches a configured routing rule.
 *   2. Confirm the submitted form_id matches the rule for that country.
 *
 * The account actually charged is resolved and recorded server-side by
 * PayPal_Credential_Router (from the routing table, never client input); the
 * `_ador_account_id` hidden field is advisory only and is never trusted.
 *
 * The hidden field names injected by the JavaScript selector:
 *   - `_ador_donor_country`  (ISO code, from client)
 *   - `_ador_account_id`     (account ID hint, server re-resolves authoritatively)
 *
 * @since 1.0.0
 */
class Form_Renderer {

	/**
	 * POST field name for the donor's submitted country code.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	public const FIELD_DONOR_COUNTRY = '_ador_donor_country';

	/**
	 * POST field name for the resolved account ID (set by JS, enforced server-side).
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	public const FIELD_ACCOUNT_ID = '_ador_account_id';

	/**
	 * Routing data source.
	 *
	 * @since 1.0.0
	 *
	 * @var Country_Routing_Repository_Interface
	 */
	private Country_Routing_Repository_Interface $routing_repo;

	/**
	 * Initialise with required dependencies.
	 *
	 * @since 1.0.0
	 *
	 * @param Country_Routing_Repository_Interface $routing_repo  Routing data source.
	 */
	public function __construct( Country_Routing_Repository_Interface $routing_repo ) {
		$this->routing_repo = $routing_repo;
	}

	/**
	 * Register WordPress hooks.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function register_hooks(): void {
		// GiveWP's donation-validation action (includes/process-donation.php).
		// The previously-hooked `give_donation_form_validate_fields` is a plain
		// function name in GiveWP, not a hook, so the validation never ran. This
		// is defense-in-depth only: PayPal_Credential_Router resolves the account
		// from the submitted form id server-side regardless, so a tampered country
		// field cannot misroute the money. This action fires on the legacy (v2)
		// donation-processing path; v3 forms validate via a separate GiveWP route.
		add_action( 'give_checkout_error_checks', array( $this, 'validate_country_routing' ) );
	}

	/**
	 * Validate that the submitted country matches a configured routing rule.
	 *
	 * Fires on the `give_checkout_error_checks` action. Registers a GiveWP
	 * validation error (via give_set_error) when the submitted country/form do
	 * not match a configured routing rule.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function validate_country_routing(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		if ( ! isset( $_POST[ self::FIELD_DONOR_COUNTRY ] ) ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$country_code = strtoupper( sanitize_key( (string) wp_unslash( $_POST[ self::FIELD_DONOR_COUNTRY ] ) ) );

		if ( '' === $country_code ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$submitted_form_id = absint( $_POST['give-form-id'] ?? 0 );

		try {
			$routing = $this->routing_repo->find_by_country_code( $country_code );
		} catch ( Country_Routing_Not_Found_Exception $e ) {
			give_set_error(
				'ador_invalid_country',
				__( 'The selected country is not configured for online donations. Please contact us for assistance.', 'alamin-donation-router' )
			);
			return;
		}

		if ( $submitted_form_id > 0 && $routing->form_id !== $submitted_form_id ) {
			give_set_error(
				'ador_form_mismatch',
				__( 'The donation form does not match your selected country. Please reload the page and try again.', 'alamin-donation-router' )
			);
		}
	}
}
