<?php
/**
 * Preview Filter Service
 *
 * @category   WordPress_Plugin
 * @package    Common
 * @subpackage Services\Preview
 * @author     miniOrange <info@miniorange.com>
 * @license    MIT/Expat
 * @link       https://plugins.miniorange.com/woocommerce-api-product-sync-with-woocommerce-rest-apis
 */

namespace MOWCPS\Common\Services\Preview;

use MOWCPS\Common\Models\Preview_Filters_Model;
use MOWCPS\Common\Models\Attribute_Mapping_Model;
use MOWCPS\Common\Models\Connection_Model;
use MOWCPS\Common\Services\Logging\Supplier_Logger;
use MOWCPS\Common\Utils\Sync_Utils;
use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Constants\Plugin_Filters;
use WP_Error;

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

/**
 * Class Preview_Filter_Service
 *
 * Handles preview filter logic for product sync
 */
class Preview_Filter_Service {

	/**
	 * Check if a product should be included based on preview filters
	 *
	 * @param array $product        The product data to check.
	 * @param int   $supplier_id    The supplier ID.
	 * @param int   $connection_id  The connection ID.
	 * @param array $preview_filter The preview filter metadata.
	 * @return bool True if product should be included, false otherwise.
	 */
	public static function should_include_product( $product, $supplier_id, $connection_id, $preview_filter ) {

		$product_identifier = self::get_product_identifier( $product, $supplier_id, $connection_id );

		if ( empty( $product_identifier ) ) {
			return false;
		}

		$filter_identifiers = $preview_filter['filter_skus'];

		$is_revert_mode = $preview_filter['is_revert_mode'] ?? false;

		if ( empty( $filter_identifiers ) ) {
			return true;
		}

		$identifier_in_list = in_array( $product_identifier, $filter_identifiers, true );

		if ( $is_revert_mode ) {
			return ! $identifier_in_list;
		} else {
			return $identifier_in_list;
		}
	}

	/**
	 * Get product identifier (unique_identifier or SKU) from product data
	 *
	 * @param array $product       The product data.
	 * @param int   $supplier_id   The supplier ID.
	 * @param int   $connection_id The connection ID.
	 * @return string|null Product identifier or null if not found.
	 */
	private static function get_product_identifier( $product, $supplier_id, $connection_id ) {
		$unique_identifier = self::get_unique_identifier( $product, $connection_id );

		if ( ! empty( $unique_identifier ) ) {
			return (string) $unique_identifier;
		}
		return self::get_product_sku( $product, $connection_id );
	}

	/**
	 * Get unique identifier from product data using connection configuration
	 *
	 * @param array $product       The product data.
	 * @param int   $connection_id The connection ID.
	 * @return string|null Unique identifier or null if not found.
	 */
	private static function get_unique_identifier( $product, $connection_id ) {
		$connection = Connection_Model::get_by_id( $connection_id );
		if ( empty( $connection ) ) {
			return null;
		}
		$prerequisites = $connection['configuration']['prerequisites'];
		if ( isset( $prerequisites['variable_response']['parent_identifier'] ) && ! empty( $prerequisites['variable_response']['parent_identifier'] ) ) {
			$unique_identifier_field = $prerequisites['variable_response']['parent_identifier'];
		} else {
			$unique_identifier_field = $prerequisites['main_product_unique_identifier'];
		}

		if ( ! isset( $unique_identifier_field ) ) {
			return null;
		}

		$unique_id_value = Sync_Utils::map_particular_attr( $unique_identifier_field, $product, '' );

		return ! empty( $unique_id_value ) ? (string) $unique_id_value : null;
	}

	/**
	 * Get product SKU from product data using attribute mapping
	 *
	 * @param array $product       The product data.
	 * @param int   $connection_id The connection ID.
	 * @return string|null Product SKU or null if not found.
	 */
	private static function get_product_sku( $product, $connection_id ) {
		$mappings = Attribute_Mapping_Model::get_all(
			array(
				'connection_id' => $connection_id,
			)
		);

		if ( empty( $mappings ) ) {
			return null;
		}

		$sku_mapping = null;
		foreach ( $mappings as $mapping ) {
			if ( 'sku' === strtolower( $mapping['wc_attribute'] ) ) {
				$sku_mapping = $mapping;
				break;
			}
		}

		if ( empty( $sku_mapping ) || empty( $sku_mapping['supplier_attribute'] ) ) {
			return null;
		}

		$supplier_attribute = $sku_mapping['supplier_attribute'];

		$mapped_value = Sync_Utils::map_particular_attr( $supplier_attribute, $product );

		return ! empty( $mapped_value ) ? (string) $mapped_value : null;
	}

