<?php

declare(strict_types=1);

namespace Acms\Services\HtmlPurifier;

use HTMLPurifier_AttrTransform;

/**
 * iframe の権限付与系属性（allow / sandbox）を、ホストポリシーの許可リストでフィルタする post-transform。
 *
 * allow / sandbox は PurifierFactory で CDATA として宣言しているため、編集者の入力は
 * AttrValidator の属性検証段階では変更されずそのまま残る。本 transform はその後段（post）で動作し、
 * src のホストにマッチした場合に「編集者が要求したトークンのうち、そのホストの許可リストに
 * 含まれるものだけ」を残す（フィルタ）。許可リスト外のトークンは常に落ち、編集者が何も
 * 書いていなければ何も付与しない（強制デフォルトは無い）。したがって「どの属性を許すか」ではなく
 * 「どのホストでどの capability を要求できるか（上限）」を一元管理できる。
 *
 * HTMLPurifier はカスタム HTML 定義をシリアライズしてキャッシュするため、本クラスは
 * プレーンなデータ（{@see IframePolicy}）のみを保持し、シリアライズ可能に保つ。
 */
final class IframePolicyTransform extends HTMLPurifier_AttrTransform
{
    private IframePolicy $policy;

    public function __construct(IframePolicy $policy)
    {
        $this->policy = $policy;
    }

    /**
     * @param array<array-key, mixed> $attr 属性の連想配列
     * @param \HTMLPurifier_Config $config
     * @param \HTMLPurifier_Context $context
     * @return array<array-key, mixed> 処理後の属性配列
     */
    public function transform($attr, $config, $context)
    {
        // 編集者が書いた生の allow / sandbox を保持してから、いったん除去する。
        $rawAllow = isset($attr['allow']) ? (string) $attr['allow'] : '';
        $rawSandbox = isset($attr['sandbox']) ? (string) $attr['sandbox'] : '';
        unset($attr['allow'], $attr['sandbox']);

        $src = isset($attr['src']) ? (string) $attr['src'] : '';
        if ($src === '') {
            // src が無い（＝非許可ホストで弾かれた／空 iframe）場合は capability を付与しない。
            return $attr;
        }

        $allow = $this->policy->resolveAllow($src, $rawAllow);
        if ($allow !== null) {
            $attr['allow'] = $allow;
        }

        $sandbox = $this->policy->resolveSandbox($src, $rawSandbox);
        if ($sandbox !== null) {
            $attr['sandbox'] = $sandbox;
        }

        return $attr;
    }
}
