<?php

namespace DaftPlug\Generatify\Features\SmartSuggestions;

use DaftPlug\Generatify\Helpers\Utils;

if (!defined('ABSPATH')) {
  exit();
}

class RelatedPosts
{
  public function __construct()
  {
    add_action('wp_enqueue_scripts', [$this, 'loadRelatedPostsAssets']);
  }

  public function loadRelatedPostsAssets()
  {
    if (Utils::getSetting('aiRelatedPosts') !== 'on') {
      return;
    }

    wp_enqueue_script('generatify-related-posts', plugins_url('assets/js/relatedPosts.js', GENERATIFY_FILE), [], GENERATIFY_VERSION, true);
    wp_localize_script('generatify-related-posts', 'generatify_related_posts_js_vars', [
      'pluginDirUrl' => GENERATIFY_DIR_URL,
      'relatedPosts' => $this->getRelatedPosts(),
      'aiRelatedPostsSettings' => [
        'title' => Utils::getSetting('aiRelatedPostsTitle'),
        'description' => Utils::getSetting('aiRelatedPostsDescription'),
        'quantity' => Utils::getSetting('aiRelatedPostsQuantity'),
      ],
    ]);
  }

  /**
   * Render the custom element for related posts
   * Only appends if there are related posts
   *
   * @param string $content The post content
   * @return string The content with the related posts element appended
   */
  public function appendRelatedPostsToContent($content)
  {
    // Skip if the setting is disabled
    if (Utils::getSetting('aiRelatedPosts') !== 'on') {
      return $content;
    }

    // Check if this is a single post in the main query
    if (!is_singular() || !in_the_loop() || is_admin()) {
      return $content;
    }

    $post_id = get_the_ID();
    if (!$post_id) {
      return $content;
    }

    $relatedPosts = $this->getRelatedPostsData($post_id);

    // Only append custom element if there are related posts
    if (!empty($relatedPosts)) {
      $content .= "\n" . '<generatify-related-posts></generatify-related-posts>' . "\n";
    }

    return $content;
  }

  /**
   * Retrieve related posts data formatted for frontend
   *
   * @return array Array of related posts with id, title, excerpt, permalink, and thumbnail URL
   */
  public function getRelatedPostsData($post_id)
  {
    // Build query args for related posts
    $desiredQuantity = (int) (Utils::getSetting('aiRelatedPostsQuantity') ?: 3);

    // Fetch a bit more than needed to allow PHP-side exclusions while keeping cacheable args.
    // Cap to a sane upper bound to avoid large queries; keep mostly fixed for better cache hit rate.
    $requestLimit = min(max($desiredQuantity + 5, 10), 20);

    $relatedArgs = [
      'post_type' => get_post_type($post_id),
      'posts_per_page' => $requestLimit,
      'post_status' => 'publish',
      // Avoid exclusionary parameters like post__not_in for better cache hit rate.
      // 'post__not_in' => [$post_id],
      'orderby' => 'date', // deterministic and cache-friendly compared to RAND
      'order' => 'DESC',
      'ignore_sticky_posts' => true,
      'no_found_rows' => true,
    ];

    // Get current post
    $post = get_post($post_id);
    if (!$post) {
      return [];
    }

    // Collect category & tag IDs (built-in taxonomies) to avoid tax_query which can trigger slow DB warnings.
    // Using category__in and tag__in is generally more performant and avoids complex tax queries.
    $categoryIds = [];
    $tagIds = [];

    if (is_object_in_taxonomy($post->post_type, 'category')) {
      $categoryIds = wp_get_post_categories($post_id, ['fields' => 'ids']);
    }
    if (is_object_in_taxonomy($post->post_type, 'post_tag')) {
      $tagIds = wp_get_post_tags($post_id, ['fields' => 'ids']);
    }

    // Only add filters if we actually have term IDs; otherwise return early (no meaningful related posts criteria)
    if (!empty($categoryIds)) {
      $relatedArgs['category__in'] = $categoryIds;
    }
    if (!empty($tagIds)) {
      $relatedArgs['tag__in'] = $tagIds;
    }

    // If we have neither categories nor tags, avoid issuing a broad query that would be low-quality & costly.
    if (empty($categoryIds) && empty($tagIds)) {
      return [];
    }

    // Query related posts
    $query = new \WP_Query($relatedArgs);

    // Format the related posts data
    $relatedPosts = [];

    if ($query->have_posts()) {
      while ($query->have_posts()) {
        $query->the_post();
        $related_post_id = get_the_ID();

        // Skip current post without using post__not_in, per VIP performance guidance
        if ((int) $related_post_id === (int) $post_id) {
          continue;
        }

        // Get post content and truncate to 100 characters
        // Use direct field read to avoid running heavy content filters in this context
        $post_content = get_post_field('post_content', $related_post_id);
        $post_content = wp_strip_all_tags($post_content);
        $post_excerpt = substr($post_content, 0, 100);

        // Add ellipsis if content is longer than 100 chars
        if (strlen($post_content) > 100) {
          $post_excerpt .= '...';
        }

        // Get thumbnail URL if it exists
        $thumbnail_url = '';
        if (has_post_thumbnail($related_post_id)) {
          $thumbnail_url = get_the_post_thumbnail_url($related_post_id, 'medium');
        }

        $relatedPosts[] = [
          'id' => $related_post_id,
          'title' => get_the_title($related_post_id),
          'excerpt' => $post_excerpt,
          'permalink' => get_the_permalink($related_post_id),
          'thumbnail' => $thumbnail_url,
        ];

        // Stop when we've collected the desired quantity
        if (count($relatedPosts) >= $desiredQuantity) {
          break;
        }
      }

      // Reset post data
      wp_reset_postdata();
    }

    return $relatedPosts;
  }

  /**
   * Get related posts data for frontend JavaScript variables
   */
  public function getRelatedPosts()
  {
    // Skip if the setting is disabled
    if (Utils::getSetting('aiRelatedPosts') !== 'on') {
      return [];
    }

    // Check if this is a single post
    if (!is_single()) {
      return [];
    }

    $post_id = get_the_ID();
    if (!$post_id) {
      return [];
    }

    $relatedPosts = $this->getRelatedPostsData($post_id);

    // Only add to frontend vars if there are related posts
    if (!empty($relatedPosts)) {
      return $relatedPosts;
    }

    return [];
  }
}