	/**
	 * Filter products array based on preview filters
	 *
	 * @param array $products      Array of products to filter.
	 * @param int   $supplier_id   The supplier ID.
	 * @param int   $connection_id The connection ID.
	 * @return array Filtered products array.
	 */
	public static function filter_products( $products, $supplier_id, $connection_id, $preview_filter ) {
		if ( empty( $products ) || ! is_array( $products ) ) {
			return $products;
		}

		$filtered_products = array();
		$excluded_count    = 0;

		foreach ( $products as $product ) {
			if ( self::should_include_product( $product, $supplier_id, $connection_id, $preview_filter ) ) {
				$filtered_products[] = $product;
			} else {
				++$excluded_count;
			}
		}

		if ( $excluded_count > 0 ) {
			Supplier_Logger::debug( $supplier_id, sprintf( 'Preview filter: %d products excluded, %d products included', $excluded_count, count( $filtered_products ) ) );
		}

		return $filtered_products;
	}

	/**
	 * Get preview filter details for a supplier
	 *
	 * @param int $supplier_id The supplier ID.
	 * @return array|null Preview filter details or null if not found.
	 */
	public static function get_preview_filter( $supplier_id ) {
		return Preview_Filters_Model::get_by_supplier_id( $supplier_id );
	}

	/**
	 * Get the directory path for preview filter files
	 *
	 * @return string Directory path
	 */
	private static function get_filters_directory() {
		$dir = MOWCPS_PLUGIN_DIR . 'data' . DIRECTORY_SEPARATOR . 'preview-cache' . DIRECTORY_SEPARATOR . 'filterFiles';

		if ( ! file_exists( $dir ) ) {
			wp_mkdir_p( $dir );
		}

		return $dir;
	}

	/**
	 * Get the file path for a supplier's filter file
	 *
	 * @param int $supplier_id The supplier ID.
	 * @return string File path
	 */
	private static function get_filter_file_path( $supplier_id ) {
		return self::get_filters_directory() . DIRECTORY_SEPARATOR . 'supplier_' . $supplier_id . '_filter.json';
	}

	/**
	 * Save filter product IDs to file
	 *
	 * @param int   $supplier_id The supplier ID.
	 * @param array $product_ids Array of product unique identifiers.
	 * @return bool|WP_Error True on success, WP_Error on failure
	 */
	public static function save_filter_to_file( $supplier_id, $product_ids ) {
		if ( ! is_array( $product_ids ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_OPERATION,
				'Product IDs must be an array',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		$file_path = self::get_filter_file_path( $supplier_id );
		$json_data = wp_json_encode( $product_ids, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );

		if ( false === $json_data ) {
			return new WP_Error(
				Constants::ERROR_GENERAL,
				'Failed to encode product IDs to JSON',
				array( 'status' => Constants::HTTP_INTERNAL_SERVER_ERROR )
			);
		}

		$temp_file = $file_path . '.tmp';
		$result    = file_put_contents( $temp_file, $json_data, LOCK_EX );

		if ( false === $result ) {
			return new WP_Error(
				Constants::ERROR_GENERAL,
				'Failed to write filter file',
				array( 'status' => Constants::HTTP_INTERNAL_SERVER_ERROR )
			);
		}

		if ( ! rename( $temp_file, $file_path ) ) {
			unlink( $temp_file );
			return new WP_Error(
				Constants::ERROR_GENERAL,
				'Failed to save filter file',
				array( 'status' => Constants::HTTP_INTERNAL_SERVER_ERROR )
			);
		}

		return true;
	}

	/**
	 * Load filter product IDs from file
	 *
	 * @param int $supplier_id The supplier ID.
	 * @return array Array of product unique identifiers
	 */
	public static function load_filter_from_file( $supplier_id ) {
		$file_path = self::get_filter_file_path( $supplier_id );

		if ( ! file_exists( $file_path ) ) {
			return array();
		}

		$content = file_get_contents( $file_path );

		if ( false === $content || empty( $content ) ) {
			return array();
		}

		$product_ids = json_decode( $content, true );

		return is_array( $product_ids ) ? $product_ids : array();
	}

	/**
	 * Delete filter file for supplier
	 *
	 * @param int $supplier_id The supplier ID.
	 * @return bool True if file was deleted or didn't exist, false on failure
	 */
	public static function delete_filter_file( $supplier_id ) {
		$file_path = self::get_filter_file_path( $supplier_id );

		if ( ! file_exists( $file_path ) ) {
			return true;
		}

		return unlink( $file_path );
	}

	/**
	 * Clear filter product IDs (deletes the file)
	 *
	 * @param int $supplier_id The supplier ID.
	 * @return bool True on success
	 */
	public static function clear_filter_products( $supplier_id ) {
		return self::delete_filter_file( $supplier_id );
	}

	/**
	 * Get count of products in filter file
	 *
	 * @param int $supplier_id The supplier ID.
	 * @return int Number of products in filter
	 */
	public static function get_filter_product_count( $supplier_id ) {
		$product_ids = self::load_filter_from_file( $supplier_id );
		return count( $product_ids );
	}
}
