<?php

namespace Prodigy\Includes\Models;

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

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
/**
 * Class Prodigy_Attributes
 */
class Prodigy_Attributes {

	const TABLE = 'prodigy_attribute_taxonomy';

	/**
	 * @param array  $data
	 *
	 * @param string $taxonomy
	 *
	 * @return int|WP_Error
	 */
	public function add( array $data, string $taxonomy ) {
		global $wpdb;

		if ( empty( taxonomy_exists( $taxonomy ) ) ) {
			return new WP_Error( 'create_attribute_error', 'Taxonomy does not exist', array( 'status' => 422 ) );
		}

		// begin transaction
		$wpdb->query( 'START TRANSACTION' );

		$result_term = wp_insert_term(
			$data['name'],
			$taxonomy,
			array( 'slug' => $data['slug'] )
		);

		if ( is_wp_error( $result_term ) ) {
			$wpdb->query( 'ROLLBACK' );

			return $result_term;
		}

		$result_sync = add_term_meta( $result_term['term_id'], Prodigy::PRODIGY_REMOTE_ATTRIBUTE_ID, $data['id'], true );

		if ( is_wp_error( $result_sync ) ) {
			$wpdb->query( 'ROLLBACK' );

			return $result_sync;
		}

		$wpdb->query( 'COMMIT' );

		return $result_term['term_id'];
	}

	/**
	 * @param int    $remote_id
	 * @param string $slug
	 *
	 * @return bool|WP_Error
	 */
	public function delete( int $remote_id, string $slug ) {

		$attributes_obj    = new Prodigy_Attribute_Taxonomies();
		$result_attributes = $attributes_obj->delete_by_remote_id( $remote_id );

		if ( empty( $result_attributes ) ) {
			return new WP_Error( 'delete_attribute_taxonomies_error', 'Error is deleting taxonomies', array( 'status' => 422 ) );
		}

		$result_unregister = unregister_taxonomy( $slug );

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

		return unregister_taxonomy( $slug );
	}

	/**
	 * @param   string $attribute_slug
	 * @param   array  $new_options
	 *
	 * @return array
	 */
	public function update_attribute_options( string $attribute_slug, array $new_options ): array {
		$result               = array();
		$current_options_data = Prodigy_Taxonomies::get_attribute_options_by_slug( $attribute_slug );
		$current_options      = $this->get_associated_options( (array) $current_options_data );

		$to_remove = $this->array_options_diff( $current_options, $new_options );
		$to_add    = $this->array_options_diff( $new_options, $current_options );

		if ( ! empty( $to_remove ) ) {
			$result = $this->delete_options( $attribute_slug, $to_remove );
		}

		if ( ! empty( $to_add ) ) {
			$result = $this->add_collection( $attribute_slug, $to_add );
		}

		return $result;
	}

	/**
	 *
	 * @param   string $attribute_slug
	 * @param   array  $to_remove
	 *
	 * @return array
	 */
	private function delete_options( string $attribute_slug, array $to_remove ): array {
		global $wpdb;
		$data = array();
		foreach ( $to_remove as $item ) {
			$term               = Prodigy_Taxonomies::get_taxonomy_by_different_slugs( $attribute_slug, $item['slug'] );
			$delete_term_result = wp_delete_term( $term->term_id, $attribute_slug );

			if ( is_wp_error( $delete_term_result ) ) {
				if ( PRODIGY_DEBUG_MODE ) {
					$message = 'Error deleting attribute option: ' . $delete_term_result->get_error_message();
					Prodigy_Logger::add_record( Prodigy_Logger::TYPE_ERROR, $message );
				}

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

				return array();
			}

			if ( $delete_term_result ) {
				$id                               = $item['id'];
				$data[ $item['id'] ]['success']   = true;
				$data[ $item['id'] ]['option_id'] = (int) $id;
			} else {
				$data[ $item['id'] ]['success']   = false;
				$data[ $item['id'] ]['option_id'] = false;
			}
		}

		return $data;
	}

