<?php

namespace App\Services;

use App\Support\HtmlDocument;
use App\Support\PromptLandingPagePixels;
use DOMDocument;
use DOMElement;

class LandingPagePixelInjector
{
    public function injectIntoHtml(
        string $html,
        ?string $utmSource,
        ?string $googleSendTo,
        ?string $metaPixelId,
    ): string {
        // Script bodies and SVG names survive this round trip; see HtmlDocument.
        if (! $document = HtmlDocument::from($html, 'landing page pixel injection')) {
            return $html;
        }

        $dom = $document->dom();

        $this->injectIntoDocument($dom, $utmSource, $googleSendTo, $metaPixelId);

        return $document->html();
    }

    public function injectIntoDocument(
        DOMDocument $dom,
        ?string $utmSource,
        ?string $googleSendTo,
        ?string $metaPixelId,
    ): void {
        $this->injectPixels($dom, $utmSource, $googleSendTo, $metaPixelId);
    }

    private function injectPixels(
        DOMDocument $dom,
        ?string $utmSource,
        ?string $googleSendTo,
        ?string $metaPixelId,
    ): void {
        $provider = PromptLandingPagePixels::provider($utmSource);

        if ($provider === PromptLandingPagePixels::GOOGLE) {
            if (is_string($googleSendTo) && PromptLandingPagePixels::isGoogleSendTo($googleSendTo)) {
                $this->injectGooglePixel($dom, $googleSendTo);
            }

            return;
        }

        if ($provider === PromptLandingPagePixels::META) {
            if (is_string($metaPixelId) && PromptLandingPagePixels::isMetaPixelId($metaPixelId)) {
                $this->injectMetaPixel($dom, $metaPixelId);
            }
        }
    }

    private function injectGooglePixel(DOMDocument $dom, string $sendTo): void
    {
        if (! PromptLandingPagePixels::isSafeId($sendTo)) {
            return;
        }

        $accountId = PromptLandingPagePixels::googleAccountId($sendTo);

        if ($accountId === null || ! PromptLandingPagePixels::isSafeId($accountId)) {
            return;
        }

        $head = $this->head($dom);

        $loader = $dom->createElement('script');
        $loader->setAttribute('async', 'async');
        $loader->setAttribute('src', 'https://www.googletagmanager.com/gtag/js?id='.$accountId);
        $head->appendChild($loader);

        $inline = $dom->createElement('script');
        $inline->appendChild($dom->createTextNode(
            "window.dataLayer = window.dataLayer || [];\n"
            ."function gtag(){dataLayer.push(arguments);}\n"
            ."gtag('js', new Date());\n"
            ."gtag('config', '{$accountId}');\n"
            ."function gtag_report_conversion(url) {\n"
            ."  var callback = function () {\n"
            ."    if (typeof(url) != 'undefined') {\n"
            ."      window.location = url;\n"
            ."    }\n"
            ."  };\n"
            ."  gtag('event', 'conversion', {\n"
            ."      'send_to': '{$sendTo}',\n"
            ."      'value': '1.0',\n"
            ."      'currency': 'USD',\n"
            ."      'event_callback': callback\n"
            ."  });\n"
            ."  return false;\n"
            ."}\n"
        ));
        $head->appendChild($inline);
    }

    private function injectMetaPixel(DOMDocument $dom, string $pixelId): void
    {
        if (! PromptLandingPagePixels::isSafeId($pixelId)) {
            return;
        }

        $head = $this->head($dom);

        $inline = $dom->createElement('script');
        $inline->appendChild($dom->createTextNode(
            "!function(f,b,e,v,n,t,s)\n"
            ."{if(f.fbq)return;n=f.fbq=function(){n.callMethod?\n"
            ."n.callMethod.apply(n,arguments):n.queue.push(arguments)};\n"
            ."if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';\n"
            ."n.queue=[];t=b.createElement(e);t.async=!0;\n"
            ."t.src=v;s=b.getElementsByTagName(e)[0];\n"
            ."s.parentNode.insertBefore(t,s)}(window, document,'script',\n"
            ."'https://connect.facebook.net/en_US/fbevents.js');\n"
            ."fbq('init', '{$pixelId}');\n"
            ."fbq('track', 'PageView');\n"
        ));
        $head->appendChild($inline);

        $noscript = $dom->createElement('noscript');
        $img = $dom->createElement('img');
        $img->setAttribute('height', '1');
        $img->setAttribute('width', '1');
        $img->setAttribute('style', 'display:none');
        $img->setAttribute('src', 'https://www.facebook.com/tr?id='.$pixelId.'&ev=PageView&noscript=1');
        $noscript->appendChild($img);
        $head->appendChild($noscript);
    }

    private function head(DOMDocument $dom): DOMElement
    {
        $heads = $dom->getElementsByTagName('head');
        $existing = $heads->item(0);

        if ($existing instanceof DOMElement) {
            return $existing;
        }

        $head = $dom->createElement('head');
        $htmls = $dom->getElementsByTagName('html');
        $html = $htmls->item(0);

        if ($html instanceof DOMElement) {
            $html->insertBefore($head, $html->firstChild);
        } else {
            $dom->appendChild($head);
        }

        return $head;
    }
}
