<?php

namespace Limb_Chatbot\Includes\Database_Strategies;

use Exception;
use Limb_Chatbot\Includes\Database_Strategy_Interface;
use Limb_Chatbot\Includes\Traits\SingletonTrait;
use WP_Post;

/**
 * Class WP_Query
 *
 * Implements database strategy for WordPress posts using WP_Query and related functions.
 * Provides create, find, update, delete, and query operations on posts.
 *
 * @since 1.0.0
 */
class WP_Query extends Database_Strategy implements Database_Strategy_Interface {

	use SingletonTrait;

	/**
	 * Create a new WordPress post.
	 *
	 * @param  array  $data  Post data to insert (wp_insert_post format).
	 * @param  string|null  $table  Unused parameter, present for interface compatibility.
	 * @param  array|null  $fillable  Unused parameter, present for interface compatibility.
	 * @param  string|null  $uuid_column  Unused parameter, present for interface compatibility.
	 *
	 * @return WP_Post The newly created post object.
	 * @throws Exception Throws exception if creation fails.
	 * @since 1.0.0
	 */
	public function create( $data, $table = null, $fillable = null, $uuid_column = null ) {
		$data = WPDB::instance()->sanitize_post_data_for_emojis( $data );
		$id = wp_insert_post( $data );
		if ( $id && ! is_wp_error( $id ) ) {
			return get_post( $id );
		} else {
			throw new Exception( __( 'Error on creating post.', 'limb-chatbot' ) );
		}
	}

	/**
	 * Find a post by ID and post type.
	 *
	 * @param  int  $id  Post ID.
	 * @param  mixed  ...$args
	 *
	 * @return WP_Post|null Returns the post object if found, or null if not.
	 * @since 1.0.0
	 */
	public function find( $id, ...$args ) {
		$posts = get_posts( [
			'p'           => $id,
			'post_type'   => $args[0],
			'post_status' => $args[1] ?? 'any',
		] );

		return ! empty( $posts[0] ) ? $posts[0] : null; // Get the first (and only) post
	}

	/**
	 * Delete a post by ID.
	 *
	 * @param array $where Associative array with 'id' key for post ID.
	 * @return array|false|WP_Post|null False on failure, or post ID on successful deletion.
	 * @since 1.0.0
	 */
	public function delete( $where ) {
		if ( $id = $where['id'] ) {
			return wp_delete_post( $id, true );
		}

		return false;
	}

	/**
	 * Update a post by ID.
	 *
	 * @param array $where Associative array with 'id' key for post ID.
	 * @param array $data  Data to update (wp_update_post format).
	 * @return int|false Post ID on success, false on failure.
	 * @since 1.0.0
	 */
	public function update( $where, $data ) {
		if ( $id = $where['id'] ) {
			$data = WPDB::instance()->sanitize_post_data_for_emojis( $data );
			return wp_update_post( array_merge( [ 'ID' => $id ], $data ) );
		}

		return false;
	}

	/**
	 * Find posts by meta key and meta value.
	 *
	 * @param string $meta_key    Meta key to query.
	 * @param mixed  $meta_value  Meta value to match.
	 * @param string $post_type   Post type.
	 * @param string $post_status Optional post status (default: 'any').
	 *
	 * @return WP_Post[] List of matched posts.
	 * @since 1.0.0
	 */
	public function find_by_meta( $meta_key, $meta_value, $post_type, $post_status = 'any' ) {
		return self::where( [ 'meta_query' => [ [ 'key' => $meta_key, 'value' => $meta_value, 'compare' => '=' ] ], 'post_status' => $post_status ], $post_type );
	}

	/**
	 * Query posts with arbitrary conditions and post type.
	 *
	 * @param  array  $conditions  WP_Query arguments array.
	 * @param  mixed  ...$args
	 *
	 * @return WP_Post[] List of posts matching the query.
	 * @since 1.0.0
	 */
	public function where( $conditions = array(), ...$args ): array {
		$posts = new \WP_Query( array_merge( $conditions, [ 'post_type' => $args[0] ] ) );
		$items = $posts->get_posts();
		wp_reset_postdata();

		return $items;
	}

	/**
	 * Count posts matching given conditions and post type.
	 *
	 * @param  array  $conditions  WP_Query arguments array.
	 * @param  mixed  ...$args
	 *
	 * @return int Number of posts found.
	 * @since 1.0.0
	 */
	public function count( $conditions, ...$args ) {
		$args = array_merge( $conditions, [ 'post_type' => $args[0], 'fields' => 'ids', 'no_found_rows' => false ] );

		return ( new \WP_Query( $args ) )->found_posts;
	}
}