<?php
namespace EASYERLO\Inc;

defined('ABSPATH') || die('Hey, what are you doing here? You silly human!');

/**
 * Easy Error Log Fatal Class.
 *
 * This class handles all the Fatal requests for the Easy Error Log plugin.
 * It provides functionality for detecting, handling, and managing fatal errors,
 * including automatic plugin deactivation and error reporting.
 *
 * @package EASYERLO\Inc
 * @since 1.0.0
 */
class EASYERLO_Fatal {

	/**
	 * Whether the fatal error handler has been registered.
	 *
	 * @var boolean
	 */
	protected $fatal_handler_registered = false;

	/**
	 * Initialize the fatal error handling functionality.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function init() {
		$fatal_error_safer = get_option('easyerlo_fatal_error_safer_enabled', 'active');

		if ( 'active' === $fatal_error_safer ) {
			$this->init_fatal_error_detection();
			add_action( 'wp_ajax_dismiss_easyerlo_notice', [ $this, 'dismiss_deactivated_plugin_notice' ]);
			add_action( 'admin_notices', [ $this, 'show_deactivated_plugin_notice' ]);
		}
	}

	/**
	 * Initialize fatal error detection and handling.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	private function init_fatal_error_detection() {
		if ( ! $this->fatal_handler_registered ) {
			// Register shutdown function to catch fatal errors.
			register_shutdown_function(array( $this, 'handle_fatal_error' ));
			$this->fatal_handler_registered = true;

			// Also register error handler for non-fatal errors if needed.
			set_error_handler(array( $this, 'handle_error' ), E_ALL);
		}
	}

	/**
	 * Handle fatal errors that occur during script execution.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function handle_fatal_error() {
		try {
			$error = $this->detect_error();
			if ( ! $error ) {
				return;
			}

			// Try to deactivate the problematic plugin.
			$deactivated_plugin = $this->maybe_deactivate_plugin($error);

			// Display custom error page when triggered.
			$this->display_custom_error_page($error, $deactivated_plugin);

		} catch ( Exception $e ) {
			// Catch exceptions and remain silent to prevent infinite loops.
			error_log('Exception: ' . $e->getMessage());
		}
	}

	/**
	 * Handle non-fatal errors and warnings.
	 *
	 * @since 1.0.0
	 * @param int    $severity The error severity level.
	 * @param string $message  The error message.
	 * @param string $file     The file where the error occurred.
	 * @param int    $line     The line number where the error occurred.
	 * @return boolean False to allow default error handling.
	 */
	public function handle_error( $severity, $message, $file, $line ) {
		// Only handle fatal-level errors here, let WordPress handle others.
		$fatal_error_types = array(
			E_ERROR,
			E_PARSE,
			E_CORE_ERROR,
			E_COMPILE_ERROR,
			E_USER_ERROR,
			E_RECOVERABLE_ERROR,
		);

		if ( in_array( $severity, $fatal_error_types, true ) ) {
			$error = array(
				'type' => $severity,
				'message' => $message,
				'file' => $file,
				'line' => $line,
			);

			$deactivated_plugin = $this->maybe_deactivate_plugin( $error );
		}

		// Don't prevent default error handling.
		return false;
	}

	/**
	 * Detect if a fatal error occurred
	 *
	 * @return array|false Error array or false if no error
	 */
	protected function detect_error() {
		$error = error_get_last();

		if ( ! $error ) {
			return false;
		}

		$fatal_error_types = array(
			E_ERROR,
			E_PARSE,
			E_CORE_ERROR,
			E_COMPILE_ERROR,
			E_USER_ERROR,
			E_RECOVERABLE_ERROR,
		);

		if ( ! in_array($error['type'], $fatal_error_types, true) ) {
			return false;
		}

		return $error;
	}

	/**
	 * Try to deactivate the plugin that caused the error
	 *
	 * @param array $error Error information
	 * @return array|null Plugin information if deactivated
	 */
	protected function maybe_deactivate_plugin( $error ) {
		$error_file = $error['file'];
		$deactivated_plugin = null;

		// Get all active plugins
		$active_plugins = $this->get_active_plugins();

		foreach ( $active_plugins as $plugin_base ) {
			$plugin_dir = WP_PLUGIN_DIR . '/' . dirname($plugin_base);

			if ( strpos($error_file, $plugin_dir) === 0 ) {
				$deactivated_plugin = $this->deactivate_plugin($plugin_base, $error);
				break;
			}
		}

		return $deactivated_plugin;
	}

