<?php

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

add_filter( 'wp_php_error_message', 'prodigy_render_php_error_message', 10, 2 );
add_filter( 'wp_php_error_args', 'prodigy_php_error_args', 10, 2 );
add_filter( 'wp_die_handler', 'prodigy_wp_die_handler' );

/**
 * @return bool
 */
function prodigy_is_debug_mode_enabled(): bool {
	$debug_constants = array(
		'WP_DEBUG',
		'WP_DEBUG_LOG',
		'WP_DEBUG_DISPLAY',
		'SCRIPT_DEBUG',
	);

	foreach ( $debug_constants as $constant ) {
		if ( defined( $constant ) && constant( $constant ) ) {
			return true;
		}
	}

	return false;
}

/**
 * @param array $error Fatal error information.
 *
 * @return bool
 */
function prodigy_is_plugin_production_php_error( array $error ): bool {
	$error_file = wp_normalize_path( (string) ( $error['file'] ?? '' ) );
	$plugin_dir = wp_normalize_path( PRODIGY_PLUGIN_PATH );

	if ( strpos( $error_file, $plugin_dir ) !== 0 ) {
		return false;
	}

	return ! prodigy_is_debug_mode_enabled();
}

/**
 * @param Throwable $error Error thrown by the plugin autoloader.
 * @param string    $file  File path being loaded.
 *
 * @return void
 */
function prodigy_handle_autoload_fatal_error( Throwable $error, string $file ): void {
	$plugin_dir = wp_normalize_path( PRODIGY_PLUGIN_PATH );
	$error_file = wp_normalize_path( $file );

	if ( prodigy_is_debug_mode_enabled() || strpos( $error_file, $plugin_dir ) !== 0 ) {
		throw $error;
	}

	if ( ! headers_sent() ) {
		status_header( 500 );
		nocache_headers();
		header( 'Content-Type: text/html; charset=' . get_bloginfo( 'charset' ) );
	}

	prodigy_render_fatal_500_template();
	exit;
}

/**
 * @return void
 */
function prodigy_render_500_error_content(): void {
	$template = PRODIGY_PLUGIN_PATH . 'templates/partials/content-error.php';
	if ( ! is_readable( $template ) ) {
		return;
	}

	$error_number = '500';
	$error_title  = __( 'Unexpected Error', 'prodigy-commerce' );
	$error_body   = '';
	include $template;
}

/**
 * @return string
 */
function prodigy_get_fatal_error_stylesheet_url(): string {
	return PRODIGY_PLUGIN_URL . 'web/templates/css/fatal-error.css';
}

/**
 * @param string $content Fatal error page content.
 *
 * @return void
 */
function prodigy_render_500_error_document( string $content = '' ): void {
	$charset = function_exists( 'get_bloginfo' ) ? get_bloginfo( 'charset' ) : 'utf-8';
	$dir     = function_exists( 'is_rtl' ) && is_rtl() ? 'rtl' : 'ltr';

	if ( $content === '' ) {
		ob_start();
		prodigy_render_500_error_content();
		$content = (string) ob_get_clean();
	}

	echo '<!DOCTYPE html>';
	?>
<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
<head>
	<meta charset="<?php echo esc_attr( $charset ); ?>">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title><?php esc_html_e( 'Unexpected Error', 'prodigy-commerce' ); ?></title>
	<link rel="stylesheet" href="<?php echo esc_url( prodigy_get_fatal_error_stylesheet_url() ); ?>">
</head>
<body dir="<?php echo esc_attr( $dir ); ?>">
	<?php echo wp_kses_post( $content ); ?>
</body>
</html>
	<?php
}

/**
 * @return void
 */
function prodigy_render_fatal_500_template(): void {
	prodigy_render_500_error_document();
}

/**
 * Replace WordPress' production fatal-error message with the Prodigy 500 template.
 *
 * @param string $message WordPress default fatal error message.
 * @param array  $error   Fatal error information.
 *
 * @return string
 */
function prodigy_render_php_error_message( string $message, array $error ): string {
	if ( ! prodigy_is_plugin_production_php_error( $error ) ) {
		return $message;
	}

	ob_start();
	prodigy_render_500_error_content();
	$GLOBALS['prodigy_php_error_template_active'] = true;
	return (string) ob_get_clean();
}

/**
 * Keep the fatal-error response as a server error while allowing custom markup.
 *
 * @param array $args  WordPress default fatal error arguments.
 * @param array $error Fatal error information.
 *
 * @return array
 */
function prodigy_php_error_args( array $args, array $error ): array {
	if ( ! prodigy_is_plugin_production_php_error( $error ) ) {
		return $args;
	}

	$args['response'] = 500;
	return $args;
}

/**
 * Use Prodigy's 500 template only for plugin production errors.
 *
 * @param callable $handler WordPress default wp_die handler.
 *
 * @return callable
 */
function prodigy_wp_die_handler( $handler ) {
	if ( ! empty( $GLOBALS['prodigy_php_error_template_active'] ) ) {
		return 'prodigy_php_error_die_handler';
	}

	return $handler;
}

/**
 * Render Prodigy's custom 500 template without WordPress' default wp_die wrapper.
 *
 * @param string|WP_Error $message Error message.
 * @param string          $title   Error title.
 * @param array           $args    Error arguments.
 *
 * @return void
 */
function prodigy_php_error_die_handler( $message, string $title = '', array $args = array() ): void {
	$defaults = array(
		'response' => 500,
		'exit'     => true,
	);
	$args     = wp_parse_args( $args, $defaults );
	$content  = is_wp_error( $message ) ? $message->get_error_message() : (string) $message;
	$charset  = function_exists( 'get_bloginfo' ) ? get_bloginfo( 'charset' ) : 'utf-8';

	if ( ! headers_sent() ) {
		status_header( (int) $args['response'] );
		nocache_headers();
		header( 'Content-Type: text/html; charset=' . $charset );
	}

	prodigy_render_500_error_document( $content );

	if ( $args['exit'] ) {
		die();
	}
}
