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

namespace MOWCPS\Common\DTO;

use WP_Error;
use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Abstracts\Base_DTO;
use MOWCPS\Common\Utils\Utils;

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

/**
 * Class Setting_Request
 *
 * Handles setting request data transformation and validation
 */
class Setting_Request extends Base_DTO {
	/**
	 * Operation type
	 *
	 * @var string
	 */
	private $operation_type;

	/**
	 * Operation
	 *
	 * @var string
	 */
	private $operation;

	/**
	 * Is active flag
	 *
	 * @var bool
	 */
	private $is_active;

	/**
	 * Configuration data
	 *
	 * @var array|null
	 */
	private $configuration;

	/**
	 * Schedule data
	 *
	 * @var array|null
	 */
	private $schedule_data;

	/**
	 * Filter data
	 *
	 * @var array|null
	 */
	private $filter_data;

	/**
	 * Connection IDs
	 *
	 * @var array|null
	 */
	private $connection_ids;

	/**
	 * Attribute mapping IDs
	 *
	 * @var array|null
	 */
	private $attribute_mapping_ids;

	/**
	 * Mapping of attribute mapping IDs to connection IDs
	 * Used for scheduled syncs to override connection IDs for "Updated" connections
	 *
	 * @var array|null
	 */
	private $mapping_to_connection_map;

	/**
	 * Valid operations
	 *
	 * @var array
	 */
	private static $valid_operations = array(
		'outbound',
		'filter',
		'schedule',
		'product-operations',
		'file-sync',
		'page',
		'batch',
		'multi-threading',
	);

	/**
	 * Valid operation types
	 *
	 * @var array
	 */
	private static $valid_operation_types = array(
		'data-sync',
		'performance-optimization',
	);

	/**
	 * Original request parameters.
	 *
	 * @var array
	 */
	private $original_params;

	/**
	 * Create instance from request parameters
	 *
	 * @param array $params Request parameters.
	 * @return self|WP_Error Instance or error if validation fails
	 */
	public static function from_request_parameters( $params ) {
		$instance = new self();

		// Transform data.
		$instance->operation                 = sanitize_text_field( wp_unslash( $params['operation'] ?? 'product-operations' ) );
		$instance->operation_type            = sanitize_text_field( wp_unslash( $params['operation_type'] ?? 'data-sync' ) );
		$instance->is_active                 = isset( $params['is_active'] ) ? (bool) sanitize_text_field( wp_unslash( $params['is_active'] ) ) : false;
		$instance->configuration             = isset( $params['configuration'] ) ? Utils::sanitize_json_field( wp_unslash( $params['configuration'] ) ) : null;
		$instance->schedule_data             = isset( $params['schedule_data'] ) ? Utils::sanitize_json_field( wp_unslash( $params['schedule_data'] ) ) : null;
		$instance->filter_data               = isset( $params['filter_data'] ) ? Utils::sanitize_json_field( wp_unslash( $params['filter_data'] ) ) : null;
		$instance->connection_ids            = isset( $params['connection_ids'] ) ? array_map( 'sanitize_text_field', wp_unslash( $params['connection_ids'] ) ) : null;
		$instance->attribute_mapping_ids     = isset( $params['attribute_mapping_ids'] ) ? array_map( 'sanitize_text_field', wp_unslash( $params['attribute_mapping_ids'] ) ) : null;
		$instance->mapping_to_connection_map = isset( $params['mapping_to_connection_map'] ) ? array_map( 'sanitize_text_field', wp_unslash( $params['mapping_to_connection_map'] ) ) : null;

		return $instance->validate();
	}

	/**
	 * Create instance from request parameters for updates (doesn't require operation field)
	 *
	 * @param array $params Request parameters.
	 * @return self|WP_Error Instance if valid, WP_Error if invalid
	 */
	public static function from_update_parameters( $params ) {
		$instance = new self();

		// Store original parameters for selective updates.
		$instance->original_params = $params;

		// Transform data - only set values if they were provided.
		if ( isset( $params['is_active'] ) ) {
			$instance->is_active = (bool) sanitize_text_field( wp_unslash( $params['is_active'] ) );
		}
		if ( isset( $params['configuration'] ) ) {
			$instance->configuration = Utils::sanitize_json_field( wp_unslash( $params['configuration'] ) );
		}
		if ( isset( $params['schedule_data'] ) ) {
			$instance->schedule_data = Utils::sanitize_json_field( wp_unslash( $params['schedule_data'] ) );
		}
		if ( isset( $params['filter_data'] ) ) {
			$instance->filter_data = Utils::sanitize_json_field( wp_unslash( $params['filter_data'] ) );
		}
		if ( isset( $params['connection_ids'] ) ) {
			$instance->connection_ids = array_map( 'sanitize_text_field', wp_unslash( $params['connection_ids'] ) );
		}
		if ( isset( $params['attribute_mapping_ids'] ) ) {
			$instance->attribute_mapping_ids = array_map( 'sanitize_text_field', wp_unslash( $params['attribute_mapping_ids'] ) );
		}

		return $instance->validate_update();
	}

