<?php
declare(strict_types=1);

namespace WP_AUX\Entities\AuxFramework\Partials;

use WHOOP\Entities\Element;
use WHOOP\Entities\Elements\A;
use WHOOP\Entities\Elements\Div;
use WHOOP\Entities\Elements\Img;
use WHOOP\Entities\Elements\Node;
use WP_AUX\Services\HtmlService;

/**
 * An image with essential image properties such as image data, link, size, URL, alt text, and wrapper.
 * @since 1.0.0
 */
class ImageEntity
{
  protected ?Img $img = null;
  protected ?array $imageData = [];
  protected ?string $size = null;
  protected ?string $url = null;
  protected ?string $alt = null;
  protected string|array|null $link = null;
  protected Element $wrapper;
  /**
   * @var callable[]
   */
  protected array $linkFilters = [];

  public function __construct(Img|string|array|null $image = null) {
    if ($image instanceof Img) {
      $this->img = $image;
    } elseif (is_array($image)) {
      $this->setImageData($image);
    } else {
      $this->url = $image;
    }

    $this->wrapper = Node::create();
  }

  /**
   * Set the image data as an array.
   *
   * If the image data contains a 'file' property, it's coming from an uploader.
   *
   * @since 1.0.0
   */
  public function setImageData(?array $imageData): self
  {
    if (isset($imageData['file'])) {
      $this->size = $imageData['size'] ?? 'large';
      $imageData = $imageData['file'];
    }

    if (!empty($imageData)) {
      $this->imageData = $imageData;
      $this->url = @$imageData['url'];
      $this->alt = @$imageData['alt'];
    }

    return $this;
  }

  /**
   * Set the thumbnail size as a string
   * @since 1.0.0
   */
  public function setSize(?string $size): self
  {
    $this->size = $size;
    return $this;
  }

  /**
   * Set the url (src) of the image
   * @since 1.0.0
   */
  public function setUrl(?string $url): self
  {
    $this->url = $url;
    return $this;
  }

  /**
   * Set the alt for the image
   * @since 1.0.0
   */
  public function setAlt(?string $alt): self
  {
    $this->alt = $alt;
    return $this;
  }

  /**
   * If the image should be a clickable link, set the link URL
   * @since 1.0.0
   */
  public function setLink(string|array|null $link): self
  {
    $this->link = $link;
    return $this;
  }

  /**
   * Set the wrapper for the image element
   * @since 1.0.0
   */
  public function wrap(string $wrapperClass) {
    $wrapper = Div::create();
    $wrapper->addClass($wrapperClass);

    $this->wrapper = $wrapper;

    return $this;
  }

  /**
   * Get the wrapper of the image element
   * @since 1.0.0
   */
  public function getWrapper(): Div
  {
    return $this->wrapper;
  }

  /**
   * Add filters that will be added to the link element before rendering
   * @since 1.0.0
   */
  public function addLinkFilter(string|callable $filter, ?callable $filterFunction = null): self
  {
    if (!is_null($filterFunction)) {
      $this->linkFilters[$filter] = $filterFunction;
    } else {
      $this->linkFilters[] = $filter;
    }

    return $this;
  }

  /**
   * Remove link filters by name
   * @since 1.0.0
   */
  public function removeLinkFilter(string $filter): self
  {
    if (isset($this->linkFilters[$filter])) {
      unset($this->linkFilters[$filter]);
    }

    return $this;
  }

  public function __toString(): string
  {
    if (!is_null($this->img)) {
      $image = $this->img;
    } else {
      $image = Img::create(null, [
        'src' => $this->url ?? @$this->imageData['src'],
        'alt' => $this->alt,
      ]);

      if ($this->imageData) {
        $srcset = false;

        if ($this->size && !empty($this->imageData['ID'])) {
          if ($imageSrc = wp_get_attachment_image_src( $this->imageData['ID'], $this->size )) {
            $image->setAttribute('src', $imageSrc[0]);
            $image->setAttribute('width', $imageSrc[1]);
            $image->setAttribute('height', $imageSrc[2]);
          }
        }

        if (isset($this->imageData['srcset'])) {
          $srcset = $this->imageData['srcset'];
        } elseif (isset($this->imageData['ID'])) {
          $srcset = wp_get_attachment_image_srcset($this->imageData['ID'], $this->size);
        }

        if (!empty($srcset)) {
          $image->setAttribute('srcset', $srcset);
        }
      }
    }

    $wrapper = clone $this->wrapper;

    if ($this->link) {
      if (is_array($this->link)) {
        $url = $this->link['url'];
      } else {
        $url = $this->link;
      }

      $link = HtmlService::link($image, $url);

      if ($this->linkFilters) {
        foreach ($this->linkFilters as $linkFilter) {
          call_user_func_array($linkFilter, [$link]);
        }
      }

      $wrapper->appendElement($link);
    } else {
      if (is_string($image)) {
        $wrapper->append($image);
      } else {
        $wrapper->appendElement($image);
      }
    }


    return (string) $wrapper;
  }

  public static function create(Img|string|array|null $image): static
  {
    $image = new static($image);

    return $image;
  }

  public function __clone() {
    $this->wrapper = clone $this->wrapper;
  }
}
