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

namespace MOWCPS\Common\Utils;

use WP_Error;
use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Constants\Plugin_Filters;
use MOWCPS\Common\Suppliers\Promostandards_Sanmar_Ca;

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

/**
 * Class Configuration_Loader
 *
 * Loads and processes supplier configurations from JSON files
 */
class Configuration_Loader {

	/**
	 * Load supplier configuration from JSON file
	 *
	 * @param string $supplier_type Supplier type (e.g., 'amrod', 'shopify', 'promostandards-sanmar).
	 * @return array|WP_Error Configuration array or error.
	 */
	public static function load_supplier_config( $supplier_type ) {
		if ( empty( $supplier_type ) ) {
			return new WP_Error(
				Constants::ERROR_MISSING_REQUIRED_FIELD,
				sprintf( Constants::SUPPLIER_MISSING_APP_TYPE, $supplier_type ),
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		$config_file = self::get_config_file_path( $supplier_type );

		if ( ! file_exists( $config_file ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_SUPPLIER_TYPE,
				sprintf( Constants::SUPPLIER_CONFIG_NOT_FOUND, $supplier_type ),
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		$config_content = file_get_contents( $config_file );
		if ( false === $config_content ) {
			return new WP_Error(
				Constants::ERROR_INVALID_SUPPLIER_TYPE,
				sprintf( Constants::SUPPLIER_CONFIG_LOADING_FAILED, $supplier_type ),
				array( 'status' => Constants::HTTP_INTERNAL_SERVER_ERROR )
			);
		}

		$config = json_decode( $config_content, true );
		if ( null === $config ) {
			return new WP_Error(
				Constants::ERROR_INVALID_SUPPLIER_TYPE,
				sprintf( Constants::SUPPLIER_INVALID_JSON, $supplier_type ),
				array( 'status' => Constants::HTTP_INTERNAL_SERVER_ERROR )
			);
		}

		// Expand Promostandards Sanmar CA fragment templates (`Connections`, compact attribute_mapping) onto promostandards.json.
		if ( Constants::SUPPLIER_APP_TYPE_PROMOSTANDARDS_SANMAR_CA === $supplier_type && is_array( $config ) && ! empty( $config['Connections'] ) ) {
			$base_config = self::load_supplier_config( 'promostandards' );
			if ( ! is_wp_error( $base_config ) ) {
				$config = Promostandards_Sanmar_Ca::merge_promostandards_sanmar_ca_overlay( $base_config, $config );
			}
		}

		return $config;
	}

	/**
	 * Process URL query parameters and build the complete URL.
	 * Handles dynamic parameter replacement and properly encodes parameter values.
	 *
	 * @param string $base_url Base URL without query parameters.
	 * @param array  $query_params Query parameters to process.
	 * @param array  $params Dynamic parameters for replacement.
	 * @return string Complete URL with encoded query parameters.
	 */
	private static function process_query_params( $base_url, $query_params, $params ) {
		if ( empty( $query_params ) ) {
			return $base_url;
		}

		$processed_params = array();
		foreach ( $query_params as $key => $value ) {
			// Handle dynamic parameter replacement.
			if ( is_string( $value ) && strpos( $value, '<' ) !== false && strpos( $value, '>' ) !== false ) {
				$param_name = trim( $value, '<>' );
				if ( isset( $params[ $param_name ] ) ) {
					$value = $params[ $param_name ];
				}
			}
			$processed_params[ $key ] = $value;
		}

		// Build URL with encoded parameters using http_build_query.
		$query = http_build_query( $processed_params, '', '&', PHP_QUERY_RFC3986 );
		return $base_url . ( ! empty( $query ) ? '?' . $query : '' );
	}

	/**
	 * Process configuration with dynamic parameters.
	 *
	 * @param array  $config Configuration array.
	 * @param array  $dynamic_params Dynamic parameters to replace.
	 * @param string $supplier_id Optional supplier ID for placeholder replacement.
	 * @return array Processed configuration.
	 */
	public static function process_configuration( $config, $dynamic_params = array(), $supplier_id = '' ) {
		// Add default parameters if not provided.
		$default_params = array(
			'start_time' => gmdate( 'Y-m-d H:i:s' ),
		);

		// Merge with provided parameters, letting provided ones override defaults.
		$params = array_merge( $default_params, $dynamic_params );

		// Add supplier_id to params if provided.
		if ( ! empty( $supplier_id ) ) {
			$params['supplier_id'] = $supplier_id;
		}

		// Create a deep copy of the config to modify.
		$processed_config = json_decode( wp_json_encode( $config ), true );

		// Process authorization query parameters if they exist.
		if ( isset( $processed_config['authorization']['auth_settings']['request_settings'] ) ) {
			$auth_settings = &$processed_config['authorization']['auth_settings']['request_settings'];
			if ( isset( $auth_settings['url'] ) && isset( $auth_settings['query_params'] ) ) {
				$auth_settings['url'] = self::process_query_params(
					$auth_settings['url'],
					$auth_settings['query_params'],
					$params
				);
				// Remove query_params since they are now part of the URL.
				unset( $auth_settings['query_params'] );
			}
		}

		// Process connection query parameters if they exist.
		if ( isset( $processed_config['connections'] ) ) {
			foreach ( $processed_config['connections'] as &$connection ) {
				if ( isset( $connection['configuration'] ) ) {
					$config = &$connection['configuration'];
					if ( isset( $config['endpoint'] ) && isset( $config['query_params'] ) ) {
						$config['endpoint'] = self::process_query_params(
							$config['endpoint'],
							$config['query_params'],
							$params
						);
						// Remove query_params since they are now part of the URL.
						unset( $config['query_params'] );
					}
				}
			}
		}

		// Alter dyncmic params before saving.
		if ( has_filter( Plugin_Filters::FILTER_ALTER_DYNAMIC_PARAMS ) ) {
			$returned_data = apply_filters(
				Plugin_Filters::FILTER_ALTER_DYNAMIC_PARAMS,
				array(
					'event_specifier' => Plugin_Filters::EVENT_ALTER_DYNAMIC_PARAMS,
					'dynamic_params'  => $params,
					'is_test'         => true,
				)
			);

			$params = $returned_data['dynamic_params'];
		}

		// Process remaining dynamic parameters in the entire config.
		$final_config = self::replace_dynamic_parameters( $processed_config, $params );

		if ( ! empty( $params['connection_body_overrides'] ) && is_array( $params['connection_body_overrides'] ) ) {
			$final_config = self::apply_promostandards_connection_body_overrides( $final_config, $params );
		}

		return $final_config ? $final_config : $config;
	}

	/**
	 * Apply Promostandards supplier-specific SOAP bodies from JSON (*_body keys) to connections and outbound operations.
	 *
	 * @param array $config Processed configuration (after placeholder replacement).
	 * @param array $params Dynamic parameters including connection_body_overrides and credentials.
	 * @return array Updated configuration.
	 */
	private static function apply_promostandards_connection_body_overrides( array $config, array $params ) {
		$overrides = $params['connection_body_overrides'] ?? array();
		if ( empty( $overrides ) ) {
			return $config;
		}

		// Run credential placeholders through the same replacement pass used for the main template.
		$processed_overrides = array();
		foreach ( $overrides as $connection_name => $body_xml ) {
			if ( ! is_string( $body_xml ) ) {
				continue;
			}
			$wrapped       = array( '__promostandards_body' => $body_xml );
			$replaced      = self::replace_dynamic_parameters( $wrapped, $params );
			$processed_overrides[ $connection_name ] = is_array( $replaced ) && isset( $replaced['__promostandards_body'] ) ? $replaced['__promostandards_body'] : $body_xml;
		}

		if ( ! empty( $config['connections'] ) && is_array( $config['connections'] ) ) {
			foreach ( $config['connections'] as &$connection ) {
				$name = $connection['name'] ?? '';
				if ( '' === $name || ! isset( $processed_overrides[ $name ] ) ) {
					continue;
				}
				if ( isset( $connection['configuration']['body'] ) && is_array( $connection['configuration']['body'] ) ) {
					$connection['configuration']['body']['data'] = $processed_overrides[ $name ];
				}
			}
			unset( $connection );
		}

		if ( ! empty( $config['operations'] ) && is_array( $config['operations'] ) ) {
			foreach ( $config['operations'] as &$operation ) {
				if ( 'outbound' !== ( $operation['operation'] ?? '' ) ) {
					continue;
				}
				$op_connections = $operation['connections'] ?? array();
				if ( ! is_array( $op_connections ) || 1 !== count( $op_connections ) ) {
					continue;
				}
				$cname = $op_connections[0];
				if ( '' === $cname || ! isset( $processed_overrides[ $cname ] ) ) {
					continue;
				}
				$textarea = $processed_overrides[ $cname ];
				if ( strpos( $textarea, '{|SKU|}' ) === false && strpos( $textarea, 'OG500' ) !== false ) {
					$textarea = str_replace( 'OG500', '{|SKU|}', $textarea );
				}
				if ( isset( $operation['configuration']['position']['data'] ) && is_array( $operation['configuration']['position']['data'] ) ) {
					foreach ( $operation['configuration']['position']['data'] as &$item ) {
						if ( isset( $item['textarea'] ) ) {
							$item['textarea'] = $textarea;
						}
					}
					unset( $item );
				}
			}
			unset( $operation );
		}

		return $config;
	}

	/**
	 * Replace dynamic parameters in configuration data
	 *
	 * @param array $config Configuration array or data to process.
	 * @param array $dynamic_params Dynamic parameters to replace.
	 * @return array Processed configuration with parameters replaced.
	 */
	public static function replace_dynamic_parameters( $config, $dynamic_params ) {
		// Convert config to JSON string for replacement.
		$config_json = wp_json_encode( $config );

		foreach ( $dynamic_params as $param => $value ) {
			if ( 'country' === $param ) {
				// Special handling for country parameter: 'CA' becomes '-ca.', others become '.'.
				$value       = Constants::COUNTRY_CA === $value ? '-ca.' : '.';
				$config_json = str_replace( '<' . $param . '>', $value, $config_json );
			} elseif ( ! is_array( $value ) ) {
				// Replace both ##<param>## and <param> formats.
				$config_json = str_replace( '##<' . $param . '>##', '##' . $value . '##', $config_json );
				$config_json = str_replace( '<' . $param . '>', $value, $config_json );
			}
		}

		$final_config = json_decode( $config_json, true );

		return $final_config ? $final_config : $config;
	}

	/**
	 * Get configuration file path
	 *
	 * @param string $supplier_name Supplier name.
	 * @return string Configuration file path.
	 */
	private static function get_config_file_path( $supplier_name ) {
		$plugin_dir = plugin_dir_path( dirname( dirname( __DIR__ ) ) );
		return $plugin_dir . 'resources/supplier-data/' . sanitize_file_name( $supplier_name ) . '.json';
	}

	/**
	 * Get all available supplier configurations
	 *
	 * @return array Array of available supplier names.
	 */
	public static function get_available_suppliers() {
		$plugin_dir = plugin_dir_path( dirname( dirname( __DIR__ ) ) );
		$config_dir = $plugin_dir . 'resources/supplier-data/';

		$suppliers = array();

		if ( is_dir( $config_dir ) ) {
			$files = glob( $config_dir . '*.json' );
			foreach ( $files as $file ) {
				$filename = basename( $file, '.json' );
				if ( 'index' !== $filename ) {
					$suppliers[] = $filename;
				}
			}
		}

		return $suppliers;
	}

	/**
	 * Validate configuration structure
	 *
	 * @param array $config Configuration to validate.
	 * @return bool|WP_Error True if valid, WP_Error if invalid.
	 */
	public static function validate_configuration( $config ) {
		// Check for basic required fields.
		$required_fields = array( 'name', 'app_type' );

		foreach ( $required_fields as $field ) {
			if ( ! isset( $config[ $field ] ) ) {
				return new WP_Error(
					Constants::ERROR_INVALID_SUPPLIER_CONFIG,
					sprintf( Constants::SUPPLIER_MISSING_REQUIRED_FIELD, $field ),
					array( 'status' => Constants::HTTP_BAD_REQUEST )
				);
			}
		}

		return true;
	}
}
