<?php
/**
 * Deactivation Feedback Diagnostics
 *
 * Collects environment and site context for deactivation feedback payloads.
 *
 * @package WP_PowerSuite\Core
 * @since 1.0.0
 */

namespace WP_PowerSuite\Core;

/**
 * DeactivationFeedbackDiagnostics Class
 */
class DeactivationFeedbackDiagnostics {

	/**
	 * Collect diagnostic context for deactivation feedback.
	 *
	 * @param array<string,mixed> $client Client-side data (browser, OS) from the modal.
	 * @return array<string,mixed>
	 */
	public static function collect( array $client = [] ): array {
		global $wpdb;

		if ( ! function_exists( 'get_plugins' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}

		$theme         = wp_get_theme();
		$theme_name    = $theme->get( 'Name' ) ?: '';
		$theme_slug    = $theme->get_stylesheet() ?: '';
		$enabled       = OptionStore::getInstance()->getEnabledModules();
		$enabled       = is_array( $enabled ) ? array_values( $enabled ) : [];
		$plugin_lists  = self::getPluginLists();
		$object_cache  = self::getObjectCacheInfo();
		$cron          = self::getCronInfo();

		return [
			'wordpress_version'          => get_bloginfo( 'version' ),
			'php_version'                => PHP_VERSION,
			'active_theme'               => [
				'name' => sanitize_text_field( (string) $theme_name ),
				'slug' => sanitize_key( (string) $theme_slug ),
			],
			'multisite'                  => is_multisite(),
			'enabled_modules'            => $enabled,
			'license_status'             => self::getLicenseStatus(),
			'locale'                     => get_locale(),
			'deactivating_user_role'     => self::getCurrentUserPrimaryRole(),
			'server_software'            => self::getServerSoftware(),
			'recent_php_error'           => self::getRecentPhpFatal(),
			'memory_limit'               => (string) ini_get( 'memory_limit' ),
			'active_page_builder'        => self::detectPageBuilders(),
			'woocommerce_active'         => class_exists( 'WooCommerce' ),
			'optimization_security_plugins' => self::detectOptimizationSecurityPlugins( $plugin_lists['active'] ),
			'installed_plugins'          => $plugin_lists['installed'],
			'active_plugins'             => $plugin_lists['active'],
			'client'                     => self::sanitizeClient( $client ),
			'object_cache'               => $object_cache,
			'cdn_host'                   => self::detectCdnAndHost(),
			'ssl'                        => is_ssl(),
			'force_ssl_admin'            => defined( 'FORCE_SSL_ADMIN' ) && FORCE_SSL_ADMIN,
			'cron'                       => $cron,
			'database_version'           => ! empty( $wpdb->db_version() ) ? (string) $wpdb->db_version() : '',
			'modules_with_errors'        => self::getModulesWithErrors( $enabled ),
		];
	}

	/**
	 * @return array{installed: array<int, array<string, string|bool>>, active: array<int, array<string, string>>}
	 */
	private static function getPluginLists(): array {
		$plugins   = get_plugins();
		$installed = [];
		$active    = [];

		foreach ( $plugins as $path => $data ) {
			$name    = isset( $data['Name'] ) ? (string) $data['Name'] : $path;
			$version = isset( $data['Version'] ) ? (string) $data['Version'] : '';
			$is_active = is_plugin_active( $path );

			$installed[] = [
				'path'    => sanitize_text_field( (string) $path ),
				'name'    => sanitize_text_field( $name ),
				'version' => sanitize_text_field( $version ),
				'active'  => $is_active,
			];

			if ( $is_active ) {
				$active[] = [
					'path'    => sanitize_text_field( (string) $path ),
					'name'    => sanitize_text_field( $name ),
					'version' => sanitize_text_field( $version ),
				];
			}
		}

		return [
			'installed' => $installed,
			'active'    => $active,
		];
	}

	/**
	 * @return 'active'|'expired'|'none'
	 */
	private static function getLicenseStatus(): string {
		if ( ! class_exists( 'WPPS_License_Manager', false ) ) {
			return 'none';
		}

		$manager = \WPPS_License_Manager::get_instance();
		$status  = $manager->get_status_data();
		$slug    = isset( $status['status'] ) ? sanitize_key( (string) $status['status'] ) : '';

		if ( $slug === '' || in_array( $slug, [ 'inactive', 'unknown' ], true ) ) {
			return 'none';
		}

		if ( in_array( $slug, [ 'active', 'grace' ], true ) || $manager->is_valid() ) {
			return 'active';
		}

		if ( $slug === 'expired' || ! $manager->is_current() ) {
			return 'expired';
		}

		return 'none';
	}

	private static function getCurrentUserPrimaryRole(): string {
		$user = wp_get_current_user();
		if ( ! ( $user instanceof \WP_User ) || ! $user->exists() ) {
			return '';
		}

		$roles = $user->roles;
		if ( ! is_array( $roles ) || $roles === [] ) {
			return '';
		}

		return sanitize_key( (string) $roles[0] );
	}

	private static function getServerSoftware(): string {
		if ( ! isset( $_SERVER['SERVER_SOFTWARE'] ) ) {
			return '';
		}

		return sanitize_text_field( wp_unslash( (string) $_SERVER['SERVER_SOFTWARE'] ) );
	}

	/**
	 * @return array<string, string>|null
	 */
	private static function getRecentPhpFatal(): ?array {
		$log_paths = [];

		if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
			if ( is_string( WP_DEBUG_LOG ) && WP_DEBUG_LOG !== '' ) {
				$log_paths[] = WP_DEBUG_LOG;
			} else {
				$log_paths[] = WP_CONTENT_DIR . '/debug.log';
			}
		}

		$error_log = ini_get( 'error_log' );
		if ( is_string( $error_log ) && $error_log !== '' && $error_log !== 'syslog' ) {
			$log_paths[] = $error_log;
		}

		$log_paths = array_values( array_unique( $log_paths ) );
		$needle    = '/(PHP Fatal error|Fatal error|Parse error)/i';

		foreach ( $log_paths as $path ) {
			if ( ! is_readable( $path ) || ! is_file( $path ) ) {
				continue;
			}

			$tail = self::readLogTail( $path, 65536 );
			if ( $tail === '' ) {
				continue;
			}

			$lines = preg_split( "/\r\n|\n|\r/", $tail );
			if ( ! is_array( $lines ) ) {
				continue;
			}

			for ( $i = count( $lines ) - 1; $i >= 0; $i-- ) {
				$line = trim( (string) $lines[ $i ] );
				if ( $line === '' || ! preg_match( $needle, $line ) ) {
					continue;
				}

				return [
					'message' => sanitize_text_field( self::truncate( $line, 500 ) ),
					'source'  => sanitize_text_field( basename( $path ) ),
				];
			}
		}

		return null;
	}

