<?php

namespace CustomPostOrder\Includes;

use WP_PowerSuite\Ordering\QueryOrderGuard;

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

/**
 * Applies custom menu_order to the eligible main query.
 */
class QueryModifier {

	/** @var array<string, mixed> */
	private array $settings;

	public function __construct( array $settings ) {
		$this->settings = $settings;
	}

	public function registerHooks(): void {
		add_action( 'pre_get_posts', [ $this, 'maybeApplyCustomOrder' ], 20 );
	}

	public function maybeApplyCustomOrder( \WP_Query $query ): void {
		if ( ! $query->is_main_query() ) {
			return;
		}

		if ( $query->is_singular() || $query->is_feed() || $query->is_preview() || $query->is_embed() ) {
			return;
		}

		$post_type = $this->resolveQueryPostType( $query );
		if ( $post_type === '' || ! $this->isPostTypeEnabled( $post_type ) ) {
			return;
		}

		if ( ! $this->matchesContext( $query, $post_type ) ) {
			return;
		}

		if ( QueryOrderGuard::querySuppressesFilters( $query ) ) {
			return;
		}

		$respect = ! empty( $this->settings['respect_existing_order'] );
		if ( QueryOrderGuard::postQueryHasExplicitOrderby( $query->get( 'orderby' ), $respect ) ) {
			return;
		}

		/**
		 * Whether custom post order should apply to this query.
		 *
		 * @param bool      $apply     Default true when all internal checks passed.
		 * @param \WP_Query $query     The query instance.
		 * @param string    $post_type Resolved post type slug.
		 * @param array     $settings  Module settings.
		 */
		$apply = apply_filters( 'wp_powersuite_custom_post_order_apply_to_query', true, $query, $post_type, $this->settings );
		if ( ! $apply ) {
			return;
		}

		$order_args = [
			'orderby' => [
				'menu_order' => 'ASC',
				'date'       => 'DESC',
			],
			'order'   => 'ASC',
		];

		/**
		 * Filter orderby arguments applied by Custom Post Order.
		 *
		 * @param array     $order_args menu_order and secondary order.
		 * @param \WP_Query $query
		 * @param string    $post_type
		 */
		$order_args = apply_filters( 'wp_powersuite_custom_post_order_orderby_args', $order_args, $query, $post_type );

		foreach ( $order_args as $key => $value ) {
			$query->set( $key, $value );
		}
	}

	private function matchesContext( \WP_Query $query, string $post_type ): bool {
		if ( ! empty( $this->settings['apply_frontend_main'] ) && ( $query->is_home() || $query->is_post_type_archive( $post_type ) ) ) {
			return true;
		}

		/**
		 * Whether a Premium query surface (archives, search, admin) should apply.
		 *
		 * Lite only honors the main frontend query. Extra contexts live in the overlay.
		 *
		 * @param bool      $match     Default false when the free main-query check missed.
		 * @param \WP_Query $query     The query instance.
		 * @param string    $post_type Resolved post type slug.
		 * @param array     $settings  Module settings.
		 */
		return (bool) apply_filters( 'wp_powersuite_custom_post_order_matches_premium_context', false, $query, $post_type, $this->settings );
	}

	private function resolveQueryPostType( \WP_Query $query ): string {
		$post_type = $query->get( 'post_type' );
		if ( is_array( $post_type ) ) {
			$post_type = reset( $post_type );
		}
		if ( ! is_string( $post_type ) || $post_type === '' ) {
			$post_type = 'post';
		}

		return sanitize_key( $post_type );
	}

	private function isPostTypeEnabled( string $post_type ): bool {
		$types = $this->settings['post_types'] ?? [];
		return is_array( $types ) && in_array( $post_type, $types, true );
	}
}
