<?php

namespace ModernFields\FieldGroups\Factories;

use ModernFields\FieldGroups\Entities\Post;
use ModernFields\FieldGroups\Repositories\UserRepository;

/**
 * Builds WordPress query arguments for retrieving field groups based on post locations.
 *
 * This builder prepares query arguments that filter field groups by location, scope and targets
 * 
 * @since 1.0.0
 */
class PostQueryFactory extends QueryFactory
{
  /**
   * Constructor
   * 
   * @since 1.0.0
   * @param Post $post The post entity used to determine field group locations
   */
  public function __construct(
    protected Post $post,
  ) {}

  /**
   * Prepares WordPress query arguments for retrieving field groups.
   *
   * Combines the provided meta query with base meta queries for location type
   * and user roles. The resulting array can be used with WordPress query functions
   * like `get_posts()` or `WP_Query`.
   * 
   * @since 1.0.0
   *
   * @param array $additional_meta_args Additional meta query conditions to merge with meta query arguments
   * @return array WordPress query arguments array
   */
  protected function prepareArgs(array $additional_meta_args): array
  {
    $post_type = $this->post->getPostType();
    $post_type_obj = get_post_type_object($post_type);
    $is_builtin = $post_type_obj && $post_type_obj->_builtin;

    if (!$is_builtin) {
      $location_meta_query = [
        [
          'key' => 'mf_location',
          'value' => 'custom-post-type',
          'compare' => '='
        ],
        [
          'key' => 'mf_cpt',
          'value' => $post_type,
          'compare' => '='
        ]
      ];
    } else {
      $location_meta_query = [
        [
          'key' => 'mf_location',
          'value' => $post_type,
          'compare' => 'IN'
        ]
      ];
    }

    $current_user = UserRepository::getCurrentLoggedInUser();

    $base_meta_query = [
      'relation' => 'AND',
      [
        'key' => 'mf_roles',
        'value' => $current_user->getRoles(),
        'compare' => 'IN'
      ],
    ];

    $query = array_merge($base_meta_query, $location_meta_query, $additional_meta_args);

    return [
      'post_type' => MODERN_FIELDS_CPT_SLUG,
      'post_status' => 'publish',
      'posts_per_page' => -1,
      'meta_query' => $query,
    ];
  }

  /**
   * Builds query arguments for field groups with 'all' scope.
   *
   * Returns field groups that apply to all posts of the current post type.
   * 
   * @since 1.0.0
   * @return self
   */
  public function getAllPostsQuery(): self
  {
    $query = $this->prepareArgs([
      [
        'key' => 'mf_scope',
        'value' => 'all',
        'compare' => '='
      ]
    ]);

    return $this->addQuery($query);
  }

  /**
   * Builds query arguments for field groups targeting specific posts.
   *
   * Returns field groups that are configured to apply to the current post by ID.
   * 
   * @since 1.0.0
   * @return self
   */
  public function getSpecificPostsQuery(): self
  {
    $query = $this->prepareArgs([
      [
        'key' => 'mf_scope',
        'value' => ['post', 'page'],
        'compare' => 'IN'
      ],
      [
        'key' => 'mf_targets',
        'value' => (string) $this->post->getId(),
        'compare' => '='
      ]
    ]);

    return $this->addQuery($query);
  }

  /**
   * Builds query arguments for field groups targeting page templates.
   *
   * Returns field groups configured for the current post's page template.
   * Returns null if the post doesn't have a custom template assigned.
   * 
   * @since 1.0.0
   * @return self
   */
  public function getTemplateQuery(): self
  {
    $template_slug = get_page_template_slug($this->post->getId());

    if (!$template_slug) {
      return $this;
    }

    $query = $this->prepareArgs([
      [
        'key' => 'mf_scope',
        'value' => 'template',
        'compare' => '='
      ],
      [
        'key' => 'mf_targets',
        'value' => $template_slug,
        'compare' => '='
      ]
    ]);

    return $this->addQuery($query);
  }

  /**
   * Builds query arguments for field groups targeting the homepage.
   *
   * Returns field groups configured for the static homepage.
   * Returns null if the current post is not set as the homepage.
   * 
   * @since 1.0.0
   * @return self
   */
  public function getHomepageQuery(): ?self
  {
    if ($this->post->getId() !== (int) get_option('page_on_front')) {
      return $this;
    }

    $query = $this->prepareArgs([
      [
        'key' => 'mf_scope',
        'value' => 'home',
        'compare' => '='
      ]
    ]);

    return $this->addQuery($query);
  }

  /**
   * Builds query arguments for field groups targeting the blog posts page.
   *
   * Returns field groups configured for the static page used as the posts page.
   * Returns null if the current post is not set as the blog posts page.
   * 
   * @since 1.0.0
   * @return self
   */
  public function getBlogHomeQuery(): self
  {
    if ($this->post->getId() !== (int) get_option('page_for_posts')) {
      return $this;
    }

    $query = $this->prepareArgs([
      [
        'key' => 'mf_scope',
        'value' => 'blog',
        'compare' => '='
      ]
    ]);

    return $this->addQuery($query);
  }

  /**
   * Builds query arguments for field groups targeting taxonomy terms.
   *
   * Returns field groups configured for any of the terms assigned to the current post.
   * Returns null if the post has no taxonomies or no terms assigned.
   * 
   * @since 1.0.0
   * @return self
   */
  public function getTaxonomyQuery(): self
  {
    $all_taxonomies = get_object_taxonomies($this->post->getPostType(), 'names');

    if (empty($all_taxonomies)) {
      return $this;
    }

    $all_terms = wp_get_object_terms($this->post->getId(), array_values($all_taxonomies)) ?? [];
    $all_term_ids = array_map(fn($term) => $term->term_id, $all_terms);

    if (empty($all_term_ids)) {
      return $this;
    }

    $query = $this->prepareArgs([
      [
        'key' => 'mf_scope',
        'value' => ['category', 'post_tag', 'taxonomy'],
        'compare' => 'IN'
      ],
      [
        'key' => 'mf_targets',
        'value' => $all_term_ids,
        'compare' => 'IN'
      ]
    ]);

    return $this->addQuery($query);
  }


  /**
   * Builds query arguments for field groups targeting post status.
   *
   * Returns field groups configured for the current post's status.
   * 
   * @since 1.0.0
   * @return self
   */
  public function getStatusQuery(): self
  {
    $query = $this->prepareArgs([
      [
        'key' => 'mf_scope',
        'value' => 'status',
        'compare' => '='
      ],
      [
        'key' => 'mf_targets',
        'value' => $this->post->getStatus(),
        'compare' => '='
      ]
    ]);

    return $this->addQuery($query);
  }
}
