<?php
/**
 * Admin page: TrustLens → Card-Testing Defense.
 *
 * @package TrustLens
 * @since   1.2.2
 */

defined( 'ABSPATH' ) || exit;

class TrustLens_Admin_Card_Testing_Page {

	public const PAGE_SLUG = 'trustlens-card-testing';

	public function register_hooks(): void {
		add_action( 'admin_menu', array( $this, 'register_submenu' ), 20 );
		add_action( 'admin_init', array( $this, 'register_settings' ) );
		add_action( 'wp_dashboard_setup', array( $this, 'register_dashboard_widget' ) );
		add_action( 'admin_post_trustlens_ct_allowlist', array( $this, 'handle_allowlist_post' ) );
		add_action( 'admin_post_trustlens_ct_history_csv', array( $this, 'handle_csv_export' ) );
	}

	public function register_submenu(): void {
		add_submenu_page(
			'trustlens',
			__( 'Card-Testing Defense', 'trustlens' ),
			__( 'Card-Testing Defense', 'trustlens' ),
			'manage_woocommerce',
			self::PAGE_SLUG,
			array( $this, 'render' )
		);
	}

	public function register_settings(): void {
		// Booleans use rest_sanitize_boolean so unchecked checkboxes (which
		// submit no value) are coerced to false instead of silently keeping
		// the previous truthy value — a WP Settings API pitfall.
		register_setting( 'trustlens_card_testing', 'trustlens_module_card_testing_enabled', array(
			'type'              => 'boolean',
			'default'           => false,
			'sanitize_callback' => 'rest_sanitize_boolean',
		) );
		register_setting( 'trustlens_card_testing', 'trustlens_card_testing_bypass_vip_customers', array(
			'type'              => 'boolean',
			'default'           => true,
			'sanitize_callback' => 'rest_sanitize_boolean',
		) );
		register_setting( 'trustlens_card_testing', 'trustlens_card_testing_retention_hours', array(
			'type'              => 'integer',
			'default'           => 48,
			'sanitize_callback' => array( $this, 'sanitize_retention' ),
		) );
		register_setting( 'trustlens_card_testing', 'trustlens_card_testing_thresholds', array(
			'type'              => 'array',
			'default'           => array(),
			'sanitize_callback' => array( $this, 'sanitize_thresholds' ),
		) );
	}

	public function sanitize_retention( $value ): int {
		return max( 24, min( 168, (int) $value ) );
	}

	public function sanitize_thresholds( $value ): array {
		if ( ! is_array( $value ) ) {
			return array();
		}
		$out = array();
		foreach ( array( 'declines_60s', 'submissions_60s' ) as $k ) {
			if ( isset( $value[ $k ] ) ) {
				$out[ $k ] = max( 1, (int) $value[ $k ] );
			}
		}
		return $out;
	}

	public function register_dashboard_widget(): void {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}
		wp_add_dashboard_widget(
			'trustlens_card_testing_status',
			__( 'TrustLens — Card-Testing Defense', 'trustlens' ),
			array( $this, 'render_dashboard_widget' )
		);
	}

	public function render_dashboard_widget(): void {
		$state = new TrustLens_Lockdown_State();
		include TRUSTLENS_PLUGIN_DIR . 'admin/views/card-testing/dashboard-widget.php';
	}

	public function render(): void {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}

		$state = new TrustLens_Lockdown_State();
		include TRUSTLENS_PLUGIN_DIR . 'admin/views/card-testing/page.php';
	}

	public function handle_csv_export(): void {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}
		$nonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( (string) $_GET['_wpnonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'trustlens_card_testing_csv' ) ) {
			return;
		}
		$hours = isset( $_GET['hours'] ) ? max( 1, min( 168, (int) $_GET['hours'] ) ) : 24;

		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Live CSV export from a custom plugin table; caching is inappropriate for an on-demand export.
		$rows = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT created_at, event_type, fingerprint_hash, decline_code, order_id
				 FROM {$wpdb->prefix}trustlens_velocity_events
				 WHERE created_at > DATE_SUB(UTC_TIMESTAMP(), INTERVAL %d HOUR)
				 ORDER BY created_at DESC",
				$hours
			),
			ARRAY_A
		);

		nocache_headers();
		header( 'Content-Type: text/csv; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename="trustlens-card-testing-' . gmdate( 'Ymd-His' ) . '.csv"' );

		$out = fopen( 'php://output', 'w' );
		fputcsv( $out, array( 'created_at_utc', 'event_type', 'fingerprint_hash', 'decline_code', 'order_id' ) );
		foreach ( $rows as $row ) {
			fputcsv( $out, array(
				(string) ( $row['created_at']       ?? '' ),
				(string) ( $row['event_type']       ?? '' ),
				(string) ( $row['fingerprint_hash'] ?? '' ),
				(string) ( $row['decline_code']     ?? '' ),
				(string) ( $row['order_id']         ?? '' ),
			) );
		}
		fclose( $out ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Closing the php://output stream for a CSV download, not a filesystem file; WP_Filesystem cannot stream downloads.
		exit;
	}

	public function handle_allowlist_post(): void {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}
		$action = isset( $_POST['tl_ct_action'] ) ? sanitize_key( (string) wp_unslash( $_POST['tl_ct_action'] ) ) : '';
		if ( '' === $action ) {
			return;
		}
		$nonce = isset( $_POST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['_wpnonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'trustlens_card_testing_allowlists' ) ) {
			return;
		}
		if ( ! class_exists( 'TrustLens_Card_Testing_Allowlist_Repository' ) ) {
			return;
		}
		$repo = new TrustLens_Card_Testing_Allowlist_Repository();

		if ( 'add_fp' === $action ) {
			$fp = isset( $_POST['fp'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['fp'] ) ) : '';
			$repo->add_fingerprint( $fp );
		} elseif ( 'remove_fp' === $action ) {
			$fp = isset( $_POST['fp'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['fp'] ) ) : '';
			$repo->remove_fingerprint( $fp );
		} elseif ( 'add_cidr' === $action ) {
			$cidr = isset( $_POST['cidr'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['cidr'] ) ) : '';
			$repo->add_ip_cidr( $cidr );
		} elseif ( 'remove_cidr' === $action ) {
			$cidr = isset( $_POST['cidr'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['cidr'] ) ) : '';
			$repo->remove_ip_cidr( $cidr );
		}

		wp_safe_redirect( admin_url( 'admin.php?page=' . self::PAGE_SLUG . '&updated=1#allowlists' ) );
		exit;
	}
}
