<?php
/**
 * Report Registry
 *
 * Defines available email report sections and fetches data from PowerSuite modules.
 *
 * @package EmailReports
 * @since 1.0.0
 */

namespace EmailReports\Includes;

use WP_PowerSuite\Core\ModuleRegistry;
use WP_PowerSuite\Core\OptionStoreModuleSettingsRepository;

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

class ReportRegistry {

	private static ?ReportRegistry $instance = null;
	private array $sections = [];
	private bool $initialized = false;

	public static function getInstance(): ReportRegistry {
		if ( self::$instance === null ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	private function __construct() {
	}

	public function init(): void {
		if ( $this->initialized ) {
			return;
		}
		$this->initialized = true;
		$this->defineSections();
	}

	public function maybeInit(): void {
		if ( ! $this->initialized ) {
			$this->init();
		}
	}

	private function defineSections(): void {
		$this->sections = [
			'track-404s' => [
				'id'          => 'track-404s',
				'title'       => __( '404 Errors', 'wp-powersuite' ),
				'description' => __( 'Broken links and missing pages', 'wp-powersuite' ),
				'module'      => 'track-404s',
				'priority'    => 20,
				'icon'        => 'warning',
			],
			'limit-login-attempts' => [
				'id'          => 'limit-login-attempts',
				'title'       => __( 'Login Security', 'wp-powersuite' ),
				'description' => __( 'Failed login attempts and lockouts', 'wp-powersuite' ),
				'module'      => 'limit-login-attempts',
				'priority'    => 15,
				'icon'        => 'shield',
			],
			'activity-log' => [
				'id'          => 'activity-log',
				'title'       => __( 'Activity Log', 'wp-powersuite' ),
				'description' => __( 'User logins and content changes', 'wp-powersuite' ),
				'module'      => 'advanced-user-activity-log',
				'priority'    => 25,
				'icon'        => 'list-alt',
			],
			'email-logs' => [
				'id'          => 'email-logs',
				'title'       => __( 'Email Delivery', 'wp-powersuite' ),
				'description' => __( 'Emails sent, delivered, failed, and bounced', 'wp-powersuite' ),
				'module'      => 'email-logs',
				'priority'    => 30,
				'icon'        => 'email-alt',
			],
		];

		$this->sections = apply_filters( 'wp_powersuite_report_sections', $this->sections );
	}

	public function getSections( bool $check_availability = false ): array {
		$this->maybeInit();

		$sections = $this->sections;

		if ( $check_availability ) {
			foreach ( $sections as $id => &$section ) {
				$section['available'] = OptionStoreModuleSettingsRepository::isModuleEnabled( $section['module'] );
			}
		}

		uasort( $sections, fn( $a, $b ) => ( $a['priority'] ?? 10 ) - ( $b['priority'] ?? 10 ) );

		return $sections;
	}

	public function getSection( string $section_id ): ?array {
		$this->maybeInit();
		return $this->sections[ $section_id ] ?? null;
	}

	public function isSectionAvailable( string $section_id ): bool {
		$section = $this->getSection( $section_id );
		if ( ! $section ) {
			return false;
		}
		if ( ! OptionStoreModuleSettingsRepository::isModuleEnabled( $section['module'] ) ) {
			return false;
		}

		return $this->isReportModuleLicensed( $section['module'] );
	}

	private function isReportModuleLicensed( string $module_id ): bool {
		if ( ! function_exists( 'wp_powersuite_is_license_valid' ) || wp_powersuite_is_license_valid() ) {
			return true;
		}

		$registry = ModuleRegistry::getInstance();
		$registry->init();
		$meta = $registry->getModuleMetadata( $module_id );

		return empty( $meta['is_pro'] );
	}

	public function getSectionData( string $section_id, array $date_range ): ?array {
		if ( ! $this->isSectionAvailable( $section_id ) ) {
			return null;
		}

		try {
			$data = null;

			switch ( $section_id ) {
				case 'track-404s':
					$data = $this->getTrack404sData( $date_range );
					break;
				case 'limit-login-attempts':
					$data = $this->getLimitLoginData( $date_range );
					break;
				case 'activity-log':
					$data = $this->getActivityLogData( $date_range );
					break;
				case 'email-logs':
					$data = $this->getEmailLogsData( $date_range );
					break;
			}

			return apply_filters( 'wp_powersuite_report_section_data', $data, $section_id, $date_range );
		} catch ( \Exception $e ) {
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
				error_log( 'WP PowerSuite Report Registry: ' . $e->getMessage() ); // phpcs:ignore
			}
			return null;
		}
	}

	public function getSectionsData( array $section_ids, array $date_range ): array {
		$data = [];
		foreach ( $section_ids as $section_id ) {
			$section_data = $this->getSectionData( $section_id, $date_range );
			if ( $section_data !== null ) {
				$section = $this->getSection( $section_id );
				$data[ $section_id ] = [
					'title'       => $section['title'],
					'description' => $section['description'],
					'icon'        => $section['icon'] ?? 'chart-bar',
					'data'        => $section_data,
				];
			}
		}
		return $data;
	}

	public function getAvailableSections(): array {
		return array_filter( $this->getSections( true ), fn( $s ) => ! empty( $s['available'] ) );
	}

	private function getTrack404sData( array $date_range ): array {
		global $wpdb;
		$table = $wpdb->prefix . 'wpps_404_logs';
		$from  = $date_range['from_datetime'] ?? ( $date_range['from'] . ' 00:00:00' );
		$to    = $date_range['to_datetime'] ?? ( $date_range['to'] . ' 23:59:59' );

		if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) !== $table ) {
			return [];
		}

