<?php
/**
 * TODO-CLIENT-005 (2026-08-02): Centralised redirect helper.
 *
 * Wraps wp_safe_redirect + the SWAPADS_TESTING_REDIRECT_EXIT guard in a
 * single call. This replaces the 15-duplication pattern:
 *
 *   wp_safe_redirect($url);
 *   if (!defined('SWAPADS_TESTING_REDIRECT_EXIT')) { exit; }
 *
 * With a single call:
 *
 *   Redirect::to($url);
 *   // or with a different HTTP status:
 *   Redirect::to($url, 303);
 *
 * Why this exists:
 *  - DRY: 15 admin handlers all had the same boilerplate.
 *  - Safe by default: Redirect::to() is testable (no exit) in test mode
 *    via SWAPADS_TESTING_REDIRECT_EXIT (set in tests/bootstrap.php).
 *  - Future-proof: a single point to add audit logging, rate limit,
 *    or swap to wp_safe_redirect with allowlist-based URL validation.
 *
 * Naming: short (`Redirect::to()`) because the namespace is already long
 * (`\SwapAds\Client\Http\Redirect`).
 *
 * @package SwapAds\Client\Http
 * @since   1.5.9
 */

declare(strict_types=1);

namespace SwapAds\Client\Http;

final class Redirect
{
    /**
     * Issue an HTTP redirect to $url via wp_safe_redirect + exit.
     *
     * In production: redirects and exits. The browser navigates to $url.
     * In tests: returns silently when SWAPADS_TESTING_REDIRECT_EXIT is
     *           defined (set in tests/bootstrap.php to skip the exit so
     *           PHPUnit can assert on the captured redirect URL).
     *
     * @param string $url    Target URL (must already be a safe URL; we use
     *                       wp_safe_redirect which validates against the
     *                       site's host allowlist).
     * @param int    $status HTTP status code (default 302 = temporary).
     *
     * @return void
     *
     * @since 1.5.9
     */
    public static function to(string $url, int $status = 302): void
    {
        // Trust wp_safe_redirect's own allowlist — it's the canonical WP
        // way to redirect safely (blocks off-host URLs by default).
        wp_safe_redirect($url, $status, 'SwapAds');

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

    /**
     * Issue a 303 redirect to the admin URL with optional query args.
     *
     * Convenience helper for the most common pattern: redirect back to
     * the current admin page with a flash message and an updated $_GET
     * parameter (e.g., ?action=delete&deleted=42).
     *
     * @param array<string, mixed> $args Query args to merge into admin URL.
     *                                  Existing args are merged (new wins).
     *
     * @return void
     *
     * @since 1.5.9
     */
    public static function backToAdmin(array $args = []): void
    {
        // Use wp_get_referer if present, fallback to current admin URL.
        $base = wp_get_referer();
        if (!is_string($base) || $base === '') {
            $base = admin_url();
        }
        $url = $args === [] ? $base : add_query_arg($args, $base);
        self::to($url);
    }
}
