<?php
/**
 * Privacy/GDPR compliance: policy content, data export, and data erasure.
 *
 * @package ZA_Creative_Login_Shield
 */

defined( 'ABSPATH' ) || exit;

/**
 * Handles WordPress Privacy API integration (GDPR compliance).
 */
class ZACLS_Privacy {

	/**
	 * Register privacy hooks.
	 */
	public static function init() {
		add_action( 'admin_init', array( __CLASS__, 'add_privacy_policy_content' ) );
		add_filter( 'wp_privacy_personal_data_exporters', array( __CLASS__, 'register_exporter' ) );
		add_filter( 'wp_privacy_personal_data_erasers', array( __CLASS__, 'register_eraser' ) );
	}

	/**
	 * Register the privacy policy section via WordPress core.
	 */
	public static function add_privacy_policy_content() {
		if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
			return;
		}

		$content = self::get_privacy_policy_text();
		wp_add_privacy_policy_content(
			'ZA Creative Login Shield',
			wp_kses_post( $content )
		);
	}

	/**
	 * Build the privacy policy text.
	 *
	 * @return string
	 */
	private static function get_privacy_policy_text() {
		return '<h3>' . esc_html__( 'What data we collect', 'za-creative-login-shield' ) . '</h3>

<p>' . esc_html__( 'ZA Creative Login Shield collects the following data when users interact with the login system on this site:', 'za-creative-login-shield' ) . '</p>

<ul>
<li><strong>' . esc_html__( 'IP Address', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Every login attempt (successful or failed) records the visitor\'s IP address. IPs are also stored for blocked IPs, active sessions, device fingerprints, and security audit log entries.', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'Username / Email', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'The username or email entered during login attempts is logged, regardless of whether the attempt succeeded or failed.', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'User Agent', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Browser user-agent string is stored with each login attempt, active session, and device fingerprint entry.', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'Device Fingerprint', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'A one-way hashed identifier derived from browser characteristics (user-agent, language, encoding) is used to recognize trusted devices. The raw fingerprint data is not stored â€” only a non-reversible hash.', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'Country Code', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'A two-letter country code may be derived from the IP address via a third-party GeoIP service (ip-api.com) and stored with login attempts and blocked IPs.', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'Session Data', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Authenticated user sessions are tracked, including session ID, associated IP, device ID, user agent, and activity timestamps.', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'Security Audit Log', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Administrative security actions (settings changes, IP blocks, lockdown events, report generation) are logged with the acting user\'s ID and IP address.', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'WebAuthn Passkey Credentials', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Registered passkey credentials store only the public key and a credential ID (never the private key), along with a sign counter used for replay protection and the authenticator model identifier (AAGUID).', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'One-Time Passwords', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Two-factor authentication codes are stored only as one-way hashes and are automatically removed after expiry (10 minutes) or when they are used.', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'Risk Scores', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Per-login risk evaluations (score, level, and contributing factors) may be stored and are automatically cleaned up after 30 days.', 'za-creative-login-shield' ) . '</li>
</ul>

<h3>' . esc_html__( 'Why we collect this data', 'za-creative-login-shield' ) . '</h3>

<p>' . esc_html__( 'This data is collected exclusively for security purposes:', 'za-creative-login-shield' ) . '</p>

<ul>
<li>' . esc_html__( 'Detect and prevent brute-force login attacks', 'za-creative-login-shield' ) . '</li>
<li>' . esc_html__( 'Identify and block malicious IP addresses', 'za-creative-login-shield' ) . '</li>
<li>' . esc_html__( 'Enforce rate limiting and account lockout policies', 'za-creative-login-shield' ) . '</li>
<li>' . esc_html__( 'Provide audit trail for security incidents', 'za-creative-login-shield' ) . '</li>
<li>' . esc_html__( 'Recognize trusted devices for enhanced login security', 'za-creative-login-shield' ) . '</li>
<li>' . esc_html__( 'Track active user sessions and enforce timeouts', 'za-creative-login-shield' ) . '</li>
</ul>

<h3>' . esc_html__( 'How long we retain data', 'za-creative-login-shield' ) . '</h3>

<ul>
<li><strong>' . esc_html__( 'Login attempts', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( '60 days (automatically cleaned up by daily cron job).', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'Blocked IPs', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Until the block expires (auto-blocks) or until manually removed (manual blocks/whitelist entries persist indefinitely).', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'Active sessions', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Until the session expires or the user logs out.', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'Device fingerprints', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Old device records are periodically cleaned up; actively used devices persist.', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( 'Audit log', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Retained until manually cleared by a site administrator via the Audit Trail page.', 'za-creative-login-shield' ) . '</li>
<li><strong>' . esc_html__( '2FA status and backup codes', 'za-creative-login-shield' ) . '</strong> â€“ ' . esc_html__( 'Retained until the user disables 2FA or the plugin is uninstalled.', 'za-creative-login-shield' ) . '</li>
</ul>

<h3>' . esc_html__( 'Does data leave your website?', 'za-creative-login-shield' ) . '</h3>

<p>' . esc_html__( 'Minimally. The only external requests are:', 'za-creative-login-shield' ) . '</p>

<ul>
<li>' . esc_html__( 'An optional GeoIP lookup via ip-api.com when a login attempt occurs, only if you have enabled the GeoIP feature in the plugin settings. This sends the visitor\'s IP address to ip-api.com to retrieve a two-letter country code. The result is cached locally for 7 days. No API key is required, and the service is free. GeoIP is disabled by default.', 'za-creative-login-shield' ) . '</li>
<li>' . esc_html__( 'An optional Cloudflare IP range fetch via api.cloudflare.com when an administrator manually clicks the "Fetch Cloudflare IPs" button on the settings page. This requests the current Cloudflare IPv4 and IPv6 ranges to restore real visitor IPs behind Cloudflare\'s proxy. No visitor data is sent. Cloudflare fetching is not automatic and must be triggered by an admin.', 'za-creative-login-shield' ) . '</li>
</ul>

