<?php
/**
 * Isolated ZERTI shop-order PDF downloads (admin-post endpoint + prefixed libraries).
 */

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

/**
 * Whether ZERTI server-side PDF generation is enabled.
 */
function zerti_shop_order_pdf_is_enabled(): bool
{
    if (!function_exists('zerti_get_plugin_settings')) {
        return true;
    }

    $settings = zerti_get_plugin_settings();
    $enabled = !isset($settings['general']['enable_server_pdf'])
        || !empty($settings['general']['enable_server_pdf']);

    return (bool) apply_filters('zerti_shop_order_pdf_enabled', $enabled);
}

/**
 * Parse order ID / doc / nonce from prefixed query args.
 *
 * @param array<string, mixed> $source
 * @return array{order_id:int,doc_type:string,nonce:string}
 */
function zerti_shop_order_pdf_parse_request_args_from_source(array $source): array
{
    $order_id = isset($source['zerti_oid']) ? absint(wp_unslash((string) $source['zerti_oid'])) : 0;
    $doc_type = isset($source['zerti_doc'])
        ? zerti_shop_order_pdf_normalize_doc_type(sanitize_key(wp_unslash((string) $source['zerti_doc'])))
        : 'invoice';
    $nonce = isset($source['zerti_nonce']) ? sanitize_text_field(wp_unslash((string) $source['zerti_nonce'])) : '';

    return [
        'order_id' => $order_id,
        'doc_type' => $doc_type,
        'nonce' => $nonce,
    ];
}

/**
 * Whether the php-psr extension is active (registers PsrExt\* interfaces).
 *
 * mPDF's psr-http-message-shim uses strict method signatures that are incompatible with PsrExt.
 */
function zerti_shop_order_pdf_has_psrext_extension(): bool
{
    return interface_exists('PsrExt\Http\Message\RequestInterface', false);
}

/**
 * Load PsrExt-compatible copies of mPDF's psr-http-message-shim before Composer autoload.
 *
 * A prepend autoloader is not reliable on shared hosting (other plugins' ClassLoaders can
 * still pull the typed vendor shim first). Eager require_once defines the classes early.
 *
 * @return bool False when PsrExt is active but compat files are missing.
 */
function zerti_shop_order_pdf_apply_psrext_shim_compat(): bool
{
    static $applied = false;
    if ($applied) {
        return true;
    }

    $applied = true;

    if (!zerti_shop_order_pdf_has_psrext_extension()) {
        return true;
    }

    $compat_dir = plugin_dir_path(ZERTI_PLUGIN_FILE) . 'includes/mpdf-psr-shim-compat/';
    $shim_files = [
        'Stream.php',
        'Uri.php',
        'Request.php',
        'Response.php',
    ];

    foreach ($shim_files as $basename) {
        $path = $compat_dir . $basename;
        if (!is_readable($path)) {
            if (defined('WP_DEBUG') && WP_DEBUG && function_exists('error_log')) {
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
                error_log('ZERTI PDF: missing PsrExt shim compat file: ' . $path);
            }

            return false;
        }
    }

    foreach ($shim_files as $basename) {
        require_once $compat_dir . $basename;
    }

    return true;
}

/**
 * Load ZERTI PDF libraries from vendor/ (includes mPDF data/, fonts, and default CSS).
 *
 * The php-scoper copy under vendor-prefixed/ contains PHP only — no mPDF data assets — so it
 * must not be used for rendering (PDFs would lose all styling).
 */
function zerti_shop_order_pdf_load_libraries(): bool
{
    static $loaded = false;
    static $used_prefixed_vendor = false;
    if ($loaded) {
        return true;
    }

    if (!zerti_shop_order_pdf_apply_psrext_shim_compat()) {
        return false;
    }

    $autoload_candidates = [
        plugin_dir_path(ZERTI_PLUGIN_FILE) . 'vendor/autoload.php',
        plugin_dir_path(ZERTI_PLUGIN_FILE) . 'vendor-prefixed/vendor/autoload.php',
    ];

    $autoload_loaded = false;
    foreach ($autoload_candidates as $autoload) {
        if (!is_readable($autoload)) {
            continue;
        }

        try {
            require_once $autoload;
            $autoload_loaded = true;
            $used_prefixed_vendor = strpos(str_replace('\\', '/', $autoload), '/vendor-prefixed/') !== false;
            break;
        } catch (\Throwable $e) {
            if (function_exists('error_log')) {
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
                error_log('ZERTI PDF autoload failed (' . $autoload . '): ' . $e->getMessage());
            }
        }
    }

    if (!$autoload_loaded) {
        return false;
    }

    $loaded = true;

    return true;
}

