<?php
declare(strict_types=1);

namespace WP_AUX\Entities;

use WP_AUX\Services\HeadService;

/**
 * The theme entity handles theme-specific configurations and settings, and
 * provides for changing these theme settings in the child theme before settings
 * are made - or must be prevented from being made - by the parent theme.
 *
 * @since 1.0.0
 */
class ThemeEntity
{
  // This theme.json has the latest version number for the parent theme. It's updated automatically through a Github action when a new version is released is released.
  public const PARENT_VERSION_CONTROL_URL = 'https://aux.tamu.edu/wordpress/theme.json';
  public const THEME_FOLDER = 'aux-wordpress';

  protected string $identifier = '';
  protected bool $isUniversity = false;

  protected array $supports = [];
  protected array $menus = [];
  protected string $childVersionControlUrl = '';
  protected string $childThemeFolder = '';
  protected ?int $contentWidth = null;
  protected string $permalinkPattern = '/%year%/%monthnum%/%day%/%postname%/';
  protected int $mainNavDepth = 2;

  public function __construct() {
    if (is_child_theme()) {
      $this->childThemeFolder = basename( get_stylesheet_directory() );
    }
  }

  /**
   * Is the current theme for a university-level site
   * @since 1.0.0
   */
  public function getIsUniversity(): bool
  {
    return $this->isUniversity;
  }

  /**
   * Set if the theme is for a university-level site
   * @since 1.0.0
   */
  public function setIsUniversity(bool $isUniversity): self
  {
    $this->isUniversity = $isUniversity;
    return $this;
  }

  /**
   * Unique identifier for the current theme
   * @since 1.0.0
   */
  public function getIdentifier(): string
  {
    return $this->identifier;
  }

  /**
   * Set unique identifier for the current theme
   * @since 1.0.0
   */
  public function setIdentifier(string $identifier): self
  {
    $this->identifier = $identifier;
    return $this;
  }

  /**
   * Pattern for permalink URLs
   * @since 1.0.0
   */
  public function getPermalinkPattern(): string
  {
    return $this->permalinkPattern;
  }

  /**
   * Set the attern for permalink URLs
   * @since 1.0.0
   */
  public function setPermalinkPattern(string $permalinkPattern): self
  {
    $this->permalinkPattern = $permalinkPattern;
    return $this;
  }

  /**
   * Get the maximum depth of the main navigation menu
   * @since 1.0.0
   */
  public function getMainNavDepth(): int
  {
    return $this->mainNavDepth;
  }

  /**
   * Add a nav menu to be registered for the template
   *
   * @since 1.0.0
   * @see register_nav_menu()
   */
  public function addMenu(string $menuHandle, string $menuTitle): static
  {
    $this->menus[$menuHandle] = $menuTitle;
    return $this;
  }

  /**
   * Remove a nav menu before it is registered
   *
   * @since 1.0.0
   */
  public function removeMenu(string $menuHandle): static
  {
    if (isset($this->menus[$menuHandle])) {
      unset($this->menus[$menuHandle]);
    }

    return $this;
  }

  /**
   * Set dynamic version control URL (for use with child themes)
   *
   * @since 1.0.0
   */
  public function setChildVersionControlUrl(string $childVersionControlUrl): self
  {
    $this->childVersionControlUrl = $childVersionControlUrl;
    return $this;
  }

  /**
   * Let WordPress manage the document title.
   *
   * By adding theme support, we declare that this theme does not use a
   * hard-coded <title> tag in the document head, and expect WordPress to
   * provide it for us.
   *
   * @since 1.0.0
   */
  public function supportTitleTag(bool $addSupport = true): static
  {
    if ($addSupport) {
      $this->addThemeSupport('title-tag');
    } else {
      $this->removeThemeSupport('title-tag');
    }

    return $this;
  }

  /**
   * Add default posts and comments RSS feed links to head.
   *
   * @since 1.0.0
   */
  public function supportAutomaticFeedLinks(bool $addSupport = true): static
  {
    if ($addSupport) {
      $this->addThemeSupport('automatic-feed-links');
    } else {
      $this->removeThemeSupport('automatic-feed-links');
    }

    return $this;
  }

  /**
   * Enable support for Post Thumbnails on posts and pages.
   *
   * @link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/
   * @since 1.0.0
   */
  public function supportPostThumbnails(bool $addSupport = true): static
  {
    if ($addSupport) {
      $this->addThemeSupport('post-thumbnails');
    } else {
      $this->removeThemeSupport('post-thumbnails');
    }

    return $this;
  }

