<?php

namespace BSD_Split_Pay_Stripe_Connect_Woo\Inc\Admin;

defined( 'ABSPATH' ) || exit;

if ( ! function_exists( 'BSD_Split_Pay_Stripe_Connect_Woo\Inc\Admin\bsd_scsp_settings_api' ) ) {
	function bsd_scsp_settings_api() {
		// BEGIN Replace legacy options - Added in v2.6
		$legacy_bsd_wc_scsp_stripe_connected_account = get_option( 'bsd_wc_scsp_stripe_connected_account' );
		$legacy_bsd_wc_scsp_transfer_percentage      = get_option( 'bsd_wc_scsp_transfer_percentage' );
		$legacy_bsd_wc_scsp_exclude_shipping         = get_option( 'bsd_wc_scsp_exclude_shipping' );
		$legacy_bsd_wc_scsp_exclude_tax              = get_option( 'bsd_wc_scsp_exclude_tax' );

		if ( $legacy_bsd_wc_scsp_stripe_connected_account ) {
			update_option( 'bsd_split_pay_stripe_connect_woo_stripe_connected_account', $legacy_bsd_wc_scsp_stripe_connected_account );
			delete_option( 'bsd_wc_scsp_stripe_connected_account' );
		}

		if ( $legacy_bsd_wc_scsp_transfer_percentage ) {
			update_option( 'bsd_split_pay_stripe_connect_woo_transfer_percentage', $legacy_bsd_wc_scsp_transfer_percentage );
			delete_option( 'bsd_wc_scsp_transfer_percentage' );
		}

		if ( $legacy_bsd_wc_scsp_exclude_shipping ) {
			$value = $legacy_bsd_wc_scsp_exclude_shipping == 'yes' ? true : false;
			update_option( 'bsd_split_pay_stripe_connect_woo_exclude_shipping', $value );
			delete_option( 'bsd_wc_scsp_exclude_shipping' );
		}

		if ( $legacy_bsd_wc_scsp_exclude_tax ) {
			$value = $legacy_bsd_wc_scsp_exclude_tax == 'yes' ? true : false;
			update_option( 'bsd_split_pay_stripe_connect_woo_exclude_tax', $value );
			delete_option( 'bsd_wc_scsp_exclude_tax' );
		}
		// END Replace legacy options

		// BEGIN Delete legacy Exclude Shipping and Exclude Tax settings - Added in 3.2
		delete_option( 'bsd_split_pay_stripe_connect_woo_exclude_shipping' );
		delete_option( 'bsd_split_pay_stripe_connect_woo_exclude_tax' );

		register_setting(
			'bsd_scsp_options_main',
			'bsd_trnsfr_shpng_fees',
			array(
				'type'              => 'boolean',
				'show_in_rest'      => true,
				'sanitize_callback' => 'sanitize_text_field',
			)
		);

		/*
		 * 3.7.5 — opt-in "wipe everything on uninstall" toggle.
		 *
		 * Default is 0 (safe — preserve customer data). When set to '1' AND
		 * the user uninstalls the plugin, uninstall.php drops the three
		 * SPP custom tables (transfer_log, strp_accnt, strp_connected_id)
		 * in addition to deleting the 23 wp_options it always cleans up.
		 *
		 * Sanitized to '0'|'1' so a misconfigured POST (e.g. raw "yes")
		 * doesn't end up tested against truthy / falsy inconsistently in
		 * uninstall.php.
		 */
		register_setting(
			'bsd_scsp_options_main',
			'spp_uninstall_remove_all_data',
			array(
				'type'              => 'boolean',
				'show_in_rest'      => false,
				'sanitize_callback' => __NAMESPACE__ . '\\spp_sanitize_bool_string',
				'default'           => '0',
			)
		);
		register_setting(
			'spp_vendor_options',
			'vendor_onboading',
			array(
				'type'              => 'boolean',
				'show_in_rest'      => true,
				'sanitize_callback' => 'sanitize_text_field',
			)
		);
		register_setting(
			'spp_vendor_options',
			'enable_title_description',
			array(
				'type'              => 'boolean',
				'show_in_rest'      => true,
				'sanitize_callback' => 'sanitize_text_field',
			)
		);
		register_setting(
			'spp_vendor_options',
			'onboarding_title',
			array(
				'type'              => 'string',
				'show_in_rest'      => true,
				'sanitize_callback' => 'sanitize_text_field',
			)
		);
		register_setting(
			'spp_vendor_options',
			'onboarding_description',
			array(
				'type'              => 'string',
				'show_in_rest'      => true,
				'sanitize_callback' => 'sanitize_text_field',
			)
		);

	// 3.7.5: each key field gets a MODE-SPECIFIC sanitizer so a live key can't
	// be saved into a test field (or vice-versa) — the misconfiguration behind
	// the "No such destination: … test mode, live key" transfer failures.
	register_setting(
		'spp_stripe_configuration_options',
		'stripe_test_api_public_key',
		array(
			'type'              => 'string',
			'show_in_rest'      => true,
			'sanitize_callback' => __NAMESPACE__ . '\spp_sanitize_test_publishable_key',
		)
	);
	register_setting(
		'spp_stripe_configuration_options',
		'stripe_test_api_secret_key',
		array(
			'type'              => 'string',
			'show_in_rest'      => false,
			'sanitize_callback' => __NAMESPACE__ . '\spp_sanitize_test_secret_key',
		)
	);

	register_setting(
		'spp_stripe_configuration_options',
		'stripe_api_public_key',
		array(
			'type'              => 'string',
			'show_in_rest'      => true,
			'sanitize_callback' => __NAMESPACE__ . '\spp_sanitize_live_publishable_key',
		)
	);
	register_setting(
		'spp_stripe_configuration_options',
		'stripe_api_secret_key',
		array(
			'type'              => 'string',
			'show_in_rest'      => false,
			'sanitize_callback' => __NAMESPACE__ . '\spp_sanitize_live_secret_key',
		)
	);
	}
}