		$file_filter = " AND url NOT REGEXP '\\\\.(css|js|map|jpg|jpeg|png|gif|svg|webp|avif|ico|woff2?|ttf|eot|pdf|zip|xml|json|txt|php)(\\\\?|$)'";

		$total_404s = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COALESCE(SUM(hit_count), 0) FROM {$table} WHERE first_seen >= %s AND first_seen <= %s{$file_filter}",
			$from,
			$to
		) );

		$unique_urls = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$table} WHERE first_seen >= %s AND first_seen <= %s{$file_filter}",
			$from,
			$to
		) );

		$top_urls = $wpdb->get_results( $wpdb->prepare(
			"SELECT url, hit_count as hits FROM {$table} WHERE first_seen >= %s AND first_seen <= %s{$file_filter} ORDER BY hit_count DESC LIMIT 5",
			$from,
			$to
		), ARRAY_A );

		return [
			'total_404s'   => $total_404s,
			'unique_urls'  => $unique_urls,
			'top_404_urls' => $top_urls ?: [],
		];
	}

	private function getLimitLoginData( array $date_range ): array {
		global $wpdb;
		$table = $wpdb->prefix . 'wpps_login_attempts';
		$from  = $date_range['from_datetime'] ?? ( $date_range['from'] . ' 00:00:00' );
		$to    = $date_range['to_datetime'] ?? ( $date_range['to'] . ' 23:59:59' );

		if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) !== $table ) {
			return [];
		}

		$failed_attempts = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$table} WHERE created_at >= %s AND created_at <= %s",
			$from,
			$to
		) );

		$lockouts = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$table} WHERE lockout_until IS NOT NULL AND created_at >= %s AND created_at <= %s",
			$from,
			$to
		) );

		$top_ips = $wpdb->get_results( $wpdb->prepare(
			"SELECT ip_address as ip, COUNT(*) as count FROM {$table} WHERE created_at >= %s AND created_at <= %s GROUP BY ip_address ORDER BY count DESC LIMIT 5",
			$from,
			$to
		), ARRAY_A );

		return [
			'failed_attempts' => $failed_attempts,
			'lockouts'        => $lockouts,
			'top_blocked_ips' => $top_ips ?: [],
		];
	}

	private function getActivityLogData( array $date_range ): array {
		global $wpdb;
		$table = $wpdb->prefix . 'wpps_activity_log';
		$from  = $date_range['from_datetime'] ?? ( $date_range['from'] . ' 00:00:00' );
		$to    = $date_range['to_datetime'] ?? ( $date_range['to'] . ' 23:59:59' );

		if ( $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table ) ) !== $table ) {
			return [];
		}

		$total_events = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$table} WHERE created_at >= %s AND created_at <= %s",
			$from,
			$to
		) );

		$user_logins = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$table} WHERE action = 'login' AND created_at >= %s AND created_at <= %s",
			$from,
			$to
		) );

		$content_changes = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$table} WHERE action IN ( 'post_created', 'post_updated', 'post_deleted', 'post_status_changed' ) AND created_at >= %s AND created_at <= %s",
			$from,
			$to
		) );

		$failed_logins = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$table} WHERE action = 'failed_login' AND created_at >= %s AND created_at <= %s",
			$from,
			$to
		) );

		$recent_events = $wpdb->get_results( $wpdb->prepare(
			"SELECT * FROM {$table} WHERE created_at >= %s AND created_at <= %s ORDER BY created_at DESC LIMIT 10",
			$from,
			$to
		), ARRAY_A );

		return [
			'total_events'    => $total_events,
			'user_logins'     => $user_logins,
			'content_changes' => $content_changes,
			'failed_logins'   => $failed_logins,
			'recent_events'   => $recent_events ?: [],
		];
	}

	private function getEmailLogsData( array $date_range ): array {
		global $wpdb;
		$table = $wpdb->prefix . 'wpps_email_logs';
		$from  = $date_range['from_datetime'] ?? ( $date_range['from'] . ' 00:00:00' );
		$to    = $date_range['to_datetime'] ?? ( $date_range['to'] . ' 23:59:59' );

		if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) !== $table ) {
			return [];
		}

		// Single aggregation scan for the date window (same metrics as before).
		$counts = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT
					SUM(CASE WHEN status = 'sent' THEN 1 ELSE 0 END) AS sent_count,
					SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) AS failed_count,
					SUM(CASE WHEN delivery_status = 'delivered' THEN 1 ELSE 0 END) AS delivered_count,
					SUM(CASE WHEN delivery_status IN ('bounced','complained','rejected') THEN 1 ELSE 0 END) AS bounced_count
				FROM {$table}
				WHERE sent_date >= %s AND sent_date <= %s",
				$from,
				$to
			),
			ARRAY_A
		);

		$recent = $wpdb->get_results( $wpdb->prepare(
			"SELECT to_email, subject, status, delivery_status, sent_date FROM {$table} WHERE sent_date >= %s AND sent_date <= %s ORDER BY sent_date DESC LIMIT 5",
			$from,
			$to
		), ARRAY_A );

		return [
			'total_sent'      => (int) ( $counts['sent_count'] ?? 0 ),
			'total_failed'    => (int) ( $counts['failed_count'] ?? 0 ),
			'total_delivered' => (int) ( $counts['delivered_count'] ?? 0 ),
			'total_bounced'   => (int) ( $counts['bounced_count'] ?? 0 ),
			'recent_emails'   => $recent ?: [],
		];
	}
}
