<?php
/**
 * Security Middleware Trait for CommerceBird
 *
 * @package CommerceBird\Admin\Security
 */

namespace CommerceBird\Admin\Security;

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

trait SecurityMiddleware {

	/**
	 * Apply security headers to responses.
	 */
	private function apply_security_headers(): void {
		$headers = SecurityConfig::get_security_headers();

		foreach ( $headers as $header => $value ) {
			if ( ! headers_sent() ) {
				header( $header . ': ' . $value );
			}
		}
	}

	/**
	 * Validate input data against known patterns.
	 *
	 * @param array $data Input data to validate.
	 * @param array $field_types Field type mappings.
	 * @return bool True if valid, false otherwise.
	 */
	private function validate_input_patterns( array $data, array $field_types ): bool {
		foreach ( $field_types as $field => $type ) {
			if ( ! isset( $data[ $field ] ) ) {
				continue;
			}

			$pattern = SecurityConfig::get_validation_pattern( $type );
			if ( $pattern && ! preg_match( $pattern, $data[ $field ] ) ) {
				return false;
			}
		}

		return true;
	}

	/**
	 * Check user capability for specific action.
	 *
	 * @param string $action Action being performed.
	 * @return bool True if user has capability, false otherwise.
	 */
	private function check_user_capability( string $action ): bool {
		$required_cap = SecurityConfig::get_required_capability( $action );

		if ( ! $required_cap ) {
			return true; // No specific capability required.
		}

		return current_user_can( $required_cap );
	}

	/**
	 * Advanced rate limiting with multiple time windows.
	 *
	 * @param string $action Action being rate limited.
	 * @return bool True if within limits, false if exceeded.
	 */
	private function check_advanced_rate_limit( string $action ): bool {
		$user_id = get_current_user_id();
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- IP used for rate limiting key.
		$ip       = isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : 'unknown';
		$base_key = "rate_limit_{$action}_{$user_id}_{$ip}";

		// Check per-minute limit.
		$minute_key      = $base_key . '_minute';
		$minute_requests = get_transient( $minute_key );

		if ( false === $minute_requests ) {
			set_transient( $minute_key, 1, MINUTE_IN_SECONDS );
		} else {
			if ( $minute_requests >= SecurityConfig::RATE_LIMIT_REQUESTS_PER_MINUTE ) {
				return false;
			}
			set_transient( $minute_key, $minute_requests + 1, MINUTE_IN_SECONDS );
		}

		// Check per-hour limit.
		$hour_key      = $base_key . '_hour';
		$hour_requests = get_transient( $hour_key );

		if ( false === $hour_requests ) {
			set_transient( $hour_key, 1, HOUR_IN_SECONDS );
		} else {
			if ( $hour_requests >= SecurityConfig::RATE_LIMIT_REQUESTS_PER_HOUR ) {
				return false;
			}
			set_transient( $hour_key, $hour_requests + 1, HOUR_IN_SECONDS );
		}

		return true;
	}

	/**
	 * Log security event with context.
	 *
	 * @param string $event_type Type of security event.
	 * @param array  $context Additional context data.
	 */
	private function log_security_event( string $event_type, array $context = array() ): void {
		if ( ! SecurityConfig::LOG_SECURITY_EVENTS ) {
			return;
		}

		$event_data = array(
			'timestamp'  => current_time( 'mysql' ),
			'event_type' => $event_type,
			'user_id'    => get_current_user_id(),
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Security logging.
			'ip_address' => isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : 'unknown',
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Security logging.
			'user_agent' => isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : 'unknown',
			'context'    => $context,
		);

		$security_log = get_transient( 'commercebird_security_log' );
		if ( ! is_array( $security_log ) ) {
			$security_log = array();
		}

		$security_log[] = $event_data;

		// Maintain log size limits.
		if ( count( $security_log ) > SecurityConfig::LOG_MAX_ENTRIES ) {
			$security_log = array_slice( $security_log, -SecurityConfig::LOG_MAX_ENTRIES );
		}

		set_transient( 'commercebird_security_log', $security_log, DAY_IN_SECONDS * SecurityConfig::LOG_RETENTION_DAYS );
	}

	/**
	 * Sanitize and validate subscription data.
	 *
	 * @param array $data Raw subscription data.
	 * @return array Sanitized and validated data.
	 */
	private function sanitize_subscription_response( array $data ): array {
		$allowed_fields = array(
			'status',
			'plan',
			'currency',
			'total',
			'needs_payment',
			'next_payment_date_gmt',
			'variation_id',
		);

		$sanitized = array();

		foreach ( $allowed_fields as $field ) {
			if ( isset( $data[ $field ] ) ) {
				if ( is_array( $data[ $field ] ) ) {
					$sanitized[ $field ] = array_map( 'sanitize_text_field', $data[ $field ] );
				} else {
					$sanitized[ $field ] = sanitize_text_field( $data[ $field ] );
				}
			}
		}

		// Handle billing data separately with stricter controls.
		if ( isset( $data['billing'] ) && is_array( $data['billing'] ) ) {
			$sanitized['billing'] = array();

			// Only include essential billing fields.
			if ( isset( $data['billing']['email'] ) ) {
				$email = sanitize_email( $data['billing']['email'] );
				if ( is_email( $email ) ) {
					$sanitized['billing']['email'] = $email;
				}
			}
		}

		return $sanitized;
	}

	/**
	 * Check if request is from a suspicious source.
	 *
	 * @return bool True if suspicious, false otherwise.
	 */
	private function is_suspicious_request(): bool {
		// Check for missing or suspicious user agent.
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Used for pattern matching.
		$user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
		if ( empty( $user_agent ) || strlen( $user_agent ) < 10 ) {
			return true;
		}

		// Check for suspicious patterns in user agent.
		$suspicious_patterns = array(
			'/bot/i',
			'/crawler/i',
			'/spider/i',
			'/scraper/i',
		);

		foreach ( $suspicious_patterns as $pattern ) {
			if ( preg_match( $pattern, $user_agent ) ) {
				return true;
			}
		}

		// Check referer header.
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Used for URL comparison.
		$referer  = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '';
		$site_url = site_url();

		if ( ! empty( $referer ) && strpos( $referer, $site_url ) !== 0 ) {
			return true;
		}

		return false;
	}
}