	/**
	 * @param   array $current_options
	 * @param   array $new_options
	 *
	 * @return array
	 */
	private function array_options_diff( array $current_options, array $new_options ): array {
		$field1 = 'id';
		$field2 = 'slug';

		$lookup = array();
		foreach ( $new_options as $item ) {
			$key            = $item[ $field1 ] . '|' . $item[ $field2 ];
			$lookup[ $key ] = true;
		}

		return array_filter(
			$current_options,
			function ( $item ) use ( $lookup, $field1, $field2 ) {
				$key = $item[ $field1 ] . '|' . $item[ $field2 ];
				return ! isset( $lookup[ $key ] );
			}
		);
	}

	/**
	 * @param   array $options_data
	 *
	 * @return array
	 */
	private function get_associated_options( array $options_data ): array {
		$assocArray = array();
		foreach ( $options_data as $key => $item ) {
			$assocArray[ $key ]['id']   = (int) $item->meta_value;
			$assocArray[ $key ]['slug'] = $item->slug;
		}

		return $assocArray;
	}

	/**
	 * @param   string $taxonomy
	 * @param   array  $list_attributes
	 *
	 * @return array
	 */
	public function add_collection( string $taxonomy, array $list_attributes ): array {
		$data = array();

		foreach ( $list_attributes as $attribute ) {
			$remote_id_info = Prodigy_Product_Attributes::get_term_id_by_meta_key( Prodigy::PRODIGY_REMOTE_ATTRIBUTE_ID, $attribute['id'] );
			$local_slug     = $attribute['slug'];

			if ( ! Prodigy_Taxonomies::get_taxonomy_by_different_slugs( $local_slug, $taxonomy ) && empty( $remote_id_info ) ) {
				$result_attributes = $this->add( $attribute, $taxonomy );
			}

			if ( ! empty( $result_attributes ) ) {
				if ( is_wp_error( $result_attributes ) ) {
					$data[ $attribute['id'] ]['success']   = false;
					$data[ $attribute['id'] ]['option_id'] = false;
					$data[ $attribute['id'] ]['error']     = $result_attributes->get_error_message();
				} else {
					$id                                    = $result_attributes;
					$data[ $attribute['id'] ]['success']   = true;
					$data[ $attribute['id'] ]['option_id'] = (int) $id;
				}
			}
		}

		return $data;
	}


	/**
	 * @param int $id
	 *
	 * @return object|null
	 */
	public static function get_by_remote_id( int $id ): ?object {
		global $wpdb;

		$table_name = $wpdb->prefix . self::TABLE;

		return $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM {$table_name} WHERE remote_id = %d', $id ) );
	}


	/**
	 * @param string $taxonomy
	 * @param string $slug
	 *
	 * @return array|object|\stdClass|null
	 */
	public static function get_attributes_by_different_slugs( string $taxonomy, string $slug ) {
		global $wpdb;

		return $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->terms} as tr 
				 LEFT JOIN {$wpdb->term_taxonomy} as tt ON (tr.term_id = tt.term_id)
				 WHERE tr.slug=%s
				 AND tt.taxonomy=%s
				 ",
				array(
					$slug,
					$taxonomy,
				)
			)
		);
	}

	/**
	 * @param   array $ids
	 *
	 * @return array|false|null
	 */
	public static function get_attributes_by_ids( array $ids ) {
		global $wpdb;

		$ids = array_map( 'absint', $ids );
		$ids = array_filter( $ids );
		if ( empty( $ids ) ) {
			return array();
		}
		$table_name   = $wpdb->prefix . self::TABLE;
		$placeholders = implode( ', ', array_fill( 0, count( $ids ), '%d' ) );
		$results = $wpdb->get_results(
			$wpdb->prepare(
				// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $table_name and $placeholders are safe (prefix+constant, format string).
				'SELECT * FROM ' . $table_name . ' WHERE id IN (' . $placeholders . ') ORDER BY FIELD(id, ' . $placeholders . ')',
				array_merge( $ids, $ids )
			)
		);

		return array_column( $results, 'slug', 'id' );
	}

	/**
	 * @return array|false|null
	 */
	public static function get_attributes_list() {
		global $wpdb;

		$table_name = $wpdb->prefix . self::TABLE;
		$results    = $wpdb->get_results(
			"SELECT * FROM $table_name",
			ARRAY_A
		);

		return array_column( $results, 'slug', 'id' );
	}
}
