<?php

namespace Google\Web_Stories_Dependencies\AmpProject\Optimizer\Transformer;

use Google\Web_Stories_Dependencies\AmpProject\Html\Attribute;
use Google\Web_Stories_Dependencies\AmpProject\Dom\Document;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\ErrorCollection;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Transformer;
use Google\Web_Stories_Dependencies\AmpProject\Html\Tag;
/**
 * AmpBoilerplateErrorHandler - adds amp-onerror handler to disable boilerplate early on runtime error.
 *
 * This ensures that the boilerplate does not hide the content for several seconds if an error occurred
 * while loading the AMP runtime that could already be detected much earlier.
 *
 * @package ampproject/amp-toolbox
 */
final class AmpBoilerplateErrorHandler implements Transformer
{
    /**
     * XPath query to find an AMP runtime script using ES6 modules.
     *
     * Note that substring() is used as ends-with() requires XPath 2.0, but PHP comes with XPath 1.0 support only.
     *
     * @var string
     */
    const AMP_MODULAR_RUNTIME_XPATH_QUERY = './script[substring(@src, string-length(@src) - 6) = \'/v0.mjs\']';
    /**
     * Error handler script to be added to the document's <head> for AMP pages not using ES modules.
     *
     * @var string
     */
    const ERROR_HANDLER_NOMODULE = 'document.querySelector("script[src*=\'/v0.js\']").onerror=function(){' . 'document.querySelector(\'style[amp-boilerplate]\').textContent=\'\'}';
    /**
     * Error handler script to be added to the document's <head> for AMP pages using ES modules.
     *
     * @var string
     */
    const ERROR_HANDLER_MODULE = '[].slice.call(document.querySelectorAll(' . '"script[src*=\'/v0.js\'],script[src*=\'/v0.mjs\']")).forEach(' . 'function(s){s.onerror=' . 'function(){' . 'document.querySelector(\'style[amp-boilerplate]\').textContent=\'\'' . '}})';
    /**
     * Apply transformations to the provided DOM document.
     *
     * @param Document        $document DOM document to apply the transformations to.
     * @param ErrorCollection $errors   Collection of errors that are collected during transformation.
     * @return void
     */
    public function transform(Document $document, ErrorCollection $errors)
    {
        if ($document->html->hasAttribute(Attribute::I_AMPHTML_NO_BOILERPLATE)) {
            // Boilerplate was removed, so no need for the amp-onerror handler.
            return;
        }
        $document->head->appendChild($document->createElementWithAttributes(Tag::SCRIPT, [Attribute::AMP_ONERROR => null], $this->usesModules($document) ? self::ERROR_HANDLER_MODULE : self::ERROR_HANDLER_NOMODULE));
    }
    /**
     * Check whether a provided document uses ES6 modules.
     *
     * @param Document $document Document to check.
     * @return bool Whether the provided document uses ES6 modules.
     */
    private function usesModules(Document $document)
    {
        $scripts = $document->xpath->query(self::AMP_MODULAR_RUNTIME_XPATH_QUERY, $document->head);
        return $scripts->length > 0;
    }
}