	private static function readLogTail( string $path, int $max_bytes ): string {
		$size = @filesize( $path );
		if ( ! is_int( $size ) || $size <= 0 ) {
			return '';
		}

		$handle = @fopen( $path, 'rb' );
		if ( $handle === false ) {
			return '';
		}

		$offset = max( 0, $size - $max_bytes );
		if ( $offset > 0 ) {
			fseek( $handle, $offset );
		}

		$content = (string) stream_get_contents( $handle );
		fclose( $handle );

		return $content;
	}

	/**
	 * @return array<int, string>
	 */
	private static function detectPageBuilders(): array {
		$builders = [];

		$checks = [
			'Elementor'      => static fn (): bool => defined( 'ELEMENTOR_VERSION' ) || self::isPluginActive( 'elementor/elementor.php' ),
			'Elementor Pro'  => static fn (): bool => defined( 'ELEMENTOR_PRO_VERSION' ) || self::isPluginActive( 'elementor-pro/elementor-pro.php' ),
			'Beaver Builder' => static fn (): bool => self::isPluginActive( 'bb-plugin/fl-builder.php' ) || self::isPluginActive( 'beaver-builder-lite-version/fl-builder.php' ),
			'Bricks'         => static fn (): bool => defined( 'BRICKS_VERSION' ) || self::isPluginActive( 'bricks/bricks.php' ),
			'Oxygen'         => static fn (): bool => self::isPluginActive( 'oxygen/functions.php' ),
			'Brizy'          => static fn (): bool => self::isPluginActive( 'brizy/brizy.php' ),
			'Divi Builder'   => static fn (): bool => self::isPluginActive( 'divi-builder/divi-builder.php' ) || function_exists( 'et_divi_fonts_url' ),
			'SiteOrigin'     => static fn (): bool => self::isPluginActive( 'siteorigin-panels/siteorigin-panels.php' ),
			'Visual Composer'=> static fn (): bool => self::isPluginActive( 'js_composer/js_composer.php' ) || self::isPluginActive( 'visualcomposer/plugin-wordpress.php' ),
			'Thrive Architect'=> static fn (): bool => self::isPluginActive( 'thrive-visual-editor/thrive-visual-editor.php' ),
		];

		foreach ( $checks as $label => $callback ) {
			if ( $callback() ) {
				$builders[] = $label;
			}
		}

		return $builders;
	}

