<?php

namespace App\Services;

use App\Models\LandingPage;
use App\Models\LandingPageGeneration;
use App\Support\CatalogGoogleConversion;
use App\Support\CatalogMetaLeadEventName;
use App\Support\HtmlDocument;
use App\Support\PromptLandingPagePixels;
use DOMDocument;
use DOMElement;

class CatalogLandingPageTrackingDocument
{
    public function apply(LandingPage $page, ?string $utmSource): string
    {
        return $this->applyHtml($page, $page->renderedDocument(), $utmSource);
    }

    public function applyHtml(LandingPage $page, string $html, ?string $utmSource): string
    {
        $generation = $page->relationLoaded('generation')
            ? $page->generation
            : $page->generation()->first();

        if (! $generation instanceof LandingPageGeneration) {
            return $html;
        }

        $google = CatalogGoogleConversion::fromSendTo($generation->googleConversionSendTo());
        $metaPixelId = $generation->metaPixelId();
        $metaLeadEvent = CatalogMetaLeadEventName::fromBrand($generation->brand_name);

        return $this->injectIntoHtml(
            $html,
            $utmSource,
            $google,
            $metaPixelId,
            $metaLeadEvent,
        );
    }

    private function injectIntoHtml(
        string $html,
        ?string $utmSource,
        ?CatalogGoogleConversion $google,
        ?string $metaPixelId,
        string $metaLeadEvent,
    ): string {
        // Script bodies and SVG names survive this round trip; see HtmlDocument.
        if (! $document = HtmlDocument::from($html, 'catalog conversion tracking')) {
            return $html;
        }

        $dom = $document->dom();

        $provider = PromptLandingPagePixels::provider($utmSource);
        $injectGoogle = $provider === PromptLandingPagePixels::GOOGLE && $google instanceof CatalogGoogleConversion;
        $injectMeta = $provider === PromptLandingPagePixels::META && is_string($metaPixelId);

        if ($injectGoogle) {
            $this->injectGoogleTag($dom, $google);
        }

        if ($injectMeta) {
            $this->injectMetaPixel($dom, $metaPixelId);
        }

        if ($injectGoogle || $injectMeta) {
            $this->injectCtaTrackingScript($dom, $injectMeta ? $metaLeadEvent : null);
        }

        return $document->html();
    }

    private function injectGoogleTag(DOMDocument $dom, CatalogGoogleConversion $google): void
    {
        $accountId = $google->accountId;

        if (! 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"
            .'window.__admediaCatalogGoogle = '.json_encode($google->payload, JSON_UNESCAPED_SLASHES).";\n"
        ));
        $head->appendChild($inline);
    }

    private function injectMetaPixel(DOMDocument $dom, string $pixelId): void
    {
        if (! PromptLandingPagePixels::isMetaPixelId($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 injectCtaTrackingScript(DOMDocument $dom, ?string $metaLeadEvent): void
    {
        $metaSetup = '';

        if (is_string($metaLeadEvent) && $metaLeadEvent !== '') {
            $metaLeadEventJson = json_encode($metaLeadEvent, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);

            if (is_string($metaLeadEventJson)) {
                $metaSetup = "  window.__admediaCatalogMetaLead = {$metaLeadEventJson};\n";
            }
        }

        $script = $dom->createElement('script');
        $script->appendChild($dom->createTextNode(
            "(function () {\n"
            .$metaSetup
            .<<<'JS'
  function isCatalogProductCta(link) {
    if (!link || !link.getAttribute) {
      return false;
    }

    if (link.closest('header.topbar a.brand, header .logo, .topbar .brand')) {
      return false;
    }

    if (link.matches('[class*="cta"], [class*="row-cta"], .row-overlay-link, .row-thumb-link')) {
      return true;
    }

    return !!link.closest('.product-row, .product-card, .product-rows, #products, section[id*="product"], article');
  }

  document.addEventListener('click', function (event) {
    var link = event.target.closest('a[href^="http"]');
    if (!isCatalogProductCta(link)) {
      return;
    }

    if (window.__admediaCatalogGoogle && typeof gtag === 'function') {
      gtag('event', 'conversion', window.__admediaCatalogGoogle);
    }

    if (window.__admediaCatalogMetaLead && typeof fbq === 'function') {
      fbq('trackCustom', window.__admediaCatalogMetaLead);
    }
  }, true);
})();
JS
        ));

        $bodies = $dom->getElementsByTagName('body');

        if ($bodies->length > 0) {
            $bodies->item(0)?->appendChild($script);
        } else {
            $dom->appendChild($script);
        }
    }

    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;
    }
}