  /**
   * Support default core markup for search form, comment form, and comments
   * to output valid HTML5.
   *
   * @since 1.0.0
   */
  public function supportHtml5(bool $addSupport = true): static
  {
    if ($addSupport) {
      $this->addThemeSupport('html5', [
        "search-form",
        "comment-form",
        "comment-list",
        "gallery",
        "caption",
        "style",
        "script",
      ]);
    } else {
      $this->removeThemeSupport('html5');
    }

    return $this;
  }

  /**
   * Add theme support for selective refresh for widgets.
   *
   * @since 1.0.0
   */
  public function supportCustomizeSelectiveRefreshWidgets(bool $addSupport = true): static
  {
    if ($addSupport) {
      $this->addThemeSupport('customize-selective-refresh-widgets');
    } else {
      $this->removeThemeSupport('customize-selective-refresh-widgets');
    }

    return $this;
  }

  /**
   * Register wordpress theme feature support
   *
   * @since 1.0.0
   * @see add_theme_support()
   */
  public function addThemeSupport(string $supportKey, ...$args): static
  {
    $this->supports[$supportKey] = $args;

    return $this;
  }

  /**
   * Remove wordpress theme feature support before it is registered
   *
   * @since 1.0.0
   */
  public function removeThemeSupport(string $supportKey): static
  {
    if (isset($this->supports[$supportKey])) {
      unset($this->supports[$supportKey]);
    }

    return $this;
  }

  /**
   * Register all theme supports and nav menus with Wordpress
   *
   * @since 1.0.0
   * @uses add_theme_support()
   * @uses register_nav_menus()
   * @uses WP_Theme::load_textdomain()
   */
  public function setup(): void
  {
    $wpTheme = wp_get_theme();
    $wpTheme->load_textdomain();

    foreach ($this->supports as $supportKey => $supportArgs) {
      $allArgs = $supportArgs;
      array_unshift($allArgs, $supportKey);

      call_user_func_array('add_theme_support', $allArgs);
    }

    if (!empty($this->menus)) {
      register_nav_menus($this->menus);
    }
  }

  /**
   * Initialize theme-specific functionality
   *
   * Enqueues child theme stylesheet if this is a child theme.
   * The parent theme's style.css is loaded by HeadService::enqueueScripts() on wp_enqueue_scripts.
   * Child style is enqueued on the same hook with priority 20 so aux-parent-theme-style is registered first.
   *
   * @since 1.0.0
   * @uses HeadService::enqueueLocalStyle()
   * @uses is_child_theme()
   */
  public function init(): void
  {
    if (is_child_theme()) {
      add_action('wp_enqueue_scripts', [$this, 'enqueueChildThemeStyle'], 20);
    }

    register_nav_menus(
      [
        'aux-header-utility-ctas' => 'AUX Utility Nav CTAs',
        'aux-header-utility-persona' => 'AUX Utility Nav Persona',
        'aux-header-utility-quicklinks' => 'AUX Utility Nav Quicklinks',
      ]
    );
  }

  /**
   * Enqueue the child theme stylesheet with parent theme style as dependency.
   *
   * Runs on wp_enqueue_scripts priority 20 so aux-parent-theme-style is already
   * registered by HeadService::enqueueScripts() (priority 10).
   *
   * @since 1.0.0
   */
  public function enqueueChildThemeStyle(): void
  {
    HeadService::enqueueLocalStyle(
      'aux-child-style',
      'style.css',
      ['aux-parent-theme-style'],
      'all'
    );
  }

  /**
   * Check for theme updates
   *
   * If the active theme is a child theme, also check the child theme for updates
   *
   * Plugin update checker code from https://github.com/YahnisElsts/plugin-update-checker
   *
   * @since 1.0.0
   * @uses \YahnisElsts\PluginUpdateChecker\v5\PucFactory::buildUpdateChecker()
   */
  public function checkVersions(): void
  {
    // parse_url() only needs a valid URL format to parse the host component, so 'http://' will work even for HTTPS sites since we're only extracting the hostname.
    $host_parts = explode(".", parse_url('http://' . $_SERVER['SERVER_NAME'], PHP_URL_HOST));
    $tld = end($host_parts);

    /**
     * If developing locally, don't check for updates
     */
    if ('local' === $tld) {
      return;
    }

    require_once get_parent_theme_file_path('plugin-update-checker/plugin-update-checker.php');

    \YahnisElsts\PluginUpdateChecker\v5\PucFactory::buildUpdateChecker(
      self::PARENT_VERSION_CONTROL_URL,
      get_parent_theme_file_path('style.css'),
      self::THEME_FOLDER
    );

    if ($this->childThemeFolder && $this->childVersionControlUrl) {
      \YahnisElsts\PluginUpdateChecker\v5\PucFactory::buildUpdateChecker(
        $this->childVersionControlUrl,
        get_theme_file_path('style.css'),
        $this->childThemeFolder
      );
    }
  }
}