	private static function isPluginActive( string $plugin_file ): bool {
		return function_exists( 'is_plugin_active' ) && is_plugin_active( $plugin_file );
	}

	/**
	 * @param array<int, array<string, string>> $active_plugins
	 * @return array<int, string>
	 */
	private static function detectOptimizationSecurityPlugins( array $active_plugins ): array {
		$patterns = [
			'wp-rocket',
			'autoptimize',
			'w3-total-cache',
			'wp-super-cache',
			'litespeed-cache',
			'hummingbird',
			'sg-cachepress',
			'wordfence',
			'sucuri',
			'ithemes-security',
			'all-in-one-wp-security',
			'better-wp-security',
			'jetpack',
			'cloudflare',
			'nginx-helper',
			'perfmatters',
			'wp-fastest-cache',
			'cache-enabler',
			'breeze',
			'redis-cache',
			'object-cache-pro',
		];

		$matches = [];
		foreach ( $active_plugins as $plugin ) {
			$path = strtolower( (string) ( $plugin['path'] ?? '' ) );
			$name = strtolower( (string) ( $plugin['name'] ?? '' ) );
			foreach ( $patterns as $pattern ) {
				if ( str_contains( $path, $pattern ) || str_contains( $name, $pattern ) ) {
					$matches[] = sanitize_text_field( (string) ( $plugin['name'] ?? $path ) );
					break;
				}
			}
		}

		return array_values( array_unique( $matches ) );
	}

	/**
	 * @param array<string,mixed> $client
	 * @return array<string,string>
	 */
	private static function sanitizeClient( array $client ): array {
		return [
			'browser' => sanitize_text_field( (string) ( $client['browser'] ?? '' ) ),
			'os'      => sanitize_text_field( (string) ( $client['os'] ?? '' ) ),
		];
	}

	/**
	 * @return array{active: bool, type: string}
	 */
	private static function getObjectCacheInfo(): array {
		$type   = 'none';
		$active = wp_using_ext_object_cache();

		if ( defined( 'WP_REDIS_HOST' ) && WP_REDIS_HOST ) {
			$type   = 'redis';
			$active = true;
		} elseif ( defined( 'MEMCACHED_SERVERS' ) && MEMCACHED_SERVERS ) {
			$type   = 'memcached';
			$active = true;
		} elseif ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
			$type   = 'object-cache.php';
			$active = true;
		} elseif ( $active ) {
			$type = 'external';
		}

