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

namespace MOWCPS\Common\Handlers\Rest_API;

use WP_Error;
use MOWCPS\Common\Models\Setting_Model;
use MOWCPS\Common\Models\Supplier_Model;
use MOWCPS\Common\Models\Connection_Model;
use MOWCPS\Common\Models\Attribute_Mapping_Model;
use MOWCPS\Common\DTO\Setting_Request;
use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Constants\Plugin_Filters;
use MOWCPS\Common\Utils\Model_Utils;
use MOWCPS\Common\Utils\Sync_Utils;

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

/**
 * Class Setting_Handler
 *
 * Handles settings REST API operations for all setting types
 */
class Setting_Handler {

	/**
	 * Constructor
	 */
	public function __construct() {
	}

	/**
	 * Get all settings by type for a supplier
	 *
	 * @param string $supplier_uuid Supplier UUID.
	 * @param string $type Setting type.
	 * @param array  $params Query parameters.
	 * @return array|WP_Error
	 */
	public function get_all_by_type( $supplier_uuid, $type, $params = array() ) {
		// Validate UUID parameter using DTO.
		$validation = Setting_Request::validate_uuid( $supplier_uuid, 'supplier_uuid' );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		$supplier = Supplier_Model::get_by_uuid( $supplier_uuid );
		if ( ! $supplier ) {
			return new WP_Error(
				Constants::ERROR_SUPPLIER_NOT_FOUND,
				Constants::MSG_SUPPLIER_NOT_FOUND,
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		$params['supplier_id'] = $supplier['id'];
		$params['type']        = $type;

		$settings = Setting_Model::get_all( $params );

		// Handle premium-specific enhancements using filter.
		if ( has_filter( Plugin_Filters::FILTER_SETTING_HANDLER_OPERATIONS ) ) {
			$filter_result = apply_filters(
				Plugin_Filters::FILTER_SETTING_HANDLER_OPERATIONS,
				array(
					'event_specifier' => Plugin_Filters::EVENT_HANDLE_SETTING_GET_ALL_ENHANCEMENT,
					'type'            => $type,
					'settings'        => $settings,
					'params'          => $params,
				)
			);
			if ( isset( $filter_result['settings'] ) ) {
				$settings = $filter_result['settings'];
			}
		}

		// Remove ID fields from API response and return sanitized data.
		return Model_Utils::sanitize_for_api_response( $settings );
	}

	/**
	 * Get setting by UUID
	 *
	 * @param string $setting_uuid Setting UUID.
	 * @return array|WP_Error
	 */
	public function get_by_uuid( $setting_uuid ) {
		// Validate UUID parameter using DTO.
		$validation = Setting_Request::validate_uuid( $setting_uuid, 'setting_uuid' );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		$setting = Setting_Model::get_by_uuid( $setting_uuid );
		if ( ! $setting ) {
			return new WP_Error(
				Constants::ERROR_RECORD_NOT_FOUND,
				Constants::MSG_RECORD_NOT_FOUND,
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		// Remove ID fields from API response and return sanitized data.
		return Model_Utils::sanitize_for_api_response( $setting );
	}

	/**
	 * Create setting for a supplier
	 *
	 * @param string|int $supplier_identifier Supplier UUID or ID.
	 * @param string     $type Setting type.
	 * @param array      $data Setting data.
	 * @return array|WP_Error
	 */
	public function create( $supplier_identifier, $type, $data ) {
		$identifier_info = Model_Utils::identify_identifier( $supplier_identifier );
		if ( is_wp_error( $identifier_info ) ) {
			return $identifier_info;
		}

		if ( 'id' === $identifier_info['type'] ) {
			$supplier_id = $identifier_info['value'];
		} else {
			$supplier = Supplier_Model::get_by_uuid( $identifier_info['value'] );
			if ( ! $supplier ) {
				return new WP_Error(
					Constants::ERROR_SUPPLIER_NOT_FOUND,
					Constants::MSG_SUPPLIER_NOT_FOUND,
					array( 'status' => Constants::HTTP_NOT_FOUND )
				);
			}
			$supplier_id = $supplier['id'];
		}

		if ( Constants::FILTER === $type ) {
			$connection_validation = Sync_Utils::validate_filter_connections_not_used_in_other_filters(
				$supplier_id,
				$data['connection_ids'] ?? array()
			);
			if ( is_wp_error( $connection_validation ) ) {
				return $connection_validation;
			}
		}

		// Add operation type to data for validation.
		$data['operation'] = $type;

		// Transform and validate data using DTO.
		$setting_request = Setting_Request::from_request_parameters( $data );
		if ( is_wp_error( $setting_request ) ) {
			return $setting_request;
		}

		// Add supplier_id to the validated data.
		$validated_data                = $setting_request->to_array();
		$validated_data['supplier_id'] = $supplier_id;

		// Convert connection_ids from UUIDs to integer IDs if provided.
		if ( isset( $data['connection_ids'] ) && is_array( $data['connection_ids'] ) ) {
			$connection_ids = array();
			foreach ( $data['connection_ids'] as $connection_uuid ) {
				$connection = Connection_Model::get_by_uuid( $connection_uuid );
				if ( ! $connection ) {
					return new WP_Error(
						Constants::ERROR_CONNECTION_NOT_FOUND,
						sprintf( Constants::MSG_CONNECTION_NOT_FOUND . ' UUID: %s', $connection_uuid ),
						array( 'status' => Constants::HTTP_NOT_FOUND )
					);
				}
				$connection_ids[] = $connection['id'];
			}
			$validated_data['connection_ids'] = $connection_ids;
		}

		// Convert attribute_mapping_ids from UUIDs to integer IDs if provided.
		if ( isset( $data['attribute_mapping_ids'] ) && is_array( $data['attribute_mapping_ids'] ) ) {
			$attribute_mapping_ids = array();
			foreach ( $data['attribute_mapping_ids'] as $mapping_uuid ) {
				$mapping = Attribute_Mapping_Model::get_by_uuid( $mapping_uuid );
				if ( ! $mapping ) {
					return new WP_Error(
						Constants::ERROR_RECORD_NOT_FOUND,
						sprintf( Constants::MSG_RECORD_NOT_FOUND . ' Attribute Mapping UUID: %s', $mapping_uuid ),
						array( 'status' => Constants::HTTP_NOT_FOUND )
					);
				}
				$attribute_mapping_ids[] = $mapping['id'];
			}
			$validated_data['attribute_mapping_ids'] = $attribute_mapping_ids;
		}

		// Convert supplier UUIDs to IDs in configuration for outbound operations.
		if ( isset( $validated_data['configuration'] ) && 'outbound' === $validated_data['operation'] ) {
			$validated_data = Model_Utils::convert_supplier_uuids_to_ids_in_config( $validated_data );
		}

		$result = Setting_Model::create( $validated_data );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		// Remove ID fields from API response and return sanitized data.
		return Model_Utils::sanitize_for_api_response( $result );
	}

	/**
	 * Update setting
	 *
	 * @param string $setting_uuid Setting UUID.
	 * @param array  $data Setting data.
	 * @return array|WP_Error
	 */
	public function update( $setting_uuid, $data ) {
		// Validate UUID parameter using DTO.
		$validation = Setting_Request::validate_uuid( $setting_uuid, 'setting_uuid' );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		// Get existing setting to determine operation type.
		$existing = Setting_Model::get_by_uuid( $setting_uuid );
		if ( ! $existing ) {
			return new WP_Error(
				Constants::ERROR_RECORD_NOT_FOUND,
				Constants::MSG_RECORD_NOT_FOUND,
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		$operation_type = $existing['operation'];

		if ( Constants::FILTER === $operation_type && isset( $data['connection_ids'] ) && is_array( $data['connection_ids'] ) ) {
			$existing_connection_uuids = array();
			if ( isset( $existing['connections'] ) && is_array( $existing['connections'] ) ) {
				$existing_connection_uuids = array_map(
					function ( $connection ) {
						return $connection['uuid'] ?? '';
					},
					$existing['connections']
				);
			}

			$connection_validation = Sync_Utils::validate_filter_connections_not_used_in_other_filters(
				intval( $existing['supplier_id'] ?? 0 ),
				$data['connection_ids'],
				$setting_uuid,
				$existing_connection_uuids
			);
			if ( is_wp_error( $connection_validation ) ) {
				return $connection_validation;
			}
		}

		// Transform and validate data using DTO for partial updates.
		if ( ! empty( $data ) ) {
			$setting_request = Setting_Request::from_update_parameters( $data );
			if ( is_wp_error( $setting_request ) ) {
				return $setting_request;
			}
			$data = $setting_request->to_array();
		}

		// Handle different operation types.
		if ( 'schedule' === $operation_type && isset( $data['schedule_data'] ) ) {
			$data['schedule_data'] = $data['schedule_data'];
		} elseif ( Constants::FILTER === $operation_type && isset( $data['filter_data'] ) ) {
			$data['filter_data'] = $data['filter_data'];
		}

		// Convert supplier UUIDs to IDs in configuration for outbound operations.
		if ( isset( $data['configuration'] ) && 'outbound' === $operation_type ) {
			$data = Model_Utils::convert_supplier_uuids_to_ids_in_config( $data );
		}

		$result = Setting_Model::update( $setting_uuid, $data );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		// Remove ID fields from API response and return sanitized data.
		return Model_Utils::sanitize_for_api_response( $result );
	}

	/**
	 * Delete setting
	 *
	 * @param string $setting_uuid Setting UUID.
	 * @return bool|WP_Error
	 */
	public function delete( $setting_uuid ) {
		// Validate UUID parameter using DTO.
		$validation = Setting_Request::validate_uuid( $setting_uuid, 'setting_uuid' );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		return Setting_Model::delete( $setting_uuid );
	}
}