	/**
	 * Validate the request data
	 *
	 * @return self|WP_Error Instance if valid, WP_Error if invalid
	 */
	protected function validate() {
		// Validate operation.
		if ( empty( $this->operation ) ) {
			return new WP_Error(
				Constants::ERROR_MISSING_REQUIRED_FIELD,
				sprintf( Constants::MSG_MISSING_REQUIRED_FIELD, 'operation' ),
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		if ( ! in_array( $this->operation, self::$valid_operations, true ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_OPERATION,
				Constants::MSG_INVALID_OPERATION,
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Validate operation_type.
		if ( ! in_array( $this->operation_type, self::$valid_operation_types, true ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_OPERATION_TYPE,
				Constants::MSG_INVALID_OPERATION_TYPE,
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Validate configuration.
		if ( null !== $this->configuration && ! is_array( $this->configuration ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				Constants::MSG_INVALID_CONFIGURATION,
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Validate schedule data.
		if ( null !== $this->schedule_data && ! is_array( $this->schedule_data ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				'Invalid schedule data format.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Validate filter data.
		if ( null !== $this->filter_data && ! is_array( $this->filter_data ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				'Invalid filter data format.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Validate connection IDs.
		if ( null !== $this->connection_ids && ! is_array( $this->connection_ids ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				'Invalid connection IDs format. Must be an array.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Validate attribute mapping IDs.
		if ( null !== $this->attribute_mapping_ids && ! is_array( $this->attribute_mapping_ids ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				'Invalid attribute mapping IDs format. Must be an array.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Validate mapping to connection map.
		if ( null !== $this->mapping_to_connection_map && ! is_array( $this->mapping_to_connection_map ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				'Invalid mapping to connection map format. Must be an array.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// For schedule operations, connection_ids should not be provided since they are resolved from attribute_mapping_ids.
		if ( 'schedule' === $this->operation && null !== $this->connection_ids ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				'Connection IDs should not be provided for schedule operations. They are automatically resolved from attribute mapping IDs.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		return $this;
	}

	/**
	 * Validate update request data - only validates fields that are present
	 *
	 * @return self|WP_Error Instance if valid, WP_Error if invalid
	 */
	protected function validate_update() {
		// Operation and operation_type cannot be updated after creation.
		if ( isset( $this->original_params['operation'] ) || isset( $this->original_params['operation_type'] ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_OPERATION,
				'Operation and operation type cannot be updated after creation.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Only validate configuration if provided.
		if ( isset( $this->original_params['configuration'] ) && ! is_array( $this->configuration ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				Constants::MSG_INVALID_CONFIGURATION,
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Only validate schedule data if provided.
		if ( isset( $this->original_params['schedule_data'] ) && ! is_array( $this->schedule_data ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				'Invalid schedule data format.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Only validate filter data if provided.
		if ( isset( $this->original_params['filter_data'] ) && ! is_array( $this->filter_data ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				'Invalid filter data format.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Only validate connection IDs if provided.
		if ( isset( $this->original_params['connection_ids'] ) && ! is_array( $this->connection_ids ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				'Invalid connection IDs format. Must be an array.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Only validate attribute mapping IDs if provided.
		if ( isset( $this->original_params['attribute_mapping_ids'] ) && ! is_array( $this->attribute_mapping_ids ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_CONFIGURATION,
				'Invalid attribute mapping IDs format. Must be an array.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		return $this;
	}

	/**
	 * Convert to array for database
	 *
	 * @return array Data ready for database
	 */
	public function to_array() {
		$data = array();

		// For update requests, only include fields that were provided.
		if ( isset( $this->original_params ) ) {
			if ( isset( $this->original_params['is_active'] ) ) {
				$data['is_active'] = $this->is_active ? 1 : 0;
			}
			if ( isset( $this->original_params['configuration'] ) ) {
				$data['configuration'] = $this->configuration;
			}
			if ( isset( $this->original_params['schedule_data'] ) ) {
				$data['schedule_data'] = $this->schedule_data;
			}
			if ( isset( $this->original_params['filter_data'] ) ) {
				$data['filter_data'] = $this->filter_data;
			}
			if ( isset( $this->original_params['connection_ids'] ) ) {
				$data['connection_ids'] = $this->connection_ids;
			}
			if ( isset( $this->original_params['attribute_mapping_ids'] ) ) {
				$data['attribute_mapping_ids'] = $this->attribute_mapping_ids;
			}
			if ( isset( $this->original_params['mapping_to_connection_map'] ) ) {
				$data['mapping_to_connection_map'] = $this->mapping_to_connection_map;
			}
		} else {
			// For create requests, include all fields.
			$data = array(
				'operation_type'            => $this->operation_type,
				'operation'                 => $this->operation,
				'is_active'                 => $this->is_active ? 1 : 0,
				'configuration'             => $this->configuration,
				'schedule_data'             => $this->schedule_data,
				'filter_data'               => $this->filter_data,
				'connection_ids'            => $this->connection_ids,
				'attribute_mapping_ids'     => $this->attribute_mapping_ids,
				'mapping_to_connection_map' => $this->mapping_to_connection_map,
			);
		}
		return $data;
	}
}
