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

namespace MOWCPS\Common\Suppliers;

use WP_Error;
use MOWCPS\Common\Abstracts\Base_Supplier_App;
use MOWCPS\Common\Interfaces\Supplier_App_Interface;
use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Constants\Plugin_Filters;
use MOWCPS\Common\Services\API\API_Service;
use MOWCPS\Common\Services\Authorization\Authorization_Service;
use MOWCPS\Common\Utils\Utils;

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

/**
 * Class Midocean
 *
 * Handles Midocean supplier app operations
 */
class Midocean extends Base_Supplier_App implements Supplier_App_Interface {
	/**
	 * Constructor
	 */
	public function __construct() {
		parent::__construct( Constants::SUPPLIER_APP_TYPE_MIDOCEAN );
	}

	/**
	 * Perform Midocean-specific connection test
	 *
	 * @param array $supplier_data Supplier data.
	 * @return array Test result.
	 */
	public function perform_connection_test( $supplier_data ) {
		// Validate supplier-specific configuration using existing validation method.
		$validation_result = $this->validate_supplier_specific_configuration( $supplier_data );
		if ( is_wp_error( $validation_result ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_AUTH_FAILED, $this->supplier_name, $validation_result->get_error_message() ),
			);
		}

		// Load and process configuration with dynamic parameters.
		$processed_config = $this->load_and_process_configuration( $supplier_data );
		if ( is_wp_error( $processed_config ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_CONFIG_LOADING_FAILED, $this->supplier_name, $processed_config->get_error_message() ),
			);
		}

		// Get authorization configuration.
		$authorization = $processed_config[ Constants::AUTHORIZATION ] ?? array();

		$auth_service = new Authorization_Service();
		$headers      = $auth_service->generate_headers( $authorization, 0 );

		if ( is_wp_error( $headers ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_AUTH_FAILED, $this->supplier_name, $headers->get_error_message() ),
			);
		}

		// Test with the highest priority connection (0 or 1).
		$connections     = $processed_config['connections'] ?? array();
		$test_connection = $this->find_test_connection( $connections );

		if ( empty( $test_connection ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_NO_TEST_ENDPOINT, $this->supplier_name ),
			);
		}

		$config   = $test_connection['configuration'];
		$endpoint = $config['endpoint'];
		$method   = $config['method'];
		$headers  = array_merge( $headers, $config['headers'] );
		$body     = $config['body'];

		if ( empty( $endpoint ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_NO_TEST_ENDPOINT_AVAILABLE, $this->supplier_name ),
			);
		}

		// Prepare API request.
		$api_request = array(
			'endpoint' => $endpoint,
			'method'   => $method,
			'headers'  => $headers,
			'body'     => $body,
			'timeout'  => 600,
		);

		// Make the authentication request.
		$response = API_Service::make_api_call( $api_request['endpoint'], $api_request );

		$response_code    = wp_remote_retrieve_response_code( $response );
		$response_message = wp_remote_retrieve_response_message( $response );
		$response_body    = json_decode( wp_remote_retrieve_body( $response ), true );

		if ( is_wp_error( $response ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_AUTH_FAILED, $this->supplier_name, $response->get_error_message() ),
				$response_code,
				$response_body,
			);
		}

		if ( ! Utils::is_status_success( $response ) ) {
			return $this->get_test_result(
				false,
				sprintf( Constants::SUPPLIER_AUTH_FAILED, $this->supplier_name, $response_message ),
				$response_code,
				$response_body,
			);
		}

		return $this->get_test_result(
			true,
			sprintf( Constants::SUPPLIER_AUTH_SUCCESSFUL, $this->supplier_name ),
			$response_code,
			$response_body,
		);
	}

	/**
	 * Validate Midocean-specific configuration
	 *
	 * @param array $supplier_data Supplier data to validate.
	 * @return bool|WP_Error True if valid, WP_Error if invalid.
	 */
	public function validate_supplier_specific_configuration( $supplier_data ) {
		// Validate required fields for Midocean.
		if ( empty( $supplier_data['api_key'] ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_SUPPLIER_CONFIG,
				sprintf( Constants::SUPPLIER_MISSING_API_KEY, $this->supplier_name ),
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		return true;
	}

	/**
	 * Transform product data for category structure.
	 *
	 * @param array $data API data.
	 * @return array
	 */
	public static function transform_product_data( $data ) {
		if ( ! isset( $data['event_specifier'] ) || Plugin_Filters::EVENT_ALTER_PRODUCTS_CATEGORY !== $data['event_specifier'] ) {
			return $data;
		}
		if ( ! empty( $data['categories'] ) ) {
			$slugs = self::create_and_build_category_hierarchy( $data['categories'] );
			if ( ! empty( $slugs ) ) {
				$data['categories'] = $slugs;
			}
		}
		return $data;
	}

	/**
	 * Create categories and return slugs.
	 *
	 * @param array $categories Parent => children structure.
	 * @return array
	 */
	private static function create_and_build_category_hierarchy( $categories ) {
		if ( ! is_array( $categories ) || empty( $categories ) ) {
			return array();
		}

		$name_to_slug_map = array();
		$processed        = array();
		$all_values       = array();
		foreach ( $categories as $children ) {
			foreach ( array_values( (array) $children ) as $val ) {
				if ( ! empty( $val ) && is_string( $val ) ) {
					$all_values[] = $val;
				}
			}
		}
		$all_keys  = array_keys( $categories );
		$top_level = array_values( array_diff( $all_keys, $all_values ) );
		if ( empty( $top_level ) && ! empty( $all_keys ) ) {
			$top_level = array( $all_keys[0] );
		}
		if ( empty( $top_level ) ) {
			return array();
		}

		$queue = array();
		foreach ( $top_level as $name ) {
			$queue[] = array( 'name' => $name, 'parent_id' => 0, 'parent_slug' => '' );
		}

		while ( ! empty( $queue ) ) {
			$item = array_shift( $queue );
			$name = $item['name'];
			if ( isset( $processed[ $name ] ) ) {
				continue;
			}
			$processed[ $name ] = true;

			$slug_part      = sanitize_title( $name );
			$composite_slug = $item['parent_slug'] ? $item['parent_slug'] . '_' . $slug_part : $slug_part;
			$name_to_slug_map[ $name ] = $composite_slug;

			$term_id = self::create_or_get_product_category( $name, $composite_slug, $item['parent_id'] );
			if ( $term_id <= 0 ) {
				continue;
			}

			$children = isset( $categories[ $name ] ) ? array_values( (array) $categories[ $name ] ) : array();
			foreach ( $children as $child_name ) {
				if ( ! empty( $child_name ) && is_string( $child_name ) && ! isset( $processed[ $child_name ] ) ) {
					$queue[] = array( 'name' => $child_name, 'parent_id' => $term_id, 'parent_slug' => $composite_slug );
				}
			}
		}

		$all_slugs = array_values( $name_to_slug_map );
		return empty( $all_slugs ) ? array() : array( 0 => $all_slugs );
	}

	/**
	 * Create or get product category.
	 *
	 * @param string $category_name  Name.
	 * @param string $composite_slug Slug.
	 * @param int    $parent_term_id Parent ID (0 for top-level).
	 * @return int Term ID or 0.
	 */
	private static function create_or_get_product_category( $category_name, $composite_slug, $parent_term_id = 0 ) {
		$term = get_term_by( 'slug', $composite_slug, 'product_cat' );
		if ( $term && ! is_wp_error( $term ) ) {
			if ( $term->parent !== $parent_term_id ) {
				wp_update_term( $term->term_id, 'product_cat', array( 'parent' => $parent_term_id ) );
			}
			return $term->term_id;
		}

		$result = wp_insert_term( $category_name, 'product_cat', array( 'slug' => $composite_slug, 'parent' => $parent_term_id ) );
		if ( ! is_wp_error( $result ) ) {
			return $result['term_id'];
		}
		if ( 'term_exists' === $result->get_error_code() ) {
			$id = (int) $result->get_error_data( 'term_exists' );
			wp_update_term( $id, 'product_cat', array( 'slug' => $composite_slug, 'parent' => $parent_term_id ) );
			return $id;
		}
		return 0;
	}
}
