<?php

namespace Drupal\siteimprove_accessibility;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Routing\CurrentRouteMatch;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Language\LanguageDefault;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Url;

/**
 * Prepares Alfa Scan for rendering.
 */
class AlfaScanPreprocess {

  /**
   * Current user service.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected AccountProxyInterface $currentUser;

  /**
   * Language default service.
   *
   * @var \Drupal\Core\Language\LanguageDefault
   */
  protected LanguageDefault $languageDefault;

  /**
   * Language manager service.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected LanguageManagerInterface $languageManager;

  /**
   * Route match service.
   *
   * @var \Drupal\Core\Routing\CurrentRouteMatchInterface
   */
  protected CurrentRouteMatch $currentRouteMatch;

  /**
   * Configuration factory service.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected ConfigFactoryInterface $configFactory;

  /**
   * Constructs AlfaScanPreprocess service.
   */
  public function __construct(
    AccountProxyInterface $currentUser,
    LanguageDefault $languageDefault,
    LanguageManagerInterface $languageManager,
    CurrentRouteMatch $currentRouteMatch,
    ConfigFactoryInterface $configFactory,
  ) {
    $this->currentUser = $currentUser;
    $this->languageDefault = $languageDefault;
    $this->languageManager = $languageManager;
    $this->currentRouteMatch = $currentRouteMatch;
    $this->configFactory = $configFactory;
  }

  /**
   * Main method to build Alfa Scan panel.
   */
  public function buildPageBottom(array &$page_bottom): void {
    if (!$this->currentUser->hasPermission('run siteimprove_accessibility scan')
      || !$this->isLanguageMatch()) {
      return;
    }

    $route_name = $this->currentRouteMatch->getRouteName();
    $node = $this->getNodeFromRoute($route_name);
    if (!$node) {
      return;
    }

    $config = $this->configFactory->get('siteimprove_accessibility.settings');
    $preview_auto_scan = $config->get('preview_auto_scan');
    $enable_manual_scans = $config->get('enable_manual_scans');

    $page_bottom['siteimprove_accessibility'] = [
      '#theme' => 'alfa_scan_block',
      '#label' => 'Siteimprove Accessibility',
      '#cache' => ['max-age' => 0],
      '#isPreview' => $this->isPreview($route_name),
      '#previewAutoScan' => $preview_auto_scan,
      '#enableManualScans' => $enable_manual_scans,
    ];

    $page_bottom['siteimprove_accessibility']['#attached']['drupalSettings']['siteimprove_accessibility']['scannedNode'] = [
      'id' => $node?->id(),
      'uuid' => $node?->uuid(),
      'isPreview' => $this->isPreview($route_name),
      'previewAutoScan' => $preview_auto_scan,
      'enableManualScans' => $enable_manual_scans,
    ];

    $this->attachPendo($page_bottom);
  }

  /**
   * Checks if the current language matches the default.
   */
  private function isLanguageMatch(): bool {
    $default_language = $this->languageDefault->get();
    $current_language = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);
    return $default_language->getId() === $current_language->getId();
  }

  /**
   * Get the node object from the route if available.
   */
  private function getNodeFromRoute(string $route_name) {
    if ($route_name === 'entity.node.canonical') {
      return $this->currentRouteMatch->getParameter('node');
    }
    if ($route_name === 'entity.node.preview') {
      return $this->currentRouteMatch->getParameter('node_preview');
    }
    return NULL;
  }

  /**
   * Attach Pendo tracking script to the page.
   */
  public function attachPendo(array &$attachments): void {
    $config = $this->configFactory->get('siteimprove_accessibility.settings');
    if (!$config->get('pendo_tracking')) {
      return;
    }

    $user_data = [
      'id' => NULL,
    ];

    $base_url = Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString();
    $account_data = [
      'id' => 'Drupal_' . md5($base_url),
    ];

    $pendo_script = "
      (function(apiKey, userData, accountData){
        (function(p,e,n,d,o){p[o]=p[o]||function(){(p[o].q=p[o].q||[]).push(arguments)};
        var t=e.createElement(n),s=e.getElementsByTagName(n)[0];
        t.async=1;t.src=d; s.parentNode.insertBefore(t,s)})
        (window, document, 'script', 'https://cdn.pendo.io/agent/static/' + apiKey + '/pendo.js', 'pendo');

        window.addEventListener('load', function() {
          if (typeof pendo !== 'undefined') {
            pendo.initialize({
              apiKey: apiKey,
              visitor: userData,
              account: accountData,
              disableGuides: true,
            });
          } else {
            console.error('Pendo script not loaded.');
          }
        });
      })('730de0a8-013b-42b8-58b9-5c52d8158b20', " . Json::encode($user_data) . ", " . Json::encode($account_data) . ");
    ";

    $attachments['#attached']['html_head'][] = [
      [
        '#tag' => 'script',
        '#value' => $pendo_script,
      ],
      'pendo_tracking_script',
    ];
  }

  /**
   * Checks if node preview page.
   *
   * @param string $route_name
   *   Route name.
   *
   * @return bool
   *   True if page is in the preview mode.
   */
  private function isPreview(string $route_name): bool {
    return ($route_name === 'entity.node.preview');
  }

}