if ( ! function_exists( 'BSD_Split_Pay_Stripe_Connect_Woo\Inc\Admin\spp_sanitize_publishable_key' ) ) {
	function spp_sanitize_publishable_key( $value ) {
		$value = sanitize_text_field( $value );
		// SEC-051 (defense-in-depth, 3.7.5): reject keys far too short to be a real
		// Stripe publishable key (pk_ keys are ~100+ chars). Empty stays allowed.
		if ( '' !== $value && strlen( $value ) < 20 ) {
			add_settings_error(
				'spp_stripe_configuration_options',
				'short_publishable_key',
				__( 'The Stripe publishable key you entered is too short to be valid and was not saved. Copy the full key from your Stripe Dashboard.', 'bsd-split-pay-stripe-connect-woo' ),
				'error'
			);
			return '';
		}
		if ( ! empty( $value ) && strpos( $value, 'pk_' ) !== 0 ) {
			add_settings_error(
				'spp_stripe_configuration_options',
				'invalid_publishable_key',
				__( 'Invalid Publishable Key format. Stripe publishable keys start with "pk_test_" or "pk_live_".', 'bsd-split-pay-stripe-connect-woo' ),
				'error'
			);
		}
		return $value;
	}
}

if ( ! function_exists( 'BSD_Split_Pay_Stripe_Connect_Woo\Inc\Admin\spp_sanitize_secret_key' ) ) {
	function spp_sanitize_secret_key( $value ) {
		$value = sanitize_text_field( $value );
		// SEC-051 (defense-in-depth, 3.7.5): reject keys far too short to be a real
		// Stripe secret (sk_/rk_ keys are ~100+ chars). Stops a truncated or
		// fat-fingered key being saved as "valid". Empty stays allowed (clears field).
		if ( '' !== $value && strlen( $value ) < 20 ) {
			add_settings_error(
				'spp_stripe_configuration_options',
				'short_secret_key',
				__( 'The Stripe secret key you entered is too short to be valid and was not saved. Copy the full key from your Stripe Dashboard.', 'bsd-split-pay-stripe-connect-woo' ),
				'error'
			);
			return '';
		}
		// Four-prefix policy: Stripe issues secret keys with one of four prefixes —
		// sk_test_, sk_live_, rk_test_, rk_live_. The validator accepts ANY key that
		// starts with 'sk_' or 'rk_' (so test + live restricted-API keys both pass).
		// The user-facing error message MUST list all four prefixes — pre-3.7.5
		// (sc-7194) it omitted rk_test_, causing customers who pasted a valid
		// restricted test key to get a misleading "invalid format" error and revert
		// to sk_test_, which contradicts our docs + Stripe's RAK best practice.
		if ( ! empty( $value ) && strpos( $value, 'sk_' ) !== 0 && strpos( $value, 'rk_' ) !== 0 ) {
			add_settings_error(
				'spp_stripe_configuration_options',
				'invalid_secret_key',
				__( 'Invalid Secret Key format. Stripe secret keys start with "sk_test_", "sk_live_", "rk_test_", or "rk_live_".', 'bsd-split-pay-stripe-connect-woo' ),
				'error'
			);
		}
		return $value;
	}
}

