<?php
declare(strict_types=1);

namespace WP_AUX\Services;

use WP_AUX\Entities\AuxCF\OptionsFields\Global\GlobalShareImageFieldEntity;
use WP_AUX\Entities\AuxCF\OptionsFields\PostType\PostTypeOptionsShareImageFieldEntity;
use WP_AUX\Entities\AuxCF\PageFields\Taxonomy\TaxonomySocialShareImageFieldEntity;

/**
 * Handles the enqueuing of scripts, styles, and fonts. Provides functionality
 * to load assets from both CDN and local sources with cache busting applied for local files.
 * @since 1.0.0
 */
class HeadService
{
  /**
   * Enqueue baseline AUX scripts, styles, and fonts
   * @since 1.0.0
   */
  public static function enqueueScripts(): void
  {
    $auxVersion = \WP_AUX::getAuxVersion();
    wp_enqueue_style(
      'aux-styles',
      "https://aux.tamu.edu/{$auxVersion}/styles/aux-styles.css",
      [],
      \WP_AUX::CACHE_CONTROL_VERSION,
      'all'
    );

    // Enqueue parent theme's main stylesheet
    wp_enqueue_style(
      'aux-parent-theme-style',
      get_parent_theme_file_uri('style.css'),
      ['aux-styles'],
      filemtime(get_parent_theme_file_path('style.css')),
      'all'
    );

    self::enqueueLocalStyle(
      'aux-print-styles',
      'css/aux-print-style.css',
      ['aux-parent-theme-style'],
      'print'
    );

    self::enqueueAuxScript(
      'aux-accordion',
      'aux-accordion.js',
      [],
      [
        'in_footer' => true,
        'strategy' => 'defer'
      ]
    );

    /**
     * Temporary local copy of aux-main-nav.js
     * The local version has a few differences from the CDN version.
     * USING THE CDN VERSION WILL BREAK THE MOBILE NAV.
     * We will switch to the CDN version once the new navigation that removes the jQuery dependency is released.
     */
    self::enqueueLocalScript(
      'aux-main-nav',
      'js/aux-main-nav.js',
      [],
      [
        'in_footer' => true,
        'strategy' => 'defer'
      ]
    );

    /**
     * Temporary local copy of aux-mobile-nav.js
     * The CDN version is using jQuery in standard mode, but WordPress uses jQuery in noConflict mode.
     * USING THE CDN VERSION WILL BREAK THE MOBILE NAV.
     * We will switch to the CDN version once the new navigation that removes the jQuery dependency is released.
     */
    self::enqueueLocalScript(
      'aux-mobile-nav',
      'js/aux-mobile-nav.js',
      ['jquery'],
      [
        'in_footer' => true,
        'strategy' => 'defer'
      ]
    );

    /**
     * aux-icons.js is used to load the AUX icons sprite sheet into the DOM.
     * It's a local script because it's not available on the AUX CDN.
     * Loaded in the footer to avoid blocking the main thread.
     */
    self::enqueueLocalScript(
      'aux-icons',
      'js/aux-icons.js',
      [],
      [
        'in_footer' => true,
        'strategy' => 'defer'
      ]
    );
  }

  /**
   * Enqueue or register AUX script from CDN
   * @since 1.0.0
   */
  public static function enqueueAuxScript(
    string $handle,
    string $scriptFile,
    array $dependencies = [],
    ?array $args = null,
    bool $registerOnly = false
  ): void
  {
    $auxVersion = \WP_AUX::getAuxVersion();

    $func = $registerOnly ? 'wp_register_script' : 'wp_enqueue_script';

    call_user_func_array($func, [
      $handle,
      "https://aux.tamu.edu/{$auxVersion}/js/{$scriptFile}",
      $dependencies,
      \WP_AUX::VERSION . '.' . $auxVersion,
      $args
    ]);
  }

  /**
   * Enqueue local stylesheet with cache busting
   * @since 1.0.0
   */
  public static function enqueueLocalStyle(
    string $handle,
    string $stylesheetFile,
    array $dependencies = [],
    string $media = 'all'
  ): void
  {
    $stylesheetUri = get_theme_file_uri($stylesheetFile);
    $stylesheetPath = get_theme_file_path($stylesheetFile);

    if (!$stylesheetPath || !file_exists($stylesheetPath)) {
      return;
    }

    $devVersion = filemtime($stylesheetPath);

    wp_enqueue_style(
      $handle,
      $stylesheetUri,
      $dependencies,
      $devVersion,
      $media
    );
  }

