<?php
declare(strict_types=1);

namespace WP_AUX\Services;

use WHOOP\Entities\Elements\A;
use WHOOP\Entities\Elements\Img;
use WP_AUX\Entities\AuxFramework\Partials\CardEntity;
use WP_AUX\Services\AuxFramework\PageComponentsService;

/**
 * Utilities for working with posts
 * @since 1.0.0
 */
class PostService
{
  /**
   * Get the anchor link for a post.
   *
   * Target and external class are added for links to a different host.
   *
   * @since 1.0.0
   */
  public static function postLink(
    int|\WP_Post|null $post = null,
    ?string $content = null,
    array $attr = []
  ): A
  {
    if (is_null($content)) {
      $content = get_the_title($post);
    }

    $link = HtmlService::link($content, get_post_permalink($post), false);

    if ($attr) {
      $link->setAttributes($attr);
    }

    return $link;
  }

  /**
   * Get an array of image data for a post's featured image
   * @since 1.0.0
   */
  public static function postImageData(
    int|\WP_Post|null $post = null,
    $size = 'post-thumbnail',
    bool $includeDetails = false
  ): ?array
  {
    $attachmentId = get_post_thumbnail_id( $post );
    $image = image_downsize( $attachmentId, $size );

    if (!$image) {
      return null;
    }

    $imageData = [
      'src' => $image[0],
      'width' => $image[1],
      'height' => $image[2],
      'alt' => get_post_meta($attachmentId, '_wp_attachment_image_alt', true),
      'srcset' => wp_get_attachment_image_srcset( $attachmentId, $size),
    ];

    if ($includeDetails) {
      $metadata = wp_get_attachment_metadata($attachmentId);

      if (isset($metadata['sizes'][$size])) {
        if (isset($metadata['sizes'][$size]['filesize'])) {
          $imageData['filesize'] = $metadata['sizes'][$size]['filesize'];
        }

        if (isset($metadata['sizes'][$size]['mime-type'])) {
          $imageData['mime-type'] = $metadata['sizes'][$size]['mime-type'];
        }
      }
    }

    return $imageData;
  }

  /**
   * Get an image element object with attributes for a post featured image at specified size
   * @since 1.0.0
   */
  public static function postImage(int|\WP_Post|null $post = null, $size = 'post-thumbnail'): ?Img
  {
    $imageData = self::postImageData($post, $size);

    if (!$imageData) {
      return null;
    }

    return Img::create(null, $imageData);
  }

  /**
   * Get the requested post before it is available in standard Wordpress flow
   * @since 1.0.0
   */
  public static function getRequestedPost(): ?\WP_Post
  {
    $requestedUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 'https' : 'http') .
      '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];

    $postId = url_to_postid($requestedUrl);

    return get_post($postId);
  }

  /**
   * Get the requested post type before it is available in standard Wordpress flow
   * @since 1.0.0
   */
  public static function isRequestedPostType(string $postType): bool
  {
    if (is_admin()) {
      return AdminService::isPostTypeEditor($postType);
    }

    $requestedPost = self::getRequestedPost();

    if ($requestedPost && $postType === $requestedPost->post_type) {
      return true;
    }

    return false;
  }

  /**
   * Get the requested label field for the post type
   * @since 1.0.0
   */
  public static function getPostTypeLabel(string $postType, string $labelKey = 'name'): ?string
  {
    $labels = get_post_type_labels(get_post_type_object($postType));

    return @$labels->{$labelKey};
  }

  /**
   * Get the requested post type label field for the post
   * @since 1.0.0
   */
  public static function getTypeLabelForPost(\WP_Post|int|string|null $post = null, string $labelKey = 'name'): ?string
  {
    if (is_string($post)) {
      $postType = $post;
    } elseif ($post instanceof \WP_Post) {
      $postType = $post->post_type;
    } else {
      $post = get_post($post);
      $postType = $post->post_type;
    }

    if (!$postType) {
      return null;
    }

    return self::getPostTypeLabel($postType, $labelKey);
  }

  /**
   * Calculate the page read time for a post
   * @since 1.0.0
   */
  public static function pageReadTime(int|\WP_Post|null $post = null, $format = '%time %action'): string
  {
    $content = get_the_content(null, false, $post);

    $wordCount = str_word_count(strip_tags($content));
    $minutes = ceil($wordCount / 200);

    if ($minutes < 1) {
      $minutes = '< 1';
    }

    return strtr($format, [
      '%time' => $minutes . ' min.',
      '%action' => 'read',
    ]);
  }

  /**
   * Get an AUX card object for a post
   * @since 1.0.0
   */
  public static function postCard(
    int|\WP_Post|null $post,
    bool $includeImage = true,
    bool $includeCategories = false,
    bool $hasIntro = false
  ): CardEntity {
    $card = CardEntity::create(
      get_the_title($post),
      get_the_excerpt($post)
    )
      ->setCta(get_the_permalink($post))
      ->setHasIntro($hasIntro);

    if ($includeCategories) {
      $card->setHeaderPrepend((string) PageComponentsService::getCategoriesTagsCollection($post));
    }

    if ($includeImage) {
      $card->setImage(PostService::postImage($post));
    }

    return $card;
  }

  /**
   * Get a search result AUX card for a post
   * @since 1.0.0
   */
  public static function searchResultCard(
    bool $includeImage = false,
    bool $includeCategories = false,
    bool $hasIntro = false
  ): CardEntity
  {
    $post = get_post();

    $card = self::postCard(null, $includeImage, $includeCategories, $hasIntro)
      ->addStyle('inline', 'inline-feed')
      ->addClass('search-result', 'search-result-' . get_post_type($post))
      ->setId('post-' . $post->ID)
      ->setCta([
        'url' => get_the_permalink($post),
        'rel' => 'bookmark'
      ]);

    apply_filters('aux/search_result_card', $card, $post);

    return $card;
  }

  /**
   * Register Wordpress actions and hooks related to posts
   * @since 1.0.0
   */
  public static function prepareHooks(): void
  {
    /**
     * Add excerpt support to page post type
     */
    add_action('after_setup_theme', function() {
      add_post_type_support('page', 'excerpt');
    });

    /**
     * Do not auto-generate excerpts from post content
     */
    add_filter( 'get_the_excerpt', function ( $excerpt, \WP_Post $post ) {
      return has_excerpt($post) ? $excerpt : '';
    }, 10, 2);
  }
}
