<?php

declare(strict_types=1);

namespace PrettyLinks\Pro\PrettyBar;

use PrettyLinks\Pro\Options\Store as OptionsStore;
use PrettyLinks\Pro\PrettyBar\Templates\BarTemplate;
use PrettyLinks\Pro\PrettyBar\Templates\BottomBarTemplate;
use PrettyLinks\Pro\PrettyBar\Templates\FloatingTemplate;
use PrettyLinks\Pro\PrettyBar\Templates\LegacyTemplate;
use PrettyLinks\Pro\PrettyBar\Templates\TopBarTemplate;
use PrettyLinks\Repositories\LinkMetas;

/**
 * Pretty Bar dispatcher.
 *
 * Subscribes to `prli_issue_cloaked_redirect`, decides which template
 * handles the link, and delegates. Templates:
 *
 *   - legacy     — fallback for Pretty Bar links migrated from 3.x
 *                  (no `prettybar_template` meta). Hidden from pickers.
 *   - top-bar    — modern horizontal bar at top of viewport.
 *   - bottom-bar — modern horizontal bar docked to bottom.
 *   - floating   — compact pill in a corner, optionally dismissible.
 *
 * Also exposes {@see self::modernTemplates()} for the admin UI so there's
 * a single source of truth for template IDs/labels.
 */
final class BarRenderer
{
    /**
     * Registered bar templates keyed by template ID.
     *
     * @var array<string, BarTemplate>
     */
    private array $templates;

    /**
     * Link meta repository.
     *
     * @var LinkMetas
     */
    private LinkMetas $linkMetas;

    /**
     * Builds the dispatcher and registers the available templates.
     *
     * @param LinkMetas $linkMetas Link meta repository.
     */
    public function __construct(LinkMetas $linkMetas)
    {
        $this->linkMetas = $linkMetas;
        $this->templates = [
            LegacyTemplate::ID    => new LegacyTemplate(),
            TopBarTemplate::ID    => new TopBarTemplate(),
            BottomBarTemplate::ID => new BottomBarTemplate(),
            FloatingTemplate::ID  => new FloatingTemplate(),
        ];
    }

    /**
     * `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 !== 'prettybar') {
            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;
        }

        $template = $this->resolveTemplate($link);
        $template->render($link, $target, $template->settings());
        exit;
    }

    /**
     * Returns the modern templates (all except legacy) — used by the
     * options UI and link-form picker.
     *
     * @return array<int, array{id: string, label: string}>
     */
    public static function modernTemplates(): array
    {
        return [
            [
                'id'    => TopBarTemplate::ID,
                'label' => (new TopBarTemplate())->label(),
            ],
            [
                'id'    => BottomBarTemplate::ID,
                'label' => (new BottomBarTemplate())->label(),
            ],
            [
                'id'    => FloatingTemplate::ID,
                'label' => (new FloatingTemplate())->label(),
            ],
        ];
    }

    /**
     * Whether the Pretty Bar redirect type is offered to admins.
     */
    public static function isActive(): bool
    {
        return (bool) get_option(Settings::ACTIVE_OPTION, true);
    }

    /**
     * Resolves which template should render the given link.
     *
     * @param array<string, mixed> $link Link row.
     *
     * @return BarTemplate The resolved template.
     */
    private function resolveTemplate(array $link): BarTemplate
    {
        $linkId = (int) ($link['id'] ?? 0);
        $meta   = $linkId > 0
            ? (string) $this->linkMetas->get($linkId, 'prettybar_template', '')
            : '';

        if ($meta !== '' && isset($this->templates[$meta])) {
            return $this->templates[$meta];
        }

        // Site-wide default: admin-selected template used whenever a link has
        // no per-link `prettybar_template` meta. Falls back to legacy (v3
        // parity) only if the configured default is unknown or empty.
        $siteDefault = (string) (new OptionsStore())->getPro('pretty_bar_default', '');
        if ($siteDefault !== '' && isset($this->templates[$siteDefault])) {
            return $this->templates[$siteDefault];
        }

        return $this->templates[LegacyTemplate::ID];
    }
}
