<?php

declare(strict_types=1);

namespace Acms\Services\HtmlPurifier;

use HTMLPurifier_AttrTransform;

/**
 * iframe の権限付与系属性（allow / sandbox）を、ホストポリシー由来の固定値で付与する post-transform。
 *
 * allow / sandbox は宣言属性にしていないため、編集者が入力しても
 * 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 は採用しない（検証段階で削除済みだが防御的に除去）。
        unset($attr['allow'], $attr['sandbox']);

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

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

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

        return $attr;
    }
}
