<?php

declare(strict_types=1);

namespace Acms\Services\HtmlPurifier;

/**
 * iframe の src を許可ホストに限定するための PCRE を生成・判定する。
 *
 * HTMLPurifier の URI.SafeIframeRegexp はホスト文字列をそのまま正規表現に流すため、
 * preg_quote によるメタ文字の安全化、プロトコル相対 (//) / http / https の吸収、
 * ポート以外での区切り偽装（userinfo @ など）の排除を一箇所に集約する。
 *
 * build() と matches() が同一の正規表現ロジックを共有することで、
 * SafeIframe フィルタの判定（URI.SafeIframeRegexp）と
 * post-transform でのホスト解決（IframePolicyTransform）の結果が一致することを保証する。
 */
final class SafeIframeRegexp
{
    /**
     * 許可ホストの配列から URI.SafeIframeRegexp 用の PCRE を生成する。
     *
     * @param string[] $hosts 許可ホスト名の配列
     * @return string|null 有効なホストが無い場合は null（iframe を許可しないシグナル）
     */
    public static function build(array $hosts): ?string
    {
        $patterns = [];
        foreach ($hosts as $host) {
            $pattern = self::hostPattern($host);
            if ($pattern !== null) {
                $patterns[] = $pattern;
            }
        }
        if ($patterns === []) {
            return null;
        }

        // ^(?:https?:)?//  … プロトコル相対・http・https を吸収
        // (?:host1|host2)  … preg_quote 済みの許可ホスト
        // (?::\d+)?        … 任意のポート（数字のみ。userinfo の `:pass@` を弾く）
        // (?:[/?#]|$)      … ホスト境界（パス・クエリ・フラグメント・終端のみ許可）
        return '%^(?:https?:)?//(?:' . implode('|', $patterns) . ')(?::\d+)?(?:[/?#]|$)%i';
    }

    /**
     * 単一ホストに対して URL がマッチするか判定する。
     *
     * build() と同一の正規表現を用いるため、SafeIframe フィルタの通過可否と一致する。
     *
     * @param string $url 判定対象の URL（iframe の src）
     * @param string $host 許可ホスト名
     * @return bool
     */
    public static function matches(string $url, string $host): bool
    {
        $regexp = self::build([$host]);
        if ($regexp === null) {
            return false;
        }
        return preg_match($regexp, $url) === 1;
    }

    /**
     * ホスト名を正規表現の部分パターンに変換する。
     *
     * @param string $host
     * @return string|null 空文字なら null
     */
    private static function hostPattern(string $host): ?string
    {
        $host = trim($host);
        if ($host === '') {
            return null;
        }
        return preg_quote($host, '%');
    }
}