if ( ! function_exists( 'BSD_Split_Pay_Stripe_Connect_Woo\Inc\Admin\spp_enforce_key_mode' ) ) {
	/**
	 * Mode-prefix guard for the per-field key sanitizers (3.7.5).
	 *
	 * A key that already passed the generic format check is verified against
	 * the field it was entered in: a TEST field must hold a test-prefixed key
	 * and a LIVE field a live-prefixed key. On mismatch we add a clear settings
	 * error and return the PREVIOUSLY-saved value (so a stray paste doesn't also
	 * wipe a good key); on match (or unknown prefix, already flagged by the base
	 * validator) we return the value unchanged.
	 *
	 * This is the entry-point defence against the misconfiguration behind
	 * Stripe's "No such destination: … a similar object exists in test mode, but
	 * a live mode key was used" — a live key sitting in a test slot (or v.v.).
	 *
	 * @param string $value       Key, already generically validated (may be '').
	 * @param string $expected    'test'|'live' — the field's mode.
	 * @param string $kind        'secret'|'publishable'.
	 * @param string $option_name Option this field maps to (to restore old value).
	 * @return string
	 */
	function spp_enforce_key_mode( $value, $expected, $kind, $option_name ) {
		if ( ! is_string( $value ) || $value === '' ) {
			return '';
		}

		$key_mode = '';
		if ( strpos( $value, 'sk_test_' ) === 0 || strpos( $value, 'rk_test_' ) === 0 || strpos( $value, 'pk_test_' ) === 0 ) {
			$key_mode = 'test';
		} elseif ( strpos( $value, 'sk_live_' ) === 0 || strpos( $value, 'rk_live_' ) === 0 || strpos( $value, 'pk_live_' ) === 0 ) {
			$key_mode = 'live';
		}

		// Unknown prefix (the base validator already flagged format) or the
		// mode matches the field → accept as-is.
		if ( $key_mode === '' || $key_mode === $expected ) {
			return $value;
		}

		$field_label = ( $expected === 'test' ) ? __( 'TEST', 'bsd-split-pay-stripe-connect-woo' ) : __( 'LIVE', 'bsd-split-pay-stripe-connect-woo' );
		$key_label   = ( $key_mode === 'test' ) ? __( 'TEST', 'bsd-split-pay-stripe-connect-woo' ) : __( 'LIVE', 'bsd-split-pay-stripe-connect-woo' );
		$kind_label  = ( $kind === 'secret' ) ? __( 'secret', 'bsd-split-pay-stripe-connect-woo' ) : __( 'publishable', 'bsd-split-pay-stripe-connect-woo' );

		add_settings_error(
			'spp_stripe_configuration_options',
			'wrong_mode_' . $expected . '_' . $kind,
			sprintf(
				/* translators: 1: the key's mode (TEST/LIVE), 2: secret|publishable, 3: the field's mode (TEST/LIVE) */
				__( 'You entered a %1$s %2$s key in the %3$s %2$s key field. It was not saved — put %1$s keys in the %1$s field, or paste your %3$s key here.', 'bsd-split-pay-stripe-connect-woo' ),
				$key_label,
				$kind_label,
				$field_label
			),
			'error'
		);

		// Keep whatever was previously saved rather than wiping a good key.
		return (string) get_option( $option_name, '' );
	}
}