	/**
	 * Get all active plugins
	 *
	 * @return array List of active plugins
	 */
	protected function get_active_plugins() {
		// Make sure we have access to WordPress functions
		if ( ! function_exists('get_option') ) {
			if ( file_exists(ABSPATH . 'wp-includes/plugin.php') ) {
				require_once ABSPATH . 'wp-includes/plugin.php';
			}
			if ( file_exists(ABSPATH . 'wp-admin/includes/plugin.php') ) {
				require_once ABSPATH . 'wp-admin/includes/plugin.php';
			}
		}

		// Get active plugins
		return get_option('active_plugins', array());
	}

	/**
	 * Deactivate a plugin and log the error
	 *
	 * @param string $plugin_base Plugin base name
	 * @param array  $error Error information
	 * @return array|null Plugin information if successful
	 */
	protected function deactivate_plugin( $plugin_base, $error ) {
		// Make sure we have access to WordPress functions
		if ( ! function_exists('deactivate_plugins') && file_exists(ABSPATH . 'wp-admin/includes/plugin.php') ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}

		// Get plugin data if possible
		$plugin_data = array(
			'Name'        => $plugin_base,
			'PluginURI'   => '',
			'Description' => '',
			'Version'     => '',
			'Author'      => '',
		);

		if ( function_exists('get_plugin_data') && file_exists(WP_PLUGIN_DIR . '/' . $plugin_base) ) {
			$plugin_data = get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin_base, false, false);
			if ( empty($plugin_data['Name']) ) {
				$plugin_data['Name'] = $plugin_base;
			}
		}

		// Deactivate the plugin
		if ( function_exists('deactivate_plugins') ) {
			deactivate_plugins($plugin_base);

			// Store deactivated plugin info for admin notice
			$this->store_deactivated_plugin_info($plugin_base, $error);

			// Return plugin information
			return array(
				'plugin_base'    => $plugin_base,
				'plugin_name'    => $plugin_data['Name'],
				'plugin_version' => $plugin_data['Version'],
				'error'          => $error,
				'deactivated'    => true,
			);
		}

