<?php

namespace Limb_Chatbot\Includes\Data_Objects;

use Limb_Chatbot\Includes\Database_Strategies\WP_Query;
use Limb_Chatbot\Includes\Services\Data_Object_Collection;


/**
 * Class WP_Post_Data_Object
 *
 * Represents a WordPress post-based data object with status mapping and meta retrieval support.
 *
 * @since 1.0.0
 */
class WP_Post_Data_Object extends Data_Object {

	/**
	 * Published post status.
	 *
	 * @since 1.0.0
	 */
	const STATUS_PUBLISHED = 1;

	/**
	 * Draft post status.
	 *
	 * @since 1.0.0
	 */
	const STATUS_DRAFT = 0;

	/**
	 * Auto-draft post status.
	 *
	 * @since 1.0.0
	 */
	const STATUS_AUTO_DRAFT = 4;

	/**
	 * Post ID.
	 *
	 * @var null|int
	 * @since 1.0.0
	 */
	public $id;

	/**
	 * Post title.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	public string $title;

	/**
	 * Internal status constant value.
	 *
	 * @var int|null
	 * @since 1.0.0
	 */
	public ?int $status = null;

	/**
	 * Post creation date (Y-m-d H:i:s).
	 *
	 * @var string
	 * @since 1.0.0
	 */
	public string $created_at;

	/**
	 * Post update date (Y-m-d H:i:s).
	 *
	 * @var string
	 * @since 1.0.0
	 */
	public string $updated_at;

	/**
	 * Get internal status constant from WP status string.
	 *
	 * @param string $status
	 * @return int
	 * @since 1.0.0
	 */
	public static function get_our_status_equivalent( $status ) {
		return array_flip( self::wp_statuses_equivalents() )[ $status ];
	}

	/**
	 * Get status map between internal constants and WP status strings.
	 *
	 * @return array
	 * @since 1.0.0
	 */
	protected static function wp_statuses_equivalents(): array {
		return [
			self::STATUS_PUBLISHED  => 'publish',
			self::STATUS_DRAFT      => 'draft',
			self::STATUS_AUTO_DRAFT => 'auto-draft',
		];
	}

	/**
	 * Get all available internal statuses.
	 *
	 * @return int[]
	 * @since 1.0.0
	 */
	public static function get_statuses(): array {
		return [
			self::STATUS_PUBLISHED,
			self::STATUS_DRAFT,
			self::STATUS_AUTO_DRAFT,
		];
	}

	/**
	 * Count posts by filtered conditions.
	 *
	 * @param array $where
	 * @param mixed ...$args
	 * @return int|null
	 * @since 1.0.0
	 */
	public static function count( $where = [], ...$args ): ?int {
		unset( $where['page'] );
		unset( $where['per_page'] );

		return parent::count( static::map_where( $where ), static::POST_TYPE );
	}

	/**
	 * Map abstract filter keys to WP_Query-compatible keys.
	 *
	 * @param array $where
	 * @return array
	 * @since 1.0.0
	 */
	protected static function map_where( $where ) {
		if ( isset( $where['id'] ) && is_array( $where['id'] ) ) {
			$where['post__in'] = $where['id'];
			unset( $where['id'] );
		}
		if ( isset( $where['status'] ) ) {
			$where['post_status'] = self::get_wp_status_equivalent( $where['status'] );
			unset( $where['status'] );
		} else {
			$where['post_status'] = 'any';
		}
		// In case there is a data which is not wp_post table related, then it should be through meta
		if ( isset( $where['uuid'] ) ) {
			$where['meta_query'] = [
				[
					'key'     => '_' . self::UUID_COLUMN_NAME,
					'value'   => $where['uuid'],
					'compare' => 'IN',
				],
			];
			unset( $where['uuid'] );
		}
		if ( isset( $where['page'] ) ) {
			$where['paged'] = $where['page'];
			unset( $where['page'] );
		}
		if ( isset( $where['per_page'] ) ) {
			$where['posts_per_page'] = $where['per_page'];
			unset( $where['per_page'] );
		}

		return $where;
	}

	/**
	 * Get WP post status string from internal status constant.
	 *
	 * @param int $status
	 * @return string
	 * @since 1.0.0
	 */
	public static function get_wp_status_equivalent( $status ) {
		return self::wp_statuses_equivalents()[ $status ];
	}

	/**
	 * Get the database strategy for WP_Post objects.
	 *
	 * @return WP_Query
	 * @since 1.0.0
	 */
	public static function get_db_strategy(): WP_Query {
		return WP_Query::instance();
	}

	/**
	 * Get meta value or meta object for given key.
	 *
	 * @param string $meta_key
	 * @param bool   $object Return full meta object instead of just the value.
	 * @return mixed|null
	 * @since 1.0.0
	 */
	public function get_meta( $meta_key, $object = false ) {
		$metas = WP_Meta_Data_Object::where( [ 'post_id' => $this->get_id(), 'meta_key' => $meta_key ] );

		return ! $metas->is_empty() ? ( $object ? $metas->first() : $metas->first()->get_meta_value() ) : null;
	}

	/**
	 * Fetch objects by filter.
	 *
	 * @param array $where
	 * @param mixed ...$args
	 * @return Data_Object_Collection
	 * @since 1.0.0
	 */
	public static function where( $where, ...$args ): Data_Object_Collection {
		return parent::where( self::map_where( $where ), static::POST_TYPE );
	}

	/**
	 * Find a single post object by ID. Falls back to auto-draft status if not found.
	 *
	 * @param int $id
	 * @return static|null
	 * @since 1.0.0
	 */
	public static function find( $id ) {
		$post = self::get_db_strategy()->find( $id, static::POST_TYPE ) ?? self::get_db_strategy()->find( $id, static::POST_TYPE, self::get_wp_status_equivalent( WP_Post_Data_Object::STATUS_AUTO_DRAFT ) );

		return ! empty( $post ) ? self::make( $post ) : null;
	}
}