if ( ! function_exists( 'BSD_Split_Pay_Stripe_Connect_Woo\Inc\Admin\spp_sanitize_test_secret_key' ) ) {
	/**
	 * Sanitize callback for the TEST secret key field: base validation + reject a live key.
	 *
	 * @since 3.7.5
	 * @param string $value Submitted key.
	 * @return string Sanitized key, or the previously-saved key on mode mismatch.
	 */
	function spp_sanitize_test_secret_key( $value ) {
		return spp_enforce_key_mode( spp_sanitize_secret_key( $value ), 'test', 'secret', 'stripe_test_api_secret_key' );
	}
}

if ( ! function_exists( 'BSD_Split_Pay_Stripe_Connect_Woo\Inc\Admin\spp_sanitize_live_secret_key' ) ) {
	/**
	 * Sanitize callback for the LIVE secret key field: base validation + reject a test key.
	 *
	 * @since 3.7.5
	 * @param string $value Submitted key.
	 * @return string Sanitized key, or the previously-saved key on mode mismatch.
	 */
	function spp_sanitize_live_secret_key( $value ) {
		return spp_enforce_key_mode( spp_sanitize_secret_key( $value ), 'live', 'secret', 'stripe_api_secret_key' );
	}
}

if ( ! function_exists( 'BSD_Split_Pay_Stripe_Connect_Woo\Inc\Admin\spp_sanitize_test_publishable_key' ) ) {
	/**
	 * Sanitize callback for the TEST publishable key field: base validation + reject a live key.
	 *
	 * @since 3.7.5
	 * @param string $value Submitted key.
	 * @return string Sanitized key, or the previously-saved key on mode mismatch.
	 */
	function spp_sanitize_test_publishable_key( $value ) {
		return spp_enforce_key_mode( spp_sanitize_publishable_key( $value ), 'test', 'publishable', 'stripe_test_api_public_key' );
	}
}

if ( ! function_exists( 'BSD_Split_Pay_Stripe_Connect_Woo\Inc\Admin\spp_sanitize_live_publishable_key' ) ) {
	/**
	 * Sanitize callback for the LIVE publishable key field: base validation + reject a test key.
	 *
	 * @since 3.7.5
	 * @param string $value Submitted key.
	 * @return string Sanitized key, or the previously-saved key on mode mismatch.
	 */
	function spp_sanitize_live_publishable_key( $value ) {
		return spp_enforce_key_mode( spp_sanitize_publishable_key( $value ), 'live', 'publishable', 'stripe_api_public_key' );
	}
}

if ( ! function_exists( 'BSD_Split_Pay_Stripe_Connect_Woo\Inc\Admin\bsd_scsp_settings_int_sanitize' ) ) {
	function bsd_scsp_settings_int_sanitize( $input ) {
		if ( is_array( $input ) ) {
			$input['quantity'] = absint( $input['quantity'] );

			if ( $input['quantity'] > 100 ) {
				$input['quantity'] = 100;
			}
		} else {
			$input = floatval( $input );

			if ( $input > 100 ) {
				$input = 100;
			}
		}

		return $input;
	}
}

if ( ! function_exists( 'BSD_Split_Pay_Stripe_Connect_Woo\\Inc\\Admin\\spp_sanitize_bool_string' ) ) {
	/**
	 * Normalise a boolean-shaped form value to the literal strings '0' or '1'.
	 *
	 * Used by the spp_uninstall_remove_all_data option (3.7.5). Accepting
	 * '1'/'on'/'true'/true → '1', everything else → '0'. The destructive
	 * uninstall.php branch tests `=== '1'` to decide whether to drop the
	 * custom tables, so the canonical-form requirement is enforced here at
	 * the sanitize-callback layer.
	 *
	 * @param mixed $value Raw POSTed value from the settings form.
	 * @return string Literal '0' or '1'.
	 */
	function spp_sanitize_bool_string( $value ): string {
		if ( true === $value || 1 === $value || '1' === $value || 'on' === $value || 'true' === $value || 'yes' === $value ) {
			return '1';
		}
		return '0';
	}
}