<p>' . esc_html__( 'All other data remains entirely within your WordPress database.', 'za-creative-login-shield' ) . '</p>

<h3>' . esc_html__( 'How we protect your data', 'za-creative-login-shield' ) . '</h3>

<p>' . esc_html__( 'Device fingerprints are stored as one-way hashes (not raw browser data). Session cookies use the HTTPOnly and Secure flags where supported. All database queries use WordPress prepared statements to prevent SQL injection.', 'za-creative-login-shield' ) . '</p>

<h3>' . esc_html__( 'Cookies', 'za-creative-login-shield' ) . '</h3>

<p>' . esc_html__( 'The plugin sets the following cookies on user browsers:', 'za-creative-login-shield' ) . '</p>

<ul>
<li><strong>zacls_device_id</strong> â€“ ' . esc_html__( 'A persistent cookie storing a hashed device identifier. Expires after 1 year. Used to recognize trusted devices for security alerts.', 'za-creative-login-shield' ) . '</li>
<li><strong>zacls_session</strong> â€“ ' . esc_html__( 'A session cookie storing the active session token. Expires when the browser is closed or when the session timeout is reached. Used to track authenticated sessions.', 'za-creative-login-shield' ) . '</li>
</ul>

<h3>' . esc_html__( 'How to request data deletion', 'za-creative-login-shield' ) . '</h3>

<p>' . esc_html__( 'You may request deletion of your personal data collected by this plugin through the WordPress Privacy Tools at Tools > Export Personal Data and Tools > Erase Personal Data. The plugin fully supports the WordPress Personal Data Exporter and Eraser, allowing you or site administrators to export or delete login attempt records, session data, device fingerprints, and audit log entries associated with your email address.', 'za-creative-login-shield' ) . '</p>

