<?php
/**
 * Settings admin page.
 *
 * @package WPDudeProducts
 */

declare(strict_types=1);

namespace WPDude\Products\Admin;

use WPDude\Products\Providers\Stripe\Stripe_Provider;
use WPDude\Products\REST\REST_Loader;
use WPDude\Products\Security\Secrets;
use WPDude\Products\Settings\Settings;
use WPDude\Products\Support\Countries;
use WPDude\Products\Support\Currencies;

/**
 * Store + Stripe settings.
 */
final class Settings_Page {

	/**
	 * Register hooks.
	 */
	public function register(): void {
		add_action( 'admin_init', array( $this, 'handle_save' ) );
	}

	/**
	 * Persist settings (and optionally test Stripe + webhook).
	 */
	public function handle_save(): void {
		if ( ! isset( $_POST['wpdude_dc_settings_nonce'] ) ) {
			return;
		}
		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( (string) $_POST['wpdude_dc_settings_nonce'] ) ), 'wpdude_dc_save_settings' ) ) {
			return;
		}
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		if ( empty( $_POST['wpdude_dc_settings_submit'] ) && empty( $_POST['wpdude_dc_test_stripe_connection'] ) ) {
			return;
		}

		$currency = Currencies::sanitize(
			sanitize_text_field( wp_unslash( (string) ( $_POST['wpdude_dc_currency'] ?? 'gbp' ) ) ),
			'gbp'
		);

		$tax_behavior = sanitize_key( wp_unslash( (string) ( $_POST['wpdude_dc_stripe_tax_behavior'] ?? 'exclusive' ) ) );
		if ( ! in_array( $tax_behavior, array( 'exclusive', 'inclusive' ), true ) ) {
			$tax_behavior = 'exclusive';
		}

		$countries = Countries::sanitize_list( isset( $_POST['wpdude_dc_sell_to_countries'] ) ? wp_unslash( (array) $_POST['wpdude_dc_sell_to_countries'] ) : array() ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized

		$settings_update = array(
			'currency'               => $currency,
			'test_mode'              => ! empty( $_POST['wpdude_dc_test_mode'] ),
			'local_confirm_payments' => ! empty( $_POST['wpdude_dc_local_confirm'] ),
			'stripe_tax_enabled'     => ! empty( $_POST['wpdude_dc_stripe_tax'] ),
			'stripe_tax_behavior'    => $tax_behavior,
			'sell_to_countries'      => $countries,
		);

		/**
		 * Filter settings payload before save (Pro adds webhooks / email customization).
		 *
		 * @param array<string, mixed> $settings_update Pending settings.
		 */
		$settings_update = (array) apply_filters( 'wpdude_dc_settings_update', $settings_update );

		Settings::update( $settings_update );

		$secret_updates = array(
			'test_publishable_key' => sanitize_text_field( wp_unslash( (string) ( $_POST['wpdude_dc_test_publishable_key'] ?? '' ) ) ),
			'test_secret_key'      => sanitize_text_field( wp_unslash( (string) ( $_POST['wpdude_dc_test_secret_key'] ?? '' ) ) ),
			'test_webhook_secret'  => sanitize_text_field( wp_unslash( (string) ( $_POST['wpdude_dc_test_webhook_secret'] ?? '' ) ) ),
			'live_publishable_key' => sanitize_text_field( wp_unslash( (string) ( $_POST['wpdude_dc_live_publishable_key'] ?? '' ) ) ),
			'live_secret_key'      => sanitize_text_field( wp_unslash( (string) ( $_POST['wpdude_dc_live_secret_key'] ?? '' ) ) ),
			'live_webhook_secret'  => sanitize_text_field( wp_unslash( (string) ( $_POST['wpdude_dc_live_webhook_secret'] ?? '' ) ) ),
		);

		/**
		 * Filter secrets payload before save (Pro adds outgoing webhook secret).
		 *
		 * @param array<string, string> $secret_updates Pending secrets.
		 */
		$secret_updates = (array) apply_filters( 'wpdude_dc_secrets_update', $secret_updates );

		Secrets::update( $secret_updates );

		$redirect_args = array( 'wpdude_dc_saved' => '1' );

		if ( ! empty( $_POST['wpdude_dc_test_stripe_connection'] ) ) {
			$stripe = new Stripe_Provider();
			$ping   = $stripe->ping();
			if ( is_wp_error( $ping ) ) {
				$redirect_args['wpdude_dc_stripe'] = 'error';
				self::store_stripe_notice( $ping->get_error_message() );
			} elseif ( Settings::is_test_mode() ) {
				$probe = $stripe->probe_webhook();
				if ( is_wp_error( $probe ) ) {
					$redirect_args['wpdude_dc_stripe'] = 'webhook_fail';
					self::store_stripe_notice( $probe->get_error_message() );
				} else {
					$redirect_args['wpdude_dc_stripe'] = 'ok_webhook';
				}
			} else {
				$redirect_args['wpdude_dc_stripe'] = 'ok_live';
			}
		}

		wp_safe_redirect( add_query_arg( $redirect_args, Menu::settings_url() ) );
		exit;
	}

	/**
	 * Persist a full Stripe test notice for the next settings page load.
	 */
	private static function store_stripe_notice( string $message ): void {
		$message = trim( $message );
		if ( '' === $message ) {
			return;
		}
		set_transient( self::stripe_notice_transient_key(), $message, 5 * MINUTE_IN_SECONDS );
	}

	/**
	 * Read and clear the stored Stripe test notice.
	 */
	private static function consume_stripe_notice(): string {
		$key = self::stripe_notice_transient_key();
		$msg = get_transient( $key );
		delete_transient( $key );
		return is_string( $msg ) ? $msg : '';
	}

	/**
	 * Per-user transient key for Stripe test notices.
	 */
	private static function stripe_notice_transient_key(): string {
		return 'wpdude_dc_stripe_notice_' . get_current_user_id();
	}

	/**
	 * Render page.
	 */
	public static function render(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have permission to access this page.', 'dude-commerce' ) );
		}

		$all         = Settings::all();
		$currency    = Settings::get_currency();
		$webhook_url = rest_url( REST_Loader::NAMESPACE . '/stripe/webhook' );
		$countries   = Countries::all();
		$selected    = Settings::get_sell_to_countries();
		?>
		<div class="wrap">
			<h1><?php echo esc_html__( 'Dude Commerce Settings', 'dude-commerce' ); ?></h1>
			<?php
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- admin notice query args after redirect.
			if ( isset( $_GET['wpdude_dc_saved'] ) ) :
				?>
				<div class="notice notice-success is-dismissible"><p><?php echo esc_html__( 'Settings saved.', 'dude-commerce' ); ?></p></div>
				<?php
			endif;

			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
			if ( isset( $_GET['wpdude_dc_stripe'] ) ) :
				$stripe_status  = sanitize_key( wp_unslash( (string) $_GET['wpdude_dc_stripe'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
				$stripe_message = self::consume_stripe_notice();

				if ( 'ok_webhook' === $stripe_status ) :
					?>
					<div class="notice notice-success is-dismissible"><p><?php echo esc_html__( 'Connected to Stripe. Test webhook received successfully.', 'dude-commerce' ); ?></p></div>
					<?php
				elseif ( 'ok_live' === $stripe_status ) :
					?>
					<div class="notice notice-success is-dismissible"><p><?php echo esc_html__( 'Connected to Stripe successfully. Switch to test mode and run the test again to verify inbound webhooks.', 'dude-commerce' ); ?></p></div>
					<?php
				elseif ( 'webhook_fail' === $stripe_status ) :
					if ( '' === $stripe_message ) {
						$stripe_message = __( 'Connected to Stripe, but no webhook arrived. Confirm the Test-mode endpoint URL, events (include checkout.session.expired), and webhook signing secret.', 'dude-commerce' );
					}
					?>
					<div class="notice notice-warning is-dismissible"><p><?php echo esc_html( $stripe_message ); ?></p></div>
					<?php
				else :
					if ( '' === $stripe_message ) {
						$stripe_message = __( 'Unable to connect to Stripe with the configured keys.', 'dude-commerce' );
					}
					?>
					<div class="notice notice-error is-dismissible"><p><?php echo esc_html( $stripe_message ); ?></p></div>
					<?php
				endif;
			endif;
			?>
			<form method="post" action="">
				<?php wp_nonce_field( 'wpdude_dc_save_settings', 'wpdude_dc_settings_nonce' ); ?>

				<h2><?php echo esc_html__( 'Store', 'dude-commerce' ); ?></h2>
				<table class="form-table" role="presentation">
					<tr>
						<th scope="row">
							<label for="wpdude_dc_currency"><?php echo esc_html__( 'Default currency', 'dude-commerce' ); ?></label>
						</th>
						<td>
							<?php
							Currencies::render_select(
								'wpdude_dc_currency',
								'wpdude_dc_currency',
								$currency
							);
							?>
							<p class="description">
								<?php echo esc_html__( 'Used for new products unless you choose another currency on the product.', 'dude-commerce' ); ?>
							</p>
						</td>
					</tr>
					<tr>
						<th scope="row"><?php echo esc_html__( 'Sell to countries', 'dude-commerce' ); ?></th>
						<td>
							<fieldset style="max-height: 200px; overflow: auto; border: 1px solid #c3c4c7; padding: 8px; max-width: 420px;">
								<?php foreach ( $countries as $code => $label ) : ?>
									<label style="display:block; margin: 2px 0;">
										<input type="checkbox" name="wpdude_dc_sell_to_countries[]" value="<?php echo esc_attr( $code ); ?>" <?php checked( in_array( $code, $selected, true ) ); ?> />
										<?php echo esc_html( $label . ' (' . $code . ')' ); ?>
									</label>
								<?php endforeach; ?>
							</fieldset>
							<p class="description"><?php echo esc_html__( 'Countries allowed for the delivery address in Stripe Checkout (full Stripe-supported list).', 'dude-commerce' ); ?></p>
						</td>
					</tr>
				</table>

				<h2><?php echo esc_html__( 'Stripe', 'dude-commerce' ); ?></h2>
				<table class="form-table" role="presentation">
					<tr>
						<th scope="row"><?php echo esc_html__( 'Mode', 'dude-commerce' ); ?></th>
						<td>
							<label>
								<input type="checkbox" name="wpdude_dc_test_mode" value="1" <?php checked( ! empty( $all['test_mode'] ) ); ?> />
								<?php echo esc_html__( 'Test mode', 'dude-commerce' ); ?>
							</label>
						</td>
					</tr>
					<tr>
						<th scope="row"><?php echo esc_html__( 'Local payment confirm', 'dude-commerce' ); ?></th>
						<td>
							<label>
								<input type="checkbox" name="wpdude_dc_local_confirm" value="1" <?php checked( ! empty( $all['local_confirm_payments'] ) ); ?> />
								<?php echo esc_html__( 'Allow confirming payments by re-fetching the Stripe session (test mode / Local sites without webhooks)', 'dude-commerce' ); ?>
							</label>
							<p class="description"><?php echo esc_html__( 'Requires Test mode. On return from Stripe Checkout, the page polls for the webhook and shows “Confirm payment (local test)” when webhooks cannot reach this site — same as Dude Downloads and Dude Paywall.', 'dude-commerce' ); ?></p>
						</td>
					</tr>
					<tr>
						<th scope="row"><?php echo esc_html__( 'Stripe Tax', 'dude-commerce' ); ?></th>
						<td>
							<label>
								<input type="checkbox" name="wpdude_dc_stripe_tax" value="1" <?php checked( ! empty( $all['stripe_tax_enabled'] ) ); ?> />
								<?php echo esc_html__( 'Enable Stripe Tax', 'dude-commerce' ); ?>
							</label>
							<p>
								<label for="wpdude_dc_stripe_tax_behavior"><?php echo esc_html__( 'Tax behavior', 'dude-commerce' ); ?></label>
								<select name="wpdude_dc_stripe_tax_behavior" id="wpdude_dc_stripe_tax_behavior">
									<option value="exclusive" <?php selected( (string) $all['stripe_tax_behavior'], 'exclusive' ); ?>><?php echo esc_html__( 'Exclusive (tax added on top)', 'dude-commerce' ); ?></option>
									<option value="inclusive" <?php selected( (string) $all['stripe_tax_behavior'], 'inclusive' ); ?>><?php echo esc_html__( 'Inclusive (tax included in price)', 'dude-commerce' ); ?></option>
								</select>
							</p>
						</td>
					</tr>
					<tr>
						<th scope="row"><?php echo esc_html__( 'Webhook endpoint', 'dude-commerce' ); ?></th>
						<td>
							<code><?php echo esc_html( $webhook_url ); ?></code>
							<p class="description">
								<?php
								printf(
									/* translators: %s: relative time e.g. "5 minutes ago" or "Never" */
									esc_html__( 'Last Stripe webhook received: %s', 'dude-commerce' ),
									esc_html( Settings::get_last_webhook_human() )
								);
								?>
							</p>
							<p class="description">
								<?php echo esc_html__( 'In Stripe Dashboard → Developers → Webhooks, add this URL and subscribe to these events:', 'dude-commerce' ); ?>
							</p>
							<ul class="description" style="list-style: disc; margin-left: 1.5em;">
								<li><code>checkout.session.completed</code></li>
								<li><code>checkout.session.async_payment_succeeded</code></li>
								<li><code>checkout.session.async_payment_failed</code></li>
								<li><code>checkout.session.expired</code></li>
								<li><code>charge.succeeded</code></li>
								<li><code>charge.refunded</code></li>
							</ul>
							<p class="description">
								<?php echo esc_html__( 'Then paste the signing secret (whsec_…) into the test or live webhook secret field below. On Local, use Stripe CLI to forward events to this URL.', 'dude-commerce' ); ?>
							</p>
						</td>
					</tr>
				</table>

				<h2><?php echo esc_html__( 'Test keys', 'dude-commerce' ); ?></h2>
				<table class="form-table" role="presentation">
					<?php self::secret_row( 'wpdude_dc_test_publishable_key', __( 'Publishable key', 'dude-commerce' ), Secrets::get( 'test_publishable_key' ) ); ?>
					<?php self::secret_row( 'wpdude_dc_test_secret_key', __( 'Secret key', 'dude-commerce' ), Secrets::get( 'test_secret_key' ), true ); ?>
					<?php self::secret_row( 'wpdude_dc_test_webhook_secret', __( 'Webhook secret', 'dude-commerce' ), Secrets::get( 'test_webhook_secret' ), true ); ?>
				</table>

				<h2><?php echo esc_html__( 'Live keys', 'dude-commerce' ); ?></h2>
				<table class="form-table" role="presentation">
					<?php self::secret_row( 'wpdude_dc_live_publishable_key', __( 'Publishable key', 'dude-commerce' ), Secrets::get( 'live_publishable_key' ) ); ?>
					<?php self::secret_row( 'wpdude_dc_live_secret_key', __( 'Secret key', 'dude-commerce' ), Secrets::get( 'live_secret_key' ), true ); ?>
					<?php self::secret_row( 'wpdude_dc_live_webhook_secret', __( 'Webhook secret', 'dude-commerce' ), Secrets::get( 'live_webhook_secret' ), true ); ?>
				</table>

				<?php
				/**
				 * Render Pro settings sections (outgoing webhooks, emails, etc.).
				 *
				 * @param array<string, mixed> $all Settings.
				 */
				do_action( 'wpdude_dc_render_settings_sections', $all );
				?>

				<p class="submit">
					<?php submit_button( __( 'Save settings', 'dude-commerce' ), 'primary', 'wpdude_dc_settings_submit', false ); ?>
					<?php submit_button( __( 'Save and test Stripe connection', 'dude-commerce' ), 'secondary', 'wpdude_dc_test_stripe_connection', false ); ?>
				</p>
				<p class="description">
					<?php
					echo esc_html__(
						'In test mode, “Save and test Stripe connection” also creates and expires a Checkout Session to verify that Stripe can reach your webhook endpoint (requires checkout.session.expired).',
						'dude-commerce'
					);
					?>
				</p>
			</form>
		</div>
		<?php
	}

	/**
	 * Secret input row (blank keeps existing). Placeholder shows masked key like Paywall/Downloads.
	 */
	private static function secret_row( string $name, string $label, string $current, bool $password = false ): void {
		$type         = $password ? 'password' : 'text';
		$autocomplete = $password ? 'new-password' : 'off';
		$placeholder  = self::masked( $current );
		?>
		<tr>
			<th scope="row"><label for="<?php echo esc_attr( $name ); ?>"><?php echo esc_html( $label ); ?></label></th>
			<td>
				<input type="<?php echo esc_attr( $type ); ?>" class="regular-text" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $name ); ?>" value="" autocomplete="<?php echo esc_attr( $autocomplete ); ?>" placeholder="<?php echo esc_attr( $placeholder ); ?>" />
			</td>
		</tr>
		<?php
	}

	/**
	 * Mask a secret for placeholders (first/last 4 chars visible).
	 */
	public static function masked( string $value ): string {
		if ( '' === $value ) {
			return '';
		}
		$len = strlen( $value );
		if ( $len < 8 ) {
			return '••••••••';
		}
		return substr( $value, 0, 4 ) . str_repeat( '•', max( 4, $len - 8 ) ) . substr( $value, -4 );
	}
}
