<?php

namespace Limb_Chatbot\Includes\Services;

use Exception;

/**
 * Service class for managing post-related operations
 *
 * @since 1.0.0
 */
class Post_Types_Service {

	/**
	 * Retrieves a collection of posts for a specific custom post type.
	 *
	 * Supports filtering by search keyword, pagination, and other WP_Query parameters.
	 *
	 * @param  string  $cpt_name  Custom post type name.
	 * @param  array  $params  Query parameters including page, per_page, and s (search).
	 *
	 * @return Collection Collection of posts with required fields.
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function get_posts( string $cpt_name, array $params = [] ): Collection {
		// Handle title search with direct SQL query
		if ( ! empty( $params['lbaic_title_search'] ) ) {
			return $this->get_posts_by_title_search( $cpt_name, $params );
		}

		// Standard WordPress query without title search
		$default_params = [
			'post_type'      => sanitize_key( $cpt_name ),
			'posts_per_page' => isset( $params['per_page'] ) ? absint( $params['per_page'] ) : 10,
			'paged'          => isset( $params['page'] ) ? absint( $params['page'] ) : 1,
			'post_status'    => 'publish',
			'orderby'        => ! empty( $params['orderby'] ) ? sanitize_key( $params['orderby'] ) : 'modified',
			'numberposts'    => - 1,
			'order'          => ! empty( $params['order'] ) && in_array( strtoupper( $params['order'] ),
				[ 'ASC', 'DESC' ],
				true ) ? strtoupper( $params['order'] ) : 'DESC',
		];

		// Get posts
		$posts = get_posts( $default_params );

		// Transform posts to collection with required fields
		$items = array_map( function ( $post ) {
			return [
				'id'           => $post->ID,
				'title'        => $post->post_title,
				'link'         => get_permalink( $post->ID ),
				'modified_gmt' => $post->post_modified_gmt,
			];
		}, $posts );

		$collection = new Collection( $items );

		// Set total count for pagination
		$total = wp_count_posts( $cpt_name )->publish ?? 0;
		$collection->set_total( (int) $total );

		// Handle include parameter for additional data
		$include = ! empty( $params['include'] ) ? $params['include'] : [];
		if ( ! empty( $include ) ) {
			/**
			 * Filter: Allow integrations to add additional properties to post types collection.
			 *
			 * @param  Collection  $collection  The collection to modify.
			 * @param  string  $cpt_name  Post type name.
			 * @param  array  $include  Include parameter value.
			 * @param  array  $params  Original query parameters.
			 */
			apply_filters( 'lbaic_post_types_collection_include', $collection, $cpt_name, $include, $params );
		}

		return $collection;
	}

	/**
	 * Retrieves posts filtered by title search using WP_Query.
	 *
	 * Searches only in post_title field for more precise results.
	 * Uses a temporary filter to modify the WHERE clause for this specific query.
	 *
	 * @param string $cpt_name Custom post type name.
	 * @param array  $params   Query parameters including lbaic_title_search, pagination, etc.
	 *
	 * @return Collection Collection of posts matching the title search.
	 * @since 1.0.0
	 */
	private function get_posts_by_title_search( string $cpt_name, array $params ): Collection {
		$search_term = sanitize_text_field( $params['lbaic_title_search'] );

		// Create a closure for the filter to avoid polluting global scope
		$title_search_filter = function ( $where ) use ( $search_term ) {
			global $wpdb;
			$like   = '%' . $wpdb->esc_like( $search_term ) . '%';
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_title LIKE %s", $like );

			return $where;
		};

		// Add filter temporarily
		add_filter( 'posts_where', $title_search_filter );

		// Build query args
		$query_args = [
			'post_type'      => sanitize_key( $cpt_name ),
			'post_status'    => 'publish',
			'posts_per_page' => isset( $params['per_page'] ) ? absint( $params['per_page'] ) : 10,
			'paged'          => isset( $params['page'] ) ? absint( $params['page'] ) : 1,
			'orderby'        => ! empty( $params['orderby'] ) ? sanitize_key( $params['orderby'] ) : 'modified',
			'order'          => ! empty( $params['order'] ) && in_array( strtoupper( $params['order'] ), [ 'ASC', 'DESC' ], true )
				? strtoupper( $params['order'] )
				: 'DESC',
		];

		// Execute query
		$query = new \WP_Query( $query_args );

		// Remove filter immediately after query
		remove_filter( 'posts_where', $title_search_filter );

		// Transform posts to collection with required fields
		$items = array_map( function ( $post ) {
			return [
				'id'           => $post->ID,
				'title'        => $post->post_title,
				'link'         => get_permalink( $post->ID ),
				'modified_gmt' => $post->post_modified_gmt,
			];
		}, $query->posts );

		$collection = new Collection( $items );

		// Set total from WP_Query
		$collection->set_total( (int) $query->found_posts );

		// Reset post data
		wp_reset_postdata();

		// Handle include parameter for additional data
		$include = ! empty( $params['include'] ) ? sanitize_text_field( $params['include'] ) : '';
		if ( ! empty( $include ) ) {
			/**
			 * Filter: Allow integrations to add additional properties to post types collection.
			 *
			 * @param  Collection  $collection  The collection to modify.
			 * @param  string  $post_type  Post type name.
			 * @param  array  $include  Include parameter values.
			 * @param  array  $params  Original query parameters.
			 */
			apply_filters( 'lbaic_post_types_collection_include', $collection, $cpt_name, $include, $params );
		}

		return $collection;
	}
}