/**
 * Whether mPDF can be used for rendering (requires full vendor assets).
 */
function zerti_shop_order_pdf_can_use_mpdf(): bool
{
    static $checked = false;
    static $can_use = false;
    static $used_prefixed_vendor = false;

    if ($checked) {
        return $can_use;
    }

    $checked = true;
    if (!zerti_shop_order_pdf_load_libraries()) {
        $can_use = false;

        return $can_use;
    }

    // If normal vendor exists, mPDF data assets are available.
    $main_vendor_autoload = plugin_dir_path(ZERTI_PLUGIN_FILE) . 'vendor/autoload.php';
    $used_prefixed_vendor = !is_readable($main_vendor_autoload);

    // Prefixed vendor copy is PHP-only and may miss mPDF data assets.
    if ($used_prefixed_vendor) {
        $can_use = false;

        return $can_use;
    }

    $can_use = class_exists(\Mpdf\Mpdf::class);

    return $can_use;
}

/**
 * Whether PDF libraries are available.
 */
function zerti_shop_order_pdf_libraries_available(): bool
{
    if (!zerti_shop_order_pdf_load_libraries()) {
        return false;
    }

    if (zerti_shop_order_pdf_can_use_mpdf()) {
        return true;
    }

    return class_exists(\Dompdf\Dompdf::class) && class_exists(\Dompdf\Options::class);
}

/**
 * Clear output buffers before streaming a binary PDF response.
 */
function zerti_shop_order_pdf_prepare_response(): void
{
    if (!headers_sent()) {
        nocache_headers();
    }

    while (ob_get_level() > 0) {
        ob_end_clean();
    }
}

/**
 * Validate and stream a shop order PDF (does not return).
 */
function zerti_shop_order_pdf_serve(int $order_id, string $nonce, string $doc_type): void
{
    zerti_shop_order_pdf_prepare_response();

    if (!zerti_shop_order_pdf_is_enabled()) {
        wp_die(esc_html__('ZERTI PDF download is disabled.', 'zerti'), '', ['response' => 403]);
    }

    $doc_type = zerti_shop_order_pdf_normalize_doc_type($doc_type);

    if ($order_id < 1 || $nonce === '' || !wp_verify_nonce($nonce, 'zerti_shop_order_pdf_' . $doc_type . '_' . $order_id)) {
        wp_die(esc_html__('Invalid request.', 'zerti'), '', ['response' => 403]);
    }

    if (!is_user_logged_in()) {
        wp_die(esc_html__('Unauthorized.', 'zerti'), '', ['response' => 403]);
    }

    if (!function_exists('zerti_user_can_view_shop_order') || !zerti_user_can_view_shop_order($order_id)) {
        wp_die(esc_html__('You do not have permission to view this order.', 'zerti'), '', ['response' => 403]);
    }

    $order = function_exists('wc_get_order') ? wc_get_order($order_id) : null;
    if (!is_a($order, 'WC_Order')) {
        wp_die(esc_html__('Order not found.', 'zerti'), '', ['response' => 404]);
    }

    if (!function_exists('zerti_shop_order_can_open_invoice') || !zerti_shop_order_can_open_invoice($order)) {
        wp_die(esc_html__('Invoice is only available for completed, processing, or pending payment orders.', 'zerti'), '', ['response' => 403]);
    }

    if (!zerti_shop_order_pdf_libraries_available()) {
        wp_die(
            esc_html__('ZERTI PDF library is not available.', 'zerti'),
            '',
            ['response' => 500]
        );
    }

    $tmp_dir = zerti_shop_order_pdf_temp_dir();
    $filename = zerti_shop_order_pdf_filename($order_id, $doc_type);

    if (zerti_shop_order_pdf_can_use_mpdf()) {
        try {
            zerti_shop_order_pdf_stream_mpdf($order, $filename, $tmp_dir, $doc_type);
        } catch (\Throwable $e) {
            if (defined('WP_DEBUG') && WP_DEBUG && function_exists('error_log')) {
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
                error_log(
                    'ZERTI mPDF error (order '
                    . $order_id
                    . ', doc '
                    . $doc_type
                    . '): '
                    . $e->getMessage()
                    . ' in '
                    . $e->getFile()
                    . ':'
                    . $e->getLine()
                );
            }

            if (class_exists(\Dompdf\Dompdf::class) && class_exists(\Dompdf\Options::class)) {
                try {
                    zerti_shop_order_pdf_stream_dompdf($order, $filename, $tmp_dir, $doc_type);
                } catch (\Throwable $fallback_error) {
                    if (defined('WP_DEBUG') && WP_DEBUG && function_exists('error_log')) {
                        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
                        error_log(
                            'ZERTI Dompdf fallback error (order '
                            . $order_id
                            . ', doc '
                            . $doc_type
                            . '): '
                            . $fallback_error->getMessage()
                        );
                    }
                }
            }

            wp_die(
                esc_html(zerti_shop_order_pdf_error_message($e)),
                '',
                ['response' => 500]
            );
        }
    }

    try {
        zerti_shop_order_pdf_stream_dompdf($order, $filename, $tmp_dir, $doc_type);
    } catch (\Throwable $e) {
        if (defined('WP_DEBUG') && WP_DEBUG && function_exists('error_log')) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
            error_log(
                'ZERTI Dompdf error (order '
                . $order_id
                . ', doc '
                . $doc_type
                . '): '
                . $e->getMessage()
            );
        }

        wp_die(
            esc_html(zerti_shop_order_pdf_error_message($e)),
            '',
            ['response' => 500]
        );
    }
}

