<?php
/**
 * Frontend query protection for restricted content.
 *
 * @package Polanger_Dashboard_Tools
 */

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

class PDT_Content_Visibility_Query {

  /**
   * Register query hooks.
   *
   * @return void
   */
  public function register_hooks() {
    add_action( 'pre_get_posts', array( $this, 'exclude_restricted_posts_from_queries' ), 20 );
  }

  /**
   * Exclude restricted content from common public queries before SQL runs.
   *
   * @param WP_Query $query Query instance.
   * @return void
   */
  public function exclude_restricted_posts_from_queries( $query ) {
    if ( ! $query instanceof WP_Query || is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
      return;
    }

    if ( ! PDT_Content_Visibility::should_hide_from_archives() || $query->get( 'pdt_content_visibility_skip' ) ) {
      return;
    }

    if ( $query->is_singular() || $query->is_404() ) {
      return;
    }

    $post_types = $this->resolve_query_post_types( $query );

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

    $restricted_ids = PDT_Content_Visibility::get_restricted_post_ids( $post_types );

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

    $existing_exclusions = $query->get( 'post__not_in' );
    $existing_exclusions = is_array( $existing_exclusions ) ? $existing_exclusions : (array) $existing_exclusions;
    $existing_exclusions = array_filter( array_map( 'absint', $existing_exclusions ) );

    $query->set(
      'post__not_in',
      array_values(
        array_unique(
          array_merge(
            $existing_exclusions,
            array_map( 'absint', $restricted_ids )
          )
        )
      )
    );
    $query->set( 'pdt_content_visibility_applied', true );
  }

  /**
   * Resolve the public post types participating in a query.
   *
   * @param WP_Query $query Query instance.
   * @return array
   */
  private function resolve_query_post_types( $query ) {
    $supported = PDT_Content_Visibility::get_supported_post_types();
    $post_type = $query->get( 'post_type' );

    if ( empty( $post_type ) || 'any' === $post_type ) {
      return $supported;
    }

    if ( is_string( $post_type ) ) {
      $post_type = array( $post_type );
    }

    return array_values( array_intersect( array_map( 'sanitize_key', (array) $post_type ), $supported ) );
  }
}