  /**
   * Enqueue local script with cache busting - automatically adds a version based on the file's last modified time.
   * @param string $handle      Name of the script. Should be unique.
   * @param string $scriptFile  Full URL of the script, or path of the script relative to the WordPress root directory.
   * @param array $dependencies An array of registered script handles this script depends on.
   * @param array|bool $args    {
   *     Optional. An array of additional script loading strategies. Default empty array.
   *     Otherwise, it may be a boolean in which case it determines whether the script is printed in the footer. Default false.
   *
   *     @type string    $strategy     Optional. If provided, may be either 'defer' or 'async'.
   *     @type bool      $in_footer    Optional. Whether to print the script in the footer. Default 'false'.
   * }
   * @return void
   * @since 1.0.0
   */
  public static function enqueueLocalScript(
    string $handle,
    string $scriptFile,
    array $dependencies = [],
    ?array $args = null
  ): void
  {
    $scriptUri = get_theme_file_uri($scriptFile);
    $scriptPath = get_theme_file_path($scriptFile);

    if (!$scriptPath || !file_exists($scriptPath)) {
      return;
    }

    // For cache busting - automatically adds a version based on the file's last modified time.
    $devVersion = filemtime($scriptPath);

    if (is_null($args)) {
      $args = ['strategy' => 'defer'];
    }

    wp_enqueue_script(
      $handle,
      $scriptUri,
      $dependencies,
      $devVersion,
      $args
    );
  }

  /**
   * Get the social share image for the current request
   *
   * If the request is for a single page or post, try to get the "featured image"
   * for the requested page or post.
   *
   * If the request is not for a single page or post, or there is no featured image
   * - If the request is for a single page or post, or for a post type archive,
   * try to get the "social share image" for the post type (under post type "Options" > "Archive")
   * - If the request is for a taxonomy, category, or other term, try to get the
   * social share image for that term (under term "Options" > "Archive")
   *
   * If no share image is defined from the above, get the social share image for
   * the entire site (under "Settings" > "AggieUX Site Settings" > "Site Settings").
   *
   * @since 1.0.0
   */
  public static function getShareImage(string $imageSize): array
  {
    $imageData = false;

    if (is_singular()) {
      $imageData = PostService::postImageData(null, $imageSize);
    }

    if (!$imageData) {
      $globalImageData = false;

      if (is_singular()) {
        $globalImageData = PostTypeService::getArchiveOption(
          get_post_type(),
          PostTypeOptionsShareImageFieldEntity::class
        );
      } elseif (is_post_type_archive()) {
        $globalImageData = PostTypeService::getArchiveOption(
          get_queried_object()->name,
          PostTypeOptionsShareImageFieldEntity::class
        );
      } elseif (is_tax() || is_category() || is_tag()) {
        $queriedObject = get_queried_object();

        if ($queriedObject instanceof \WP_Term) {
          $globalImageData = TaxonomyTermsService::getTermField(
            TaxonomySocialShareImageFieldEntity::$name,
            $queriedObject->term_id
          );
        }
      }

      if (!$globalImageData) {
        $globalImageData = get_field(GlobalShareImageFieldEntity::$name, 'option');
      }

      if ($globalImageData) {
        switch ($imageSize) {
          case 'full-screen-width':
            $imageData = [
              'src' => $globalImageData['url'],
              'alt' => $globalImageData['alt'],
              'width' => $globalImageData['width'],
              'height' => $globalImageData['height'],
            ];
            break;
          default:
            $imageData = [
              'src' => $globalImageData['sizes'][$imageSize],
              'alt' => $globalImageData['alt'],
              'width' => $globalImageData['sizes'][$imageSize . '-width'],
              'height' => $globalImageData['sizes'][$imageSize . '-height'],
            ];
        }
      }
    }

    return is_array($imageData) ? $imageData : [];
  }

  public static function getShareImages(): array
  {
    $images = [];

    foreach (['full-screen-width', 'large', 'medium', 'thumbnail'] as $imageSize) {
      $imageData = HeadService::getShareImage($imageSize);

      if ($imageData) {
        $images[$imageSize] = [
          'src' => $imageData['src'],
          'attr' => [
            'alt' => esc_attr($imageData['alt']),
            'width' => $imageData['width'],
            'height' => $imageData['height'],
          ],
        ];
      }
    }

    return $images;
  }
}
