<?php
/**
 * TitanCart template wrapper.
 *
 * WordPress includes this file via the template_include hook.
 * It collects the pending template + data from StorefrontModule,
 * extracts the variables into local scope, then includes the real template.
 *
 * Uses output buffering to inject the TitanCart site header right after
 * the <body> tag (since wp_body_open is not available in all themes).
 *
 * This file should never be accessed directly.
 *
 * @package TitanCart
 */

defined( 'ABSPATH' ) || exit;

$_tc_pending = \TitanCart\Storefront\StorefrontModule::consume_pending_template();

if ( ! $_tc_pending['file'] || ! file_exists( $_tc_pending['file'] ) ) {
    // Fallback: just load the theme's 404 template.
    include get_query_template( '404' ) ?: get_index_template();
    return;
}

// Extract data variables into this scope so the template can use them directly.
// e.g. $products, $params, $product, $category, $section, $user …
//
// IMPORTANT (S123): WordPress's wp-includes/template-loader.php does
//   `foreach ( $tag_templates as $tag => $template_getter )`
// before include-ing our wrapper. PHP foreach leaves the iterator vars in
// scope, so $tag, $template_getter, and $tag_templates leak in here as
// strings/array. EXTR_SKIP below would then refuse to overwrite our real
// $tag object from the data builder. Explicit unset clears the leak first.
unset( $tag, $template_getter, $tag_templates );

if ( ! empty( $_tc_pending['vars'] ) ) {
    extract( $_tc_pending['vars'], EXTR_SKIP ); // phpcs:ignore WordPress.PHP.DontExtract
}

// ── Output: with native theme, just include directly; otherwise inject header ──
if ( defined( 'TITANCART_THEME_ACTIVE' ) ) {
    // TitanCart theme is active — templates call get_header()/get_footer() natively.
    // No output buffering or header injection needed.
    include $_tc_pending['file'];
} else {
    // Third-party theme — use output buffering to inject our site header after <body>.
    //
    // S457 (R1 follow-up): the header MUST be rendered BEFORE the template is
    // included. render_site_header() registers its mobile-menu binding via
    // wp_add_inline_script() on a footer stub handle (WP.org R1 🅱1 relocation);
    // the template include below runs wp_footer, which prints and closes the
    // footer script queue. When the header rendered after the include, its
    // enqueue was a silent no-op — markup spliced in, handler script never
    // printed (S457 E2E: hamburger visible but dead). Render order fixed;
    // the splice position after <body> is unchanged.
    $_tc_header_html = '';
    ob_start();
    \TitanCart\Storefront\StorefrontModule::render_site_header();
    $_tc_header_html = ob_get_clean();

    ob_start();

    // Load the actual TitanCart template (shop/archive.php, product/single.php, etc.)
    include $_tc_pending['file'];

    $_tc_output = ob_get_clean();

    // Inject site header right after <body ...> tag.
    if ( $_tc_header_html ) {
        // Find the closing > of the <body> tag and insert after it.
        // Use callback to avoid backreference issues with $ in HTML.
        $_tc_output = preg_replace_callback(
            '/(<body[^>]*>)/i',
            function ( $m ) use ( $_tc_header_html ) {
                return $m[1] . $_tc_header_html;
            },
            $_tc_output,
            1 // only first match
        );
    }

    // The buffer below is a COMPLETE already-rendered HTML document (a full
    // TitanCart template that escaped every dynamic value at its own echo
    // sites, with the site header spliced in after <body>). There is no core
    // API that outputs an arbitrary composed document, and any escaping
    // function applied here would corrupt the page pipeline-wide (wp_kses
    // strips the very forms/scripts the templates legitimately emit). This is
    // the theme-pipeline output boundary — the same role wp-includes/
    // template-loader.php plays for themes — and is documented for reviewers
    // in docs/WPORG-REVIEWER-NOTES.md ("Escape-at-echo exceptions").
    echo $_tc_output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- theme-pipeline boundary: fully-rendered template document; every dynamic value escaped at its producing echo site; see WPORG-REVIEWER-NOTES.md.
}
