<?php
/**
 * Logger — Central Audit & Event Log
 *
 * All subsystems log through here.
 * Uses direct wpdb insert (not WP_Query) for performance.
 *
 * @package GuardianShield
 */

namespace GuardianShield;

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

class Logger {

	// ── Attack Log ───────────────────────────────
	/**
	 * Insert a row into gs_attack_logs.
	 *
	 * @param array{
	 *   ip_address:   string,
	 *   attack_type:  string,
	 *   severity:     int,
	 *   description:  string,
	 *   request_uri:  string,
	 *   user_agent:   string,
	 *   request_data?: string,
	 *   country_code?: string,
	 *   threat_score?: int,
	 *   blocked:      int
	 * } $data
	 */
	public function log_attack( array $data ): int {
		global $wpdb;

		$defaults = [
			'ip_address'   => '',
			'attack_type'  => 'unknown',
			'severity'     => 1,
			'description'  => '',
			'request_uri'  => substr( $_SERVER['REQUEST_URI'] ?? '', 0, 2000 ),
			'user_agent'   => substr( $_SERVER['HTTP_USER_AGENT'] ?? '', 0, 500 ),
			'request_data' => null,
			'country_code' => null,
			'threat_score' => 0,
			'blocked'      => 0,
		];

		$row = array_merge( $defaults, $data );

		// Sanitise and truncate strings to column limits.
		$row['ip_address']  = substr( sanitize_text_field( $row['ip_address'] ), 0, 45 );
		$row['attack_type'] = substr( sanitize_text_field( $row['attack_type'] ), 0, 100 );
		$row['severity']    = max( 1, min( 4, (int) $row['severity'] ) );
		$row['threat_score']= max( 0, min( 100, (int) $row['threat_score'] ) );
		$row['blocked']     = (int) (bool) $row['blocked'];

		$wpdb->insert(
			$wpdb->prefix . 'gs_attack_logs',
			$row,
			[ '%s', '%s', '%d', '%s', '%s', '%s', '%s', '%s', '%d', '%d' ]
		);

		return (int) $wpdb->insert_id;
	}

	// ── Login Attempt Log ────────────────────────
	public function log_login_attempt( string $ip, string $username, string $result ): int {
		global $wpdb;

		$wpdb->insert(
			$wpdb->prefix . 'gs_login_attempts',
			[
				'ip_address'   => substr( $ip, 0, 45 ),
				'username'     => substr( $username, 0, 200 ),
				'result'       => in_array( $result, [ 'success', 'failure', 'blocked' ], true ) ? $result : 'failure',
				'user_agent'   => substr( $_SERVER['HTTP_USER_AGENT'] ?? '', 0, 500 ),
				'country_code' => null,
			],
			[ '%s', '%s', '%s', '%s', '%s' ]
		);

		return (int) $wpdb->insert_id;
	}

	// ── Firewall Event Log ───────────────────────
	public function log_firewall_event( array $data ): int {
		global $wpdb;

		$wpdb->insert(
			$wpdb->prefix . 'gs_firewall_events',
			[
				'ip_address'   => substr( $data['ip_address'] ?? '', 0, 45 ),
				'rule_matched' => substr( $data['rule_matched'] ?? '', 0, 200 ),
				'action'       => in_array( $data['action'] ?? '', [ 'block', 'allow', 'log' ], true ) ? $data['action'] : 'log',
				'request_uri'  => substr( $data['request_uri'] ?? '', 0, 2000 ),
				'payload'      => $data['payload'] ?? null,
			],
			[ '%s', '%s', '%s', '%s', '%s' ]
		);

		return (int) $wpdb->insert_id;
	}

	// ── Scan Result Log ──────────────────────────
	public function log_scan_result( array $data ): int {
		global $wpdb;

		$wpdb->insert(
			$wpdb->prefix . 'gs_scan_results',
			[
				'scan_type'    => in_array( $data['scan_type'] ?? '', [ 'malware', 'integrity', 'full' ], true )
					? $data['scan_type'] : 'malware',
				'file_path'    => substr( $data['file_path'] ?? '', 0, 1000 ),
				'threat_type'  => substr( $data['threat_type'] ?? '', 0, 200 ),
				'threat_detail'=> $data['threat_detail'] ?? null,
				'severity'     => max( 1, min( 4, (int) ( $data['severity'] ?? 2 ) ) ),
				'status'       => in_array( $data['status'] ?? '', [ 'detected', 'quarantined', 'ignored', 'clean' ], true )
					? $data['status'] : 'detected',
			],
			[ '%s', '%s', '%s', '%s', '%d', '%s' ]
		);

		return (int) $wpdb->insert_id;
	}

