<?php
namespace Prodigy\Includes\Models;

use Prodigy\Includes\Helpers\Prodigy_Logger;
use Prodigy\Includes\Prodigy;
use Prodigy\Includes\Prodigy_Cache;
use WP_Error;

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

/**
 * Class Products
 */
class Prodigy_Products {


	const PRODUCTS_IDS   = 'ids';
	const PRODUCTS_NAMES = 'names';

	public Prodigy_Categories $category;

	private Prodigy_Cache $cache;

	public const PRODUCT_META_TITLE = 'prodigy_product_meta_title';

	/**
	 * Products constructor.
	 */
	public function __construct() {
		$this->category = new Prodigy_Categories();
		$this->cache    = new Prodigy_Cache();
	}

	/**
	 * @param array $products
	 */
	public function add_products( array $products ) {
		foreach ( $products as $product ) {
			$this->add_product( $product );
		}
	}

	/**
	 * @param array $products
	 *
	 * @return bool
	 */
	public function validate_products( $products ) {
		return true;
	}

	/**
	 * @param array $parameters
	 *
	 * @return bool
	 */
	public function validate_products_params( array $parameters ): bool {
		$result = true;
		if ( ! empty( $parameters ) ) {
			foreach ( $parameters as $parameter ) {
				if ( ! isset( $parameter['id'] ) ) {
					$result = false;
					break;
				}
			}
		} else {
			$result = false;
		}

		return $result;
	}

	/**
	 * @param array $request_params
	 *
	 * @return int|WP_Error
	 */
	public function add_product( array $request_params ) {
		$description     = $request_params['meta_description'] ?? '';
		$meta_title      = $request_params['meta_title'] ?? '';
		$title           = $request_params['name'] ?? '';
		$slug            = $request_params['slug'];
		$remote_id       = (int) $request_params['id'];
		$categories      = $request_params['categories'] ?? array();
		$categories_post = $this->set_categories( $categories );
		if ( is_wp_error( $categories_post ) ) {
			return $categories_post;
		}

		$categoriesIds = self::getAncestorsByIds( $categories_post['categories_ids'] ?? array(), Prodigy::get_prodigy_category_type() );
		$post_id       = $this->set_product( $remote_id, $slug, $categoriesIds, $description, $title );

		if ( is_wp_error( $post_id ) ) {
			return $post_id;
		}

		if ( isset( $post_id ) ) {
			if ( isset( $request_params['tags'] ) ) {
				( new Prodigy_Tags() )->add_tags( $post_id, $request_params['tags'] );
			}
			$this->set_product_relations( $post_id, $remote_id, $meta_title );
			$this->set_product_taxonomies( $post_id, $categoriesIds );
		}

		return $post_id;
	}

	/**
	 * @param int   $post_id
	 * @param array $categoriesIds
	 *
	 * @return void
	 */
	private function set_product_taxonomies( int $post_id, array $categoriesIds ): void {
		$term_taxonomy_ids = wp_set_object_terms( $post_id, $categoriesIds, Prodigy::get_prodigy_category_type() );
		if ( is_wp_error( $term_taxonomy_ids ) ) {
			if ( PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record( Prodigy_Logger::TYPE_ERROR, __LINE__ . __METHOD__ . __CLASS__ . ' ' . $term_taxonomy_ids->get_error_message() );
			}
			new WP_Error( $term_taxonomy_ids->get_error_message(), array( 'status' => $term_taxonomy_ids->get_error_data()['status'] ?? \WP_Http::UNPROCESSABLE_ENTITY ) );
		}
	}

	/**
	 * @param array $categories
	 *
	 * @return array|array[]|void|WP_Error
	 */
	private function set_categories( array $categories ) {
		if ( empty( $categories ) ) {
			return;
		}

		return $this->category->add_categories( $categories );
	}

	/**
	 * @param int    $remote_id
	 * @param string $slug
	 * @param array  $categoriesIds
	 * @param string $description
	 * @param string $title
	 *
	 * @return int|WP_Error
	 */
	private function set_product( int $remote_id, string $slug, array $categoriesIds, string $description, string $title ) {
		$post_data = array(
			'post_title'    => wp_strip_all_tags( $title ),
			'post_content'  => wp_strip_all_tags( $description ),
			'post_name'     => wp_strip_all_tags( $slug ),
			'post_type'     => Prodigy::get_prodigy_product_type(),
			'post_status'   => 'publish',
			'post_category' => $categoriesIds,
			'tags_input'    => $tags_posts['tags_ids'] ?? '',
		);

		$product = self::get_product_meta_by_remote_id( Prodigy::PRODIGY_REMOTE_PRODUCT_ID, $remote_id );

		if ( $product ) {
			$post_data['ID'] = $product->post_id;
			$post_id         = wp_update_post( $post_data, true );
		} else {
			$post_id = wp_insert_post( $post_data, true );
		}

		if ( is_wp_error( $post_id ) ) {
			if ( PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record( Prodigy_Logger::TYPE_ERROR, __LINE__ . __METHOD__ . __CLASS__ . ' ' . $post_id->get_error_message() );
			}

			return new WP_Error( $post_id->get_error_message(), array( 'status' => $post_id->get_error_data()['status'] ?? \WP_Http::UNPROCESSABLE_ENTITY ) );
		}

		return (int) $post_id;
	}

