<?php

declare(strict_types=1);

namespace PrettyLinks\Pro\RedirectTypes;

use PrettyLinks\Pro\PrettyBar\FrameDetector;

/**
 * Invisible iframe cloak — address bar stays on the pretty URL while the
 * target page renders inside a full-viewport frame. Drop-in replacement
 * for v3's `cloak` redirect type. Falls back to a plain 302 when the
 * target page forbids framing (X-Frame-Options / CSP frame-ancestors).
 *
 * Subscribes to `prli_issue_cloaked_redirect` alongside Pretty Bar — each
 * renderer inspects `redirect_type` and skips if it isn't its.
 */
final class CloakRenderer
{
    /**
     * `prli_issue_cloaked_redirect` action callback.
     *
     * @param string               $redirectType Link redirect_type value.
     * @param array<string, mixed> $link         Link row.
     * @param string               $target       Resolved outbound URL.
     * @param string               $paramString  Forwarded query/param string (v3 arg 4).
     * @param integer              $status       Fallback HTTP status (v4 additive arg 5).
     */
    public function handle(string $redirectType, array $link, string $target, string $paramString, int $status): void
    {
        unset($paramString, $status);
        if ($redirectType !== 'cloak') {
            return;
        }

        if (!(new FrameDetector())->allowsFraming($target)) {
            // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- Pretty Links redirects to user-configured external destinations by design.
            wp_redirect($target, 302, 'Pretty Links');
            exit;
        }

        $this->render($link, $target);
        exit;
    }

    /**
     * Renders the cloaking iframe document for the target URL.
     *
     * @param array<string, mixed> $link   Link row.
     * @param string               $target Resolved outbound URL.
     *
     * @return void
     */
    private function render(array $link, string $target): void
    {
        nocache_headers();
        if (!headers_sent()) {
            header('Content-Type: text/html; charset=utf-8');
            header('X-Pretty-Link: cloak');
        }

        $title = (string) ($link['name'] ?? 'Pretty Link');

        echo '<!doctype html><html lang="en"><head>';
        echo '<meta charset="utf-8">';
        echo '<meta name="robots" content="noindex,nofollow">';
        echo '<meta name="viewport" content="width=device-width,initial-scale=1">';
        echo '<title>' . esc_html($title) . '</title>';
        echo '<style>html,body{margin:0;padding:0;height:100%;overflow:hidden}'
            . 'iframe{border:0;width:100%;height:100%;display:block}</style>';
        do_action('prli_cloak_head', $link);
        echo '</head><body>';
        echo '<iframe src="' . esc_url($target) . '" title="' . esc_attr($title) . '">';
        echo esc_html__('Your browser does not support frames.', 'pretty-link-pro') . ' ';
        // phpcs:ignore Squiz.Commenting.InlineComment.NotCapital,Squiz.Commenting.InlineComment.InvalidEndChar -- WordPress translator comment, kept verbatim.
        // translators: %s: link to the destination
        $parts = explode('%s', __('Click %s to continue.', 'pretty-link-pro'), 2);
        echo esc_html($parts[0] ?? '')
            . '<a href="' . esc_url($target) . '">' . esc_html__('here', 'pretty-link-pro') . '</a>'
            . esc_html($parts[1] ?? '');
        echo '</iframe>';
        echo '</body></html>';
    }
}