		return null;
	}

	/**
	 * Store information about the deactivated plugin for admin notices
	 *
	 * @param string $plugin_base Plugin base name
	 * @param array  $error Error information
	 */
	protected function store_deactivated_plugin_info( $plugin_base, $error ) {
		if ( ! function_exists('get_option') || ! function_exists('update_option') ) {
			return;
		}

		// Get plugin data properly
		$plugin_name = $plugin_base;
		$plugin_version = '';
		$plugin_author = '';

		if ( function_exists('get_plugin_data') && file_exists(WP_PLUGIN_DIR . '/' . $plugin_base) ) {
			$plugin_data = get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin_base, false, false);
			$plugin_name = ! empty($plugin_data['Name']) ? $plugin_data['Name'] : $plugin_base;
			$plugin_version = ! empty($plugin_data['Version']) ? $plugin_data['Version'] : '';
			$plugin_author = ! empty($plugin_data['Author']) ? $plugin_data['Author'] : '';
		}

		// Store for admin notice (temporary storage, cleared after displaying)
		$deactivated_plugins = get_option('easyerlo_deactivated_plugins', array());
		$deactivated_plugins[] = array(
			'plugin' => $plugin_base,
			'plugin_name' => $plugin_name,
			'plugin_version' => $plugin_version,
			'plugin_author' => $plugin_author,
			'error'  => $error,
			'time'   => time(),
		);
		update_option('easyerlo_deactivated_plugins', $deactivated_plugins);

		// Store in permanent log
		$this->add_to_deactivation_log($plugin_base, $error);
	}

	/**
	 * Add an entry to the permanent deactivation log
	 *
	 * @param string $plugin_base Plugin base name
	 * @param array  $error Error information
	 */
	protected function add_to_deactivation_log( $plugin_base, $error ) {
		// Get the current log
		$deactivation_log = get_option('easyerlo_deactivation_log', array());

		// Get plugin data if possible
		$plugin_name = $plugin_base;
		if ( function_exists('get_plugin_data') && file_exists(WP_PLUGIN_DIR . '/' . $plugin_base) ) {
			$plugin_data = get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin_base);
			$plugin_name = ! empty($plugin_data['Name']) ? $plugin_data['Name'] : $plugin_base;
		}

		// Create a new log entry
		$log_entry = array(
			'plugin'      => sanitize_text_field($plugin_base),
			'plugin_name' => sanitize_text_field($plugin_name),
			'error_type'  => absint($error['type']),
			'error_msg'   => sanitize_text_field($error['message']),
			'error_file'  => sanitize_text_field($error['file']),
			'error_line'  => absint($error['line']),
			'time'        => time(),
			'date'        => gmdate('Y-m-d H:i:s'),
		);

		// Add to the log (limit to 100 entries to prevent database bloat)
		array_unshift($deactivation_log, $log_entry);
		if ( count($deactivation_log) > 100 ) {
			$deactivation_log = array_slice($deactivation_log, 0, 100);
		}

		// Update the log
		update_option('easyerlo_deactivation_log', $deactivation_log);
	}

	/**
	 * Get error type as human-readable string
	 *
	 * @param int $error_type Error type constant
	 * @return string Error type string
	 */
	protected function get_error_type_string( $error_type ) {
		switch ( $error_type ) {
			case E_ERROR:
				return 'Fatal Error';
			case E_PARSE:
				return 'Parse Error';
			case E_CORE_ERROR:
				return 'Core Error';
			case E_COMPILE_ERROR:
				return 'Compile Error';
			case E_USER_ERROR:
				return 'User Error';
			case E_RECOVERABLE_ERROR:
				return 'Recoverable Error';
			default:
				return 'Unknown Error';
		}
	}

	/**
	 * Display a custom error page with warning and reload button
	 *
	 * @param array      $error Error information
	 * @param array|null $deactivated_plugin Information about the deactivated plugin
	 */
	protected function display_custom_error_page( $error, $deactivated_plugin = null ) {
		// Set the HTTP status code
		http_response_code(500);

		// Get error type as string
		$error_type = $this->get_error_type_string($error['type']);

		// Get site name and home URL
		$site_name = 'WordPress Site';
		$home_url = '/';
		if ( function_exists('get_bloginfo') ) {
			$site_name = get_bloginfo('name');
			$home_url = home_url();
		}

		// Prepare plugin information
		$plugin_name = 'Unknown Plugin';
		$plugin_version = '';
		$plugin_info_message = '';

		if ( $deactivated_plugin ) {
			$plugin_name = $deactivated_plugin['plugin_name'];
			$plugin_version = $deactivated_plugin['plugin_version'] ? ' v' . $deactivated_plugin['plugin_version'] : '';
			$plugin_info_message = sprintf(
				'<p>The plugin <strong>%1$s%2$s</strong> has been automatically deactivated to prevent further errors.</p>',
				esc_html($plugin_name),
				esc_html($plugin_version)
			);
		}

		// Output the error page
		echo '<!DOCTYPE html>
                <html>
                <head>
                    <title>' . esc_html__('Fatal Error Detected', 'easy-error-log') . '</title>
                    <meta charset="utf-8">
                    <meta name="viewport" content="width=device-width, initial-scale=1">
                    <style>
                        body { 
                            font-family: Arial, sans-serif; 
                            padding: 20px;
                            background: #f1f1f1;
                            display: flex;
                            align-items: center;
                            justify-content: center;
                            flex-direction: column;
                        }
                        pre {
                            display: none;
                        }
                        .container { 
                            background: white; 
                            padding: 30px; 
                            border-radius: 8px; 
                            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
                            margin: 20px;
                        }
                        .error-header { color: #d63638; border-bottom: 2px solid #d63638; padding-bottom: 15px; margin-bottom: 20px; }
                        .error-details { background: #fef7f7; border: 1px solid #d63638; padding: 15px; margin: 15px 0; border-radius: 4px; }
                        .plugin-info { background: #fff3cd; border: 1px solid #ffeaa7; padding: 15px; margin: 15px 0; border-radius: 4px; }
                        .actions { margin-top: 30px; text-align: center; }
                        .btn { display: inline-block; padding: 12px 24px; margin: 5px; text-decoration: none; border-radius: 4px; font-weight: bold; cursor: pointer; border: none; font-size: 14px; }
                        .btn-danger { background: #d63638; color: white; }
                        .btn-primary { background: #0073aa; color: white; }
                        .btn-secondary { background: #6c757d; color: white; }
                        .btn:hover { opacity: 0.9; }
                        .technical-details { margin-top: 30px; padding-top: 20px; border-top: 1px solid #ddd; font-size: 12px; color: #666; }
                    </style>
                </head>
                <body>
                    <div class="container">
                        <div class="error-header">
                            <h1>🚨 ' . esc_html__('Fatal Error Detected', 'easy-error-log') . '</h1>
                            <h2>' . esc_html__('Safety Mode Activated', 'easy-error-log') . '</h2>
                        </div>';

		if ( $deactivated_plugin ) {
			echo '
                <div class="plugin-info">
                    <h3>' . esc_html__('Plugin Information:', 'easy-error-log') . '</h3>
                    <p><strong>' . esc_html__('Plugin Name:', 'easy-error-log') . '</strong> ' . esc_html($plugin_name) . '</p>
                    <p><strong>' . esc_html__('Version:', 'easy-error-log') . '</strong> ' . esc_html($plugin_version) . '</p>
                    ' . wp_kses_post($plugin_info_message) . '
                </div>';
		}

			echo '

                <div class="error-details">
                    <h3>' . esc_html__('Error Information:', 'easy-error-log') . '</h3>
                    <p><strong>' . esc_html__('Type:', 'easy-error-log') . '</strong> ' . esc_html($error_type) . '</p>
                    <p><strong>' . esc_html__('Message:', 'easy-error-log') . '</strong> ' . esc_html($error['message']) . '</p>
                    <p><strong>' . esc_html__('File:', 'easy-error-log') . '</strong> ' . esc_html($error['file']) . '</p>
                    <p><strong>' . esc_html__('Line:', 'easy-error-log') . '</strong> ' . esc_html($error['line']) . '</p>
                    <p><strong>' . esc_html__('Time:', 'easy-error-log') . '</strong> ' . esc_html(gmdate('Y-m-d H:i:s')) . '</p>
                </div>
                
                <div class="actions">
                    <h3>' . esc_html__('Choose an action:', 'easy-error-log') . '</h3>
                    <a href="' . esc_url($home_url) . '" class="btn btn-primary">🏠 ' . esc_html__('Go to Homepage', 'easy-error-log') . '</a>
                </div>
            </div>
        </body>
        </html>';
		exit;
	}

	/**
	 * Display admin notice for deactivated plugins.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function show_deactivated_plugin_notice() {
		// Only show notices in admin area.
		if ( ! is_admin() ) {
			return;
		}

		$deactivated_plugins = get_option('easyerlo_deactivated_plugins', array());

		if ( empty($deactivated_plugins) || ! is_array($deactivated_plugins) ) {
			return;
		}

		// Filter out invalid entries.
		$valid_plugins = array();
		foreach ( $deactivated_plugins as $index => $plugin_info ) {
			if ( ! is_array($plugin_info) ) {
				continue;
			}

			// Check if we have valid plugin and error information.
			if ( ! isset($plugin_info['plugin']) ||
				! isset($plugin_info['error']) ||
				! is_array($plugin_info['error']) ||
				! isset($plugin_info['error']['message']) ||
				empty($plugin_info['error']['message']) ) {
				continue;
			}

			$valid_plugins[ $index ] = $plugin_info;
		}

		// If no valid plugins, clean up the option and return.
		if ( empty($valid_plugins) ) {
			delete_option('easyerlo_deactivated_plugins');
			return;
		}

		foreach ( $valid_plugins as $index => $plugin_info ) {
			// Get plugin information with proper validation.
			$plugin_name = isset($plugin_info['plugin_name']) && ! empty($plugin_info['plugin_name']) ?
				$plugin_info['plugin_name'] : $plugin_info['plugin'];

			$plugin_version = ( ! empty($plugin_info['plugin_version']) && $plugin_info['plugin_version'] !== 'Unknown' ) ?
				' v' . $plugin_info['plugin_version'] : '';

			$plugin_author = ( ! empty($plugin_info['plugin_author']) && $plugin_info['plugin_author'] !== 'Unknown' ) ?
				' by ' . $plugin_info['plugin_author'] : '';

			// Get error information.
			$error_data = $plugin_info['error'];
			$error_message = $error_data['message'];
			$error_file = isset($error_data['file']) && ! empty($error_data['file']) ? basename($error_data['file']) : 'Unknown file';
			$error_line = isset($error_data['line']) ? $error_data['line'] : 'Unknown';

			// Get time.
			$time_value = isset($plugin_info['time']) ? $plugin_info['time'] : time();
			$time = is_numeric($time_value) ? gmdate('Y-m-d H:i:s', $time_value) : 'Unknown time';

			echo '<div class="notice notice-error is-dismissible wpnts-fatal-error-notice" data-notice-id="' . esc_attr($index) . '">';
			echo '<div style="padding: 10px 0;">';
			echo '<h3 style="margin: 0 0 10px 0; color: #d63638;">🚨 Fatal Error Detected & Resolved</h3>';
			echo '<p><strong>Fatal Detector:</strong> The plugin <strong>' . esc_html($plugin_name . $plugin_version) . '</strong>' . esc_html($plugin_author) . ' was automatically deactivated due to a fatal error.</p>';
			echo '<div style="background: #f8f9fa; padding: 10px; border-left: 4px solid #d63638; margin: 10px 0;">';
			echo '<p style="margin: 0;"><strong>Error:</strong> ' . esc_html($error_message) . '</p>';
			echo '<p style="margin: 5px 0 0 0;"><strong>Location:</strong> ' . esc_html($error_file) . ' (Line ' . esc_html($error_line) . ') • <strong>Time:</strong> ' . esc_html($time) . '</p>';
			echo '</div>';
			echo '<p style="margin: 10px 0 0 0;"><em>Please contact the plugin developer, check for plugin updates, or review the plugin code before reactivating.</em></p>';
			echo '</div>';
			echo '</div>';
		}

		// Add script to handle dismissal with nonce verification.
		$nonce = wp_create_nonce('dismiss_easyerlo_notice');
		echo '<script>
		jQuery(document).ready(function($) {
			$(".wpnts-fatal-error-notice").on("click", ".notice-dismiss", function() {
				var $notice = $(this).parent();
				var noticeId = $notice.data("notice-id");
				
				$.post(ajaxurl, {
					action: "dismiss_easyerlo_notice",
					notice_id: noticeId,
					nonce: "' . esc_js($nonce) . '"
				}).done(function() {
					$notice.fadeOut();
				}).fail(function() {
					console.log("Failed to dismiss notice");
				});
			});
		});
		</script>';
	}

	/**
	 * Handle AJAX request to dismiss deactivated plugin notice.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function dismiss_deactivated_plugin_notice() {
		// Verify nonce and sanitize input.
		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'dismiss_easyerlo_notice' ) ) {
			wp_die( esc_html__( 'Security check failed', 'easy-error-log' ) );
		}

		$notice_id = isset( $_POST['notice_id'] ) ? absint( $_POST['notice_id'] ) : 0;
		$deactivated_plugins = get_option( 'easyerlo_deactivated_plugins', array() );

		if ( isset( $deactivated_plugins[ $notice_id ] ) ) {
			unset( $deactivated_plugins[ $notice_id ] );
			update_option( 'easyerlo_deactivated_plugins', array_values( $deactivated_plugins ) );
		}

		wp_die();
	}

	/**
	 * Get deactivated plugins for admin notices
	 *
	 * @return array Array of deactivated plugins
	 */
	public function get_deactivated_plugins() {
		return get_option('easyerlo_deactivated_plugins', array());
	}

	/**
	 * Clear deactivated plugins notices
	 */
	public function clear_deactivated_plugins_notices() {
		delete_option('easyerlo_deactivated_plugins');
	}

	/**
	 * Get the deactivation log
	 *
	 * @return array Array of logged deactivations
	 */
	public function get_deactivation_log() {
		return get_option('easyerlo_deactivation_log', array());
	}

	/**
	 * Clear the deactivation log
	 */
	public function clear_deactivation_log() {
		delete_option('easyerlo_deactivation_log');
	}
}