	private function set_product_relations( $post_id, $remote_id, $meta_title ): void {
		update_post_meta( $post_id, Prodigy::PRODIGY_REMOTE_PRODUCT_ID, $remote_id );
		update_post_meta( $post_id, self::PRODUCT_META_TITLE, $meta_title );
	}

	/**
	 * @param array  $objectData
	 * @param string $type
	 *
	 * @return array
	 */
	public static function getAncestorsByIds( array $objectData, string $type ): array {
		if ( empty( $objectData ) ) {
			return array();
		}
		$parentsMerge = array();
		foreach ( $objectData as $objectId ) {
			$parentsMerge = array_merge( $parentsMerge, get_ancestors( $objectId, $type ) );
		}

		return array_unique( array_merge( $objectData, $parentsMerge ) );
	}


	/**
	 * @param string $tag_slug
	 *
	 * @return array|bool|object|\stdClass[]
	 */
	public function has_products_tag( string $tag_slug ) {
		global $wpdb;

		$post_type = Prodigy::get_prodigy_product_type();
		$taxonomy  = Prodigy::get_prodigy_tag_type();
		$term_slug = $tag_slug;

		// Table names are WP globals (prefix + literal); %i not available before WP 6.2.
		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		return $wpdb->get_results(
			$wpdb->prepare(
				"SELECT p.*
				FROM {$wpdb->posts} p
				JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
				JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
				JOIN {$wpdb->terms} t ON tt.term_id = t.term_id
				WHERE p.post_type = %s
				  AND tt.taxonomy = %s
				  AND t.slug = %s
				  AND p.post_status = 'publish';
				",
				$post_type,
				$taxonomy,
				$term_slug
			)
		);
	}

	/**
	 * @param int $product_id
	 *
	 * @return array
	 */
	public function get_product_tags( int $product_id ): array {
		$product_slugs = wp_get_object_terms( $product_id, Prodigy::get_prodigy_tag_type() );

		if ( ! is_wp_error( $product_slugs ) && ! empty( $product_slugs ) ) {
			$product_slugs = array_map(
				function ( $term ) {
					return array(
						'name' => $term->name,
						'slug' => $term->slug,
					);
				},
				$product_slugs
			);
		}

		return $product_slugs;
	}

	/**
	 * @param string $names_list
	 *
	 * @return array
	 */
	public static function prodigy_get_products_id_by_name( string $names_list ): array {
		global $wpdb;
		$img_ids_by_names = array();
		$clean_string     = html_entity_decode( $names_list );
		$product_names    = explode( ',', $clean_string );
		if ( is_array( $product_names ) ) {
			foreach ( $product_names as $key => $product_name ) {
				$product = $wpdb->get_row(
					$wpdb->prepare(
						"SELECT * FROM {$wpdb->posts} where post_name=%s and post_type=%s",
						array( $product_name, Prodigy::get_prodigy_product_type() )
					)
				);

				if ( isset( $product ) ) {
					$img_ids_by_names[ $key ] = $product->ID ?? '';
				}
			}
		}

		return $img_ids_by_names;
	}


	/**
	 * @param string $key
	 * @param int    $value
	 *
	 * @return array|object|\stdClass|null
	 */
	public static function get_product_meta_by_remote_id( string $key, int $value ) {
		global $wpdb;

		return $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->postmeta} WHERE meta_key = %s and meta_value= %d ",
				array( $key, $value )
			)
		);}

	/**
	 * Fetch postmeta rows for multiple remote IDs in a single query.
	 * Returns an array keyed by meta_value (remote product ID).
	 *
	 * @param string $key    Meta key to match.
	 * @param int[]  $values Array of remote product IDs.
	 *
	 * @return array<int, object>
	 */
	public static function get_products_meta_by_remote_ids( string $key, array $values ): array {
		if ( empty( $values ) ) {
			return array();
		}

		global $wpdb;

		$values      = array_map( 'intval', $values );
		$placeholders = implode( ',', array_fill( 0, count( $values ), '%d' ) );

		// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
		$rows = $wpdb->get_results(
			$wpdb->prepare(
				// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
				"SELECT * FROM {$wpdb->postmeta} WHERE meta_key = %s AND meta_value IN ($placeholders)",
				array_merge( array( $key ), $values )
			)
		);

		$indexed = array();
		foreach ( $rows as $row ) {
			$indexed[ (int) $row->meta_value ] = $row;
		}

		return $indexed;
	}

	/**
	 * @param string $type
	 *
	 * @return array
	 */
	public static function get_products_by_type( string $type ): array {
		global $wpdb;

		$result = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->posts} as posts 
                    LEFT JOIN {$wpdb->postmeta} as pm ON posts.id=pm.post_id
                    WHERE pm.meta_key='prodigy_remote_product_id' and posts.post_type=%s
                  ",
				Prodigy::get_prodigy_product_type()
			),
			ARRAY_A
		);

		$products = array();
		if ( $type === self::PRODUCTS_IDS ) {
			foreach ( $result as $item ) {
				$products[ $item['meta_value'] ] = esc_html( $item['meta_value'] );
			}
		}

		if ( $type === self::PRODUCTS_NAMES ) {
			foreach ( $result as $item ) {
				$products[ $item['post_name'] ] = esc_html( $item['post_title'] );
			}
		}

		return $products;
	}
}