/**
 * User-facing PDF failure message; includes exception text when WP_DEBUG is on.
 */
function zerti_shop_order_pdf_error_message(?\Throwable $error = null): string
{
    $message = __('Error generating PDF with mPDF.', 'zerti');

    if ($error instanceof \Throwable && defined('WP_DEBUG') && WP_DEBUG) {
        $message .= ' ' . $error->getMessage();
    }

    return $message;
}

/**
 * Dedicated admin-post handler (avoids admin-ajax.php where invoice plugins often hook).
 */
function zerti_admin_post_download_order_pdf(): void
{
    // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce verified before serve().
    $order_id = isset($_GET['zerti_oid']) ? absint(wp_unslash((string) $_GET['zerti_oid'])) : 0;
    $nonce = isset($_GET['zerti_nonce']) ? sanitize_text_field(wp_unslash((string) $_GET['zerti_nonce'])) : '';
    $doc_type = isset($_GET['zerti_doc'])
        ? zerti_shop_order_pdf_normalize_doc_type(sanitize_key(wp_unslash((string) $_GET['zerti_doc'])))
        : 'invoice';

    if ($order_id < 1 || $nonce === '' || !wp_verify_nonce($nonce, 'zerti_shop_order_pdf_' . $doc_type . '_' . $order_id)) {
        wp_die(esc_html__('Invalid request.', 'zerti'), '', ['response' => 403]);
    }

    if (!is_user_logged_in()) {
        wp_die(esc_html__('Unauthorized.', 'zerti'), '', ['response' => 403]);
    }

    if (!function_exists('zerti_user_can_view_shop_order') || !zerti_user_can_view_shop_order($order_id)) {
        wp_die(esc_html__('You do not have permission to view this order.', 'zerti'), '', ['response' => 403]);
    }

    zerti_shop_order_pdf_serve($order_id, $nonce, $doc_type);
}

/**
 * Register the isolated PDF download endpoint.
 */
function zerti_register_shop_order_pdf_hooks(): void
{
    if (!zerti_shop_order_pdf_is_enabled()) {
        return;
    }

    add_action('admin_post_zerti_download_order_pdf', 'zerti_admin_post_download_order_pdf', 0);
}

add_action('plugins_loaded', 'zerti_register_shop_order_pdf_hooks', 5);

zerti_shop_order_pdf_apply_psrext_shim_compat();
