<?php

/**
 * Serves Parkstatic static files when static mode is on.
 *
 * @package Parkstatic
 */
declare (strict_types = 1);
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
$parkstatic_uri = ( defined( 'PARKSTATIC_REQUEST_URI' ) ? PARKSTATIC_REQUEST_URI : Parkstatic_Static_File_Server::normalize_uri( (string) (( wp_parse_url( ( isset( $_SERVER['REQUEST_URI'] ) ? sanitize_url( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '/' ), PHP_URL_PATH ) ?: '/' )) ) );
$parkstatic_method = strtoupper( sanitize_text_field( wp_unslash( (string) ($_SERVER['REQUEST_METHOD'] ?? 'GET') ) ) );
if ( !in_array( $parkstatic_method, array('GET', 'HEAD'), true ) ) {
    return;
}
$parkstatic_wp_paths = array(
    '/wp-admin',
    '/wp-login.php',
    '/wp-signup.php',
    '/wp-activate.php',
    '/wp-json',
    '/wp-content',
    '/wp-includes',
    '/wp-cron.php',
    '/xmlrpc.php',
    '/studio-auto-login'
);
foreach ( $parkstatic_wp_paths as $parkstatic_wp_path ) {
    if ( 0 === strpos( $parkstatic_uri, $parkstatic_wp_path ) ) {
        return;
    }
}
if ( !empty( $_GET['redirect_to'] ) ) {
    // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- wp-admin passthrough routing only.
    $parkstatic_redirect_to = rawurldecode( sanitize_url( wp_unslash( $_GET['redirect_to'] ) ) );
    // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- public front-end wp-admin passthrough routing; no form is processed.
    if ( preg_match( '#/(wp-admin|wp-login\\.php)(/|$|\\?)#', $parkstatic_redirect_to ) ) {
        return;
    }
}
$parkstatic_site_root = ( defined( 'PARKSTATIC_SITE_ROOT' ) ? PARKSTATIC_SITE_ROOT : ABSPATH );
$parkstatic_root_php = $parkstatic_site_root . $parkstatic_uri . '.php';
if ( is_file( $parkstatic_root_php ) ) {
    return;
}
$parkstatic_resolved = Parkstatic_Static_File_Server::resolve( $parkstatic_uri );
if ( null === $parkstatic_resolved ) {
    $parkstatic_looks_like_asset = 0 === strpos( $parkstatic_uri, '/assets/' );
    if ( !$parkstatic_looks_like_asset ) {
        $parkstatic_extension = strtolower( pathinfo( $parkstatic_uri, PATHINFO_EXTENSION ) );
        $parkstatic_looks_like_asset = '' !== $parkstatic_extension && 'html' !== $parkstatic_extension && 'php' !== $parkstatic_extension;
    }
    if ( $parkstatic_looks_like_asset ) {
        // Relative ES module specifiers resolve against the module URL's
        // path and drop the query string (WHATWG URL spec). When the entry
        // chunk is served via the legacy /?parkstatic_asset=<file> form, an
        // `import("./chunk-HASH.js")` inside it resolves to /chunk-HASH.js
        // (root) — a URL the handler does not otherwise match. Redirect it to
        // the install's canonical asset base so the bytes are at least served
        // instead of 404ing.
        //
        // NOTE: this redirect does NOT make the browser treat the chunk as one
        // module. The module map is keyed by request URL, and a redirect does
        // not collapse `/chunk-HASH.js` and `/?parkstatic_asset=chunk-HASH.js`
        // into a single entry — so under the legacy base a chunk reached by a
        // relative import is still evaluated separately from the same chunk
        // reached via the rewritten <link rel="modulepreload">, giving two
        // React copies and "Invalid hook call" (#321). Only the clean /assets/
        // base fully avoids that (relative imports resolve to /assets/<file>,
        // matching every other reference), which is why detect_and_store_
        // legacy_asset_base() biases hard toward it. This branch is a
        // best-effort net for the legacy base and for non-module root-relative
        // references (e.g. new URL("./x", import.meta.url)); it is dormant in
        // clean mode, where relative imports resolve on the first resolve()
        // and never reach here.
        if ( '/' === dirname( $parkstatic_uri ) ) {
            $parkstatic_fallback = Parkstatic_Static_File_Server::resolve( '/assets/' . basename( $parkstatic_uri ) );
            if ( null !== $parkstatic_fallback ) {
                $parkstatic_target = Parkstatic_Static_File_Server::get_public_asset_base() . rawurlencode( basename( $parkstatic_uri ) );
                if ( function_exists( 'status_header' ) ) {
                    status_header( 302 );
                } else {
                    http_response_code( 302 );
                }
                header( 'Location: ' . $parkstatic_target );
                // Stable per-deploy (hashed filenames map 1:1 to a single
                // canonical URL), but a flip between legacy and clean asset
                // bases should self-heal quickly, so keep the edge TTL short.
                header( 'Cache-Control: public, max-age=300' );
                exit;
            }
        }
        // Never let a transient missing-asset response get cached at the
        // edge: a deploy removes old hashed filenames, and a cached 404 for
        // them outlives the new index.html that no longer references them.
        // no-store keeps deploys self-healing without touching Cloudflare.
        if ( function_exists( 'status_header' ) ) {
            status_header( 404 );
        } else {
            http_response_code( 404 );
        }
        header( 'Cache-Control: no-store' );
        exit;
    }
    return;
}
Parkstatic_Static_File_Server::output( $parkstatic_resolved['file'], $parkstatic_resolved['content_root'], ( isset( $parkstatic_resolved['status'] ) ? (int) $parkstatic_resolved['status'] : 200 ) );