<p>' . esc_html__( 'When the plugin is uninstalled, all database tables and options are removed, resulting in complete data deletion.', 'za-creative-login-shield' ) . '</p>';
	}

	/**
	 * Register the personal data exporter.
	 *
	 * @param array $exporters Registered exporters.
	 * @return array
	 */
	public static function register_exporter( $exporters ) {
		$exporters['za-creative-login-shield'] = array(
			'exporter_friendly_name' => __( 'ZA Creative Login Shield Data', 'za-creative-login-shield' ),
			'callback'               => array( __CLASS__, 'export_data' ),
		);
		return $exporters;
	}

	/**
	 * Export personal data for a given email address.
	 *
	 * @param string $email User email.
	 * @param int    $page  Page number.
	 * @return array
	 */
	public static function export_data( $email, $page = 1 ) {
		$user   = get_user_by( 'email', $email );
		$data   = array();
		$done   = true;

		if ( ! $user ) {
			return array(
				'data' => $data,
				'done' => $done,
			);
		}

		$user_id = $user->ID;
		global $wpdb;

		$limit = 100;
		$offset = ( $page - 1 ) * $limit;

		// Export login attempts.
		$attempts = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prepare(
				"SELECT ip, username, status, user_agent, country_code, attempt_time
				FROM {$wpdb->prefix}zacls_login_attempts
				WHERE user_id = %d OR username = %s
				ORDER BY attempt_time DESC
				LIMIT %d OFFSET %d",
				$user_id,
				$user->user_login,
				$limit,
				$offset
			),
			ARRAY_A
		);

		if ( ! empty( $attempts ) ) {
			$items = array();
			foreach ( $attempts as $row ) {
				$items[] = array(
					'name'  => __( 'Login Attempt', 'za-creative-login-shield' ),
					'value' => sprintf(
						'IP: %s | Username: %s | Status: %s | Country: %s | Time: %s | User Agent: %s',
						$row['ip'],
						$row['username'],
						$row['status'],
						$row['country_code'],
						$row['attempt_time'],
						$row['user_agent']
					),
				);
			}
			$data[] = array(
				'group_id'    => 'zacls_login_attempts',
				'group_label' => __( 'Login Attempts', 'za-creative-login-shield' ),
				'item_id'     => "zacls-attempts-{$user_id}",
				'data'        => $items,
			);
			$done   = count( $attempts ) < $limit;
		}

		// Export device fingerprints.
		$devices = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prepare(
				"SELECT device_id, ip, user_agent, trusted, first_seen, last_seen
				FROM {$wpdb->prefix}zacls_device_fingerprints
				WHERE user_id = %d",
				$user_id
			),
			ARRAY_A
		);

		if ( ! empty( $devices ) ) {
			$device_items = array();
			foreach ( $devices as $row ) {
				$device_items[] = array(
					'name'  => __( 'Device', 'za-creative-login-shield' ),
					'value' => sprintf(
						'Device ID: %s | IP: %s | Trusted: %s | First seen: %s | Last seen: %s | User Agent: %s',
						$row['device_id'],
						$row['ip'],
						$row['trusted'] ? __( 'Yes', 'za-creative-login-shield' ) : __( 'No', 'za-creative-login-shield' ),
						$row['first_seen'],
						$row['last_seen'],
						$row['user_agent']
					),
				);
			}
			$data[] = array(
				'group_id'    => 'zacls_devices',
				'group_label' => __( 'Known Devices', 'za-creative-login-shield' ),
				'item_id'     => "zacls-devices-{$user_id}",
				'data'        => $device_items,
			);
		}

		// Export sessions.
		$sessions = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prepare(
				"SELECT ip, device_id, user_agent, login_time, last_activity, is_active
				FROM {$wpdb->prefix}zacls_sessions
				WHERE user_id = %d",
				$user_id
			),
			ARRAY_A
		);

		if ( ! empty( $sessions ) ) {
			$session_items = array();
			foreach ( $sessions as $row ) {
				$session_items[] = array(
					'name'  => __( 'Session', 'za-creative-login-shield' ),
					'value' => sprintf(
						'IP: %s | Device ID: %s | Active: %s | Login: %s | Last activity: %s | User Agent: %s',
						$row['ip'],
						$row['device_id'],
						$row['is_active'] ? __( 'Yes', 'za-creative-login-shield' ) : __( 'No', 'za-creative-login-shield' ),
						$row['login_time'],
						$row['last_activity'],
						$row['user_agent']
					),
				);
			}
			$data[] = array(
				'group_id'    => 'zacls_sessions',
				'group_label' => __( 'Sessions', 'za-creative-login-shield' ),
				'item_id'     => "zacls-sessions-{$user_id}",
				'data'        => $session_items,
			);
		}

		// Export WebAuthn credentials.
		$webauthn = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prepare(
				"SELECT credential_type, name, created_at, last_used, transports
				FROM {$wpdb->prefix}zacls_webauthn_credentials
				WHERE user_id = %d",
				$user_id
			),
			ARRAY_A
		);

		if ( ! empty( $webauthn ) ) {
			$webauthn_items = array();
			foreach ( $webauthn as $row ) {
				$webauthn_items[] = array(
					'name'  => __( 'Passkey Credential', 'za-creative-login-shield' ),
					'value' => sprintf(
						'Type: %s | Name: %s | Transports: %s | Registered: %s | Last used: %s',
						$row['credential_type'],
						$row['name'],
						$row['transports'],
						$row['created_at'],
						$row['last_used'] ? $row['last_used'] : __( 'Never', 'za-creative-login-shield' )
					),
				);
			}
			$data[] = array(
				'group_id'    => 'zacls_webauthn',
				'group_label' => __( 'Passkey Credentials', 'za-creative-login-shield' ),
				'item_id'     => "zacls-webauthn-{$user_id}",
				'data'        => $webauthn_items,
			);
		}

		// Export 2FA status.
		$twofa_status = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prepare(
				"SELECT method, enabled, updated_at
				FROM {$wpdb->prefix}zacls_2fa_status
				WHERE user_id = %d",
				$user_id
			),
			ARRAY_A
		);

		if ( ! empty( $twofa_status ) ) {
			$data[] = array(
				'group_id'    => 'zacls_2fa',
				'group_label' => __( 'Two-Factor Authentication', 'za-creative-login-shield' ),
				'item_id'     => "zacls-2fa-{$user_id}",
				'data'        => array(
					array(
						'name'  => __( '2FA Method', 'za-creative-login-shield' ),
						'value' => sprintf(
							'Method: %s | Enabled: %s | Updated: %s',
							$twofa_status['method'],
							$twofa_status['enabled'] ? __( 'Yes', 'za-creative-login-shield' ) : __( 'No', 'za-creative-login-shield' ),
							$twofa_status['updated_at']
						),
					),
				),
			);
		}

		// Export risk scores.
		$risk_scores = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prepare(
				"SELECT ip, score, level, factors, created_at
				FROM {$wpdb->prefix}zacls_risk_scores
				WHERE user_id = %d
				ORDER BY created_at DESC",
				$user_id
			),
			ARRAY_A
		);

		if ( ! empty( $risk_scores ) ) {
			$risk_items = array();
			foreach ( $risk_scores as $row ) {
				$risk_items[] = array(
					'name'  => __( 'Risk Score', 'za-creative-login-shield' ),
					'value' => sprintf(
						'IP: %s | Score: %s | Level: %s | Factors: %s | Time: %s',
						$row['ip'],
						$row['score'],
						$row['level'],
						$row['factors'],
						$row['created_at']
					),
				);
			}
			$data[] = array(
				'group_id'    => 'zacls_risk_scores',
				'group_label' => __( 'Risk Scores', 'za-creative-login-shield' ),
				'item_id'     => "zacls-risk-{$user_id}",
				'data'        => $risk_items,
			);
		}

		// Export audit log.
		$audit_entries = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prepare(
				"SELECT action, details, ip, created_at
				FROM {$wpdb->prefix}zacls_audit_log
				WHERE user_id = %d
				ORDER BY created_at DESC",
				$user_id
			),
			ARRAY_A
		);

		if ( ! empty( $audit_entries ) ) {
			$audit_items = array();
			foreach ( $audit_entries as $row ) {
				$audit_items[] = array(
					'name'  => __( 'Audit Entry', 'za-creative-login-shield' ),
					'value' => sprintf(
						'Action: %s | Details: %s | IP: %s | Time: %s',
						$row['action'],
						$row['details'],
						$row['ip'],
						$row['created_at']
					),
				);
			}
			$data[] = array(
				'group_id'    => 'zacls_audit_log',
				'group_label' => __( 'Security Audit Log', 'za-creative-login-shield' ),
				'item_id'     => "zacls-audit-{$user_id}",
				'data'        => $audit_items,
			);
		}

		return array(
			'data' => $data,
			'done' => $done,
		);
	}

	/**
	 * Register the personal data eraser.
	 *
	 * @param array $erasers Registered erasers.
	 * @return array
	 */
	public static function register_eraser( $erasers ) {
		$erasers['za-creative-login-shield'] = array(
			'eraser_friendly_name' => __( 'ZA Creative Login Shield Data Eraser', 'za-creative-login-shield' ),
			'callback'             => array( __CLASS__, 'erase_data' ),
		);
		return $erasers;
	}

	/**
	 * Erase personal data for a given email address.
	 *
	 * @param string $email User email.
	 * @param int    $page  Page number.
	 * @return array
	 */
	public static function erase_data( $email, $page = 1 ) {
		$user = get_user_by( 'email', $email );
		$done = true;

		if ( ! $user ) {
			return array(
				'items_removed'  => false,
				'items_retained' => false,
				'messages'       => array(),
				'done'           => true,
			);
		}

		$user_id = $user->ID;
		global $wpdb;

		$items_removed  = 0;
		$items_retained = 0;

		// Delete login attempts for this user.
		$removed = $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prefix . 'zacls_login_attempts',
			array( 'user_id' => $user_id ),
			array( '%d' )
		);
		if ( $removed ) {
			$items_removed += $removed;
		}

		// Delete device fingerprints.
		$removed = $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prefix . 'zacls_device_fingerprints',
			array( 'user_id' => $user_id ),
			array( '%d' )
		);
		if ( $removed ) {
			$items_removed += $removed;
		}

		// Delete sessions.
		$removed = $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prefix . 'zacls_sessions',
			array( 'user_id' => $user_id ),
			array( '%d' )
		);
		if ( $removed ) {
			$items_removed += $removed;
		}

		// Delete audit log entries.
		$removed = $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prefix . 'zacls_audit_log',
			array( 'user_id' => $user_id ),
			array( '%d' )
		);
		if ( $removed ) {
			$items_removed += $removed;
		}

		// Delete WebAuthn credentials.
		$removed = $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prefix . 'zacls_webauthn_credentials',
			array( 'user_id' => $user_id ),
			array( '%d' )
		);
		if ( $removed ) {
			$items_removed += $removed;
		}

		// Delete 2FA status.
		$removed = $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prefix . 'zacls_2fa_status',
			array( 'user_id' => $user_id ),
			array( '%d' )
		);
		if ( $removed ) {
			$items_removed += $removed;
		}

		// Delete risk scores.
		$removed = $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prefix . 'zacls_risk_scores',
			array( 'user_id' => $user_id ),
			array( '%d' )
		);
		if ( $removed ) {
			$items_removed += $removed;
		}

		// Anonymize blocked IPs (change to anonymized reference, don't delete).
		$wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prefix . 'zacls_blocked_ips',
			array( 'blocked_by' => 'anonymized' ),
			array( 'blocked_by' => strval( $user_id ) ),
			array( '%s' ),
			array( '%s' )
		);

		return array(
			'items_removed'  => $items_removed > 0,
			'items_retained' => false,
			'messages'       => $items_removed > 0
				? array( sprintf( __( 'Removed %d ZA Creative Login Shield records.', 'za-creative-login-shield' ), $items_removed ) )
				: array(),
			'done'           => $done,
		);
	}
}