		return [
			'active' => (bool) $active,
			'type'   => sanitize_key( $type ),
		];
	}

	/**
	 * @return array{host: string, cdn: bool, cdn_provider: string}
	 */
	private static function detectCdnAndHost(): array {
		$host = 'unknown';
		$cdn  = false;
		$cdn_provider = '';

		if ( defined( 'KINSTAMU_VERSION' ) || getenv( 'KINSTA_CACHE_ZONE' ) ) {
			$host = 'Kinsta';
			$cdn  = true;
			$cdn_provider = 'Kinsta';
		} elseif ( defined( 'PWP_NAME' ) || getenv( 'IS_WPE' ) || defined( 'WPE_PROVIDER' ) ) {
			$host = 'WP Engine';
		} elseif ( defined( 'CLOUDWAYS' ) || getenv( 'CW_ENV' ) ) {
			$host = 'Cloudways';
		} elseif ( defined( 'FLYWHEEL_CONFIG_DIR' ) ) {
			$host = 'Flywheel';
		} elseif ( defined( 'WPCOMSH_VERSION' ) ) {
			$host = 'WordPress.com';
		} elseif ( defined( 'GD_SYSTEM_PLUGIN_DIR' ) ) {
			$host = 'GoDaddy';
		} elseif ( defined( 'SP_HOSTING' ) || defined( 'SiteGround_Optimizer\VERSION' ) ) {
			$host = 'SiteGround';
		} elseif ( defined( 'PLP_VERSION' ) ) {
			$host = 'Pagely';
		} elseif ( defined( 'SPINUPWP_CACHE_PATH' ) ) {
			$host = 'SpinupWP';
		}

		if ( ! $cdn && defined( 'CDN_ENABLED' ) && CDN_ENABLED ) {
			$cdn          = true;
			$cdn_provider = 'CDN_ENABLED';
		}

		if ( ! $cdn && defined( 'CLOUDFLARE_PLUGIN_DIR' ) ) {
			$cdn          = true;
			$cdn_provider = 'Cloudflare';
		}

		return [
			'host'          => sanitize_text_field( $host ),
			'cdn'           => $cdn,
			'cdn_provider'  => sanitize_text_field( $cdn_provider ),
		];
	}

	/**
	 * @return array{wp_cron_disabled: bool, last_scheduled_run: int|null}
	 */
	private static function getCronInfo(): array {
		$disabled = defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON;
		$last_run = null;

		if ( function_exists( '_get_cron_array' ) ) {
			$cron = _get_cron_array();
			if ( is_array( $cron ) ) {
				$now = time();
				foreach ( $cron as $timestamp => $hooks ) {
					if ( ! is_numeric( $timestamp ) || (int) $timestamp > $now ) {
						continue;
					}
					$ts = (int) $timestamp;
					if ( $last_run === null || $ts > $last_run ) {
						$last_run = $ts;
					}
				}
			}
		}

		return [
			'wp_cron_disabled'     => $disabled,
			'last_scheduled_run'   => $last_run,
			'last_scheduled_run_gmt' => $last_run !== null ? gmdate( 'Y-m-d H:i:s', $last_run ) : null,
		];
	}

	/**
	 * @param array<int, string> $enabled_modules
	 * @return array<int, array{module_id: string, error: string}>
	 */
	private static function getModulesWithErrors( array $enabled_modules ): array {
		$monitor = PerformanceMonitor::getInstance();
		$errors  = [];

		foreach ( $enabled_modules as $module_id ) {
			$module_id = sanitize_key( (string) $module_id );
			if ( $module_id === '' || ! $monitor->isModuleDisabled( $module_id ) ) {
				continue;
			}

			$error = $monitor->getDisabledModuleError( $module_id );
			$errors[] = [
				'module_id' => $module_id,
				'error'     => sanitize_text_field( (string) ( $error ?? 'Unknown error' ) ),
			];
		}

		return $errors;
	}

	private static function truncate( string $value, int $max ): string {
		if ( strlen( $value ) <= $max ) {
			return $value;
		}

		return substr( $value, 0, $max - 3 ) . '...';
	}
}