	// ── File Hash Upsert ─────────────────────────
	public function upsert_file_hash( string $path, string $hash, int $size, string $type, string $status = 'clean' ): void {
		global $wpdb;

		$wpdb->replace(
			$wpdb->prefix . 'gs_file_hashes',
			[
				'file_path'    => substr( $path, 0, 1000 ),
				'file_hash'    => $hash,
				'file_size'    => $size,
				'file_type'    => in_array( $type, [ 'core', 'plugin', 'theme', 'upload' ], true ) ? $type : 'core',
				'status'       => in_array( $status, [ 'clean', 'modified', 'new', 'deleted' ], true ) ? $status : 'clean',
				'last_checked' => current_time( 'mysql', true ),
				'alerted'      => 0,
			],
			[ '%s', '%s', '%d', '%s', '%s', '%s', '%d' ]
		);
	}

	// ── Query Helpers (for Dashboard) ────────────

	public function get_recent_attacks( int $limit = 50 ): array {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		return $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM `{$wpdb->prefix}gs_attack_logs`
				  ORDER BY created_at DESC
				  LIMIT %d",
				$limit
			),
			ARRAY_A
		) ?: [];
	}

	public function get_attack_count_by_type( int $days = 7 ): array {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		return $wpdb->get_results(
			$wpdb->prepare(
				"SELECT attack_type, COUNT(*) AS total, SUM(blocked) AS blocked_count
				   FROM `{$wpdb->prefix}gs_attack_logs`
				  WHERE created_at > DATE_SUB(NOW(), INTERVAL %d DAY)
				  GROUP BY attack_type
				  ORDER BY total DESC",
				$days
			),
			ARRAY_A
		) ?: [];
	}

	public function get_login_attempts( int $limit = 100 ): array {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		return $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM `{$wpdb->prefix}gs_login_attempts`
				  ORDER BY created_at DESC
				  LIMIT %d",
				$limit
			),
			ARRAY_A
		) ?: [];
	}

	public function get_failed_logins_for_ip( string $ip, int $window_minutes = 30 ): int {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		return (int) $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM `{$wpdb->prefix}gs_login_attempts`
				  WHERE ip_address = %s
				    AND result = 'failure'
				    AND created_at > DATE_SUB(NOW(), INTERVAL %d MINUTE)",
				$ip,
				$window_minutes
			)
		);
	}

	public function get_total_stats(): array {
		global $wpdb;

		$cache_key = 'gs_total_stats';
		$cached    = get_transient( $cache_key );
		if ( false !== $cached ) {
			return $cached;
		}

		$attacks_24h = (int) $wpdb->get_var(
			"SELECT COUNT(*) FROM `{$wpdb->prefix}gs_attack_logs`
			  WHERE created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)"
		);
		$blocked_24h = (int) $wpdb->get_var(
			"SELECT COUNT(*) FROM `{$wpdb->prefix}gs_attack_logs`
			  WHERE blocked = 1
			    AND created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)"
		);
		$logins_24h = (int) $wpdb->get_var(
			"SELECT COUNT(*) FROM `{$wpdb->prefix}gs_login_attempts`
			  WHERE result = 'failure'
			    AND created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)"
		);
		$scan_threats = (int) $wpdb->get_var(
			"SELECT COUNT(*) FROM `{$wpdb->prefix}gs_scan_results`
			  WHERE status = 'detected'"
		);

		$stats = [
			'attacks_24h'  => $attacks_24h,
			'blocked_24h'  => $blocked_24h,
			'logins_24h'   => $logins_24h,
			'scan_threats' => $scan_threats,
		];

		set_transient( $cache_key, $stats, 300 );
		return $stats;
	}
}
