<?php
declare(strict_types=1);

namespace WP_AUX\Entities\AuxFramework;

use WHOOP\Entities\Classlist;
use WP_AUX\Enum\BackgroundEnum;

/**
 * The ElementClassesEntity class is responsible for managing and generating CSS class lists for elements,
 * based on a set of base styles, optional background, modifiers, and additional classes.
 *
 * @since 1.0.0
 */
class ElementClassesEntity
{
  protected string $baseClass = '';
  protected ?string $style = '';
  protected ?BackgroundEnum $background = null;
  protected bool $dynamicBackground = false;
  protected array $modifiers = [];
  protected array $additionalClasses = [];

  public function __construct(string $baseClass, ?string $style = '') {
    $this->baseClass = $baseClass;
    $this->style = $style;
  }

  /**
   * Set the background
   *
   * If the background is a string, the matching background enum will be found and set.
   *
   * @since 1.0.0
   */
  public function setBackground(string|BackgroundEnum|null $background = '', bool $dynamicBackground = false): static
  {
    if ($background) {
      if (is_string($background)) {
        $background = BackgroundEnum::tryFrom($background);
      }

      if ($background) {
        $this->background = $background;
        $this->dynamicBackground = $dynamicBackground;
      }
    }

    return $this;
  }

  public function setDynamicBackground(string|BackgroundEnum|null $background): static
  {
    $this->setBackground($background, true);

    return $this;
  }

  /**
   * Add a modifier to the class
   *
   * Modifiers are rendered as {$this->baseClass}--{$modifier}
   *
   * @since 1.0.0
   */
  public function addModifier(string $modifier): static
  {
    $this->modifiers[] = $modifier;

    $this->modifiers = array_unique($this->modifiers);

    return $this;
  }

  /**
   * Add one modifier consisting of multiple strings
   *
   * This is useful for adding modifiers from an array variable that could be 'banner' or 'cta' or both as 'banner-cta'
   *
   * @since 1.0.0
   */
  public function addCompoundModifier(array $modifier): static
  {
    return $this->addModifier(join('-', $modifier));
  }

  /**
   * Add a simple, literal class to the classes list
   *
   * Where modifiers have the base class prepended to form an additional class name
   * in the classes string, classes added with addClass are added just as they are.
   *
   * @since 1.0.0
   */
  public function addClass(string $class): static
  {
    $this->additionalClasses[] = $class;
    return $this;
  }

  /**
   * Get if the current background is dark
   * @since 1.0.0
   */
  public function isDark(): bool
  {
    return $this->background ? $this->background->isDark() : false;
  }

  /**
   * Get if the current background is a divider
   * @since 1.0.0
   */
  public function hasDivider(): bool
  {
    return $this->background === BackgroundEnum::Divider;
  }

  /**
   * Add the background's class string to the classlist
   * @since 1.0.0
   */
  protected function addBackgroundClass(Classlist $classlist): void
  {
    if (!$this->background) {
      return;
    }

    $backgroundValue = $this->background->string();

    if (empty($backgroundValue)) {
      return;
    }

    if ($this->dynamicBackground && !$this->hasDivider()) {
      $backgroundValue = 'dynamic-' . $backgroundValue;
    }

    $classlist->addClass($this->baseClass . '--' . $backgroundValue);
  }

  /**
   * Get the classlist for the element
   * @since 1.0.0
   */
  public function getClasslist(): Classlist
  {
    $classlist = new Classlist($this->baseClass);

    if (!empty($this->style)) {
      $classlist->addClass($this->baseClass . '--' . $this->style);
    }

    $this->addBackgroundClass($classlist);

    if (!empty($this->modifiers)) {
      foreach ($this->modifiers as $modifier) {
        $classlist->addClass($this->baseClass . '--' . $modifier);
      }
    }

    if (!empty($this->additionalClasses)) {
      foreach ($this->additionalClasses as $class) {
        $classlist->addClass($class);
      }
    }

    return $classlist;
  }

  public function __toString(): string
  {
    $classList = $this->getClasslist();

    return $classList->getClassesString();
  }
}
