<?php

namespace Simplyin\Simplyin_W_Plugin\Admin;

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

use Simplyin\Simplyin_W_Plugin\Admin\Template_Components\Select;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Integration\Integration_Interface;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Mapping;
use Simplyin\Simplyin_W_Plugin\Shipping_Mapping\Simplyin\Simplyin_Method_Interface;

class Shipping_Mapping_Options {

	private Mapping $shipping_mapping;

	/**
	 * @var Select[]|null
	 */
	private static ?array $shipping_mapping_fields = null;


	public function __construct( ?Mapping $mapping = null ) {
		if ( $mapping ) {
			$this->shipping_mapping = $mapping;
		} else {
			$this->shipping_mapping = new Mapping();

		}
	}


	/**
	 * Returns a flat array of all Select objects: global selects first, then zone-specific selects.
	 * Used by rebuild_mapping() and as source for get_grouped_shipping_mapping_fields().
	 *
	 * @return Select[]
	 */
	public function get_shipping_mapping_fields( bool $force_regenerate = false ): array {

		if ( self::$shipping_mapping_fields && ! $force_regenerate ) {
			return self::$shipping_mapping_fields;
		}

		$mapping = $this->shipping_mapping;
		$this->shipping_mapping->build_mapping();

		$selects                 = [];
		$integrations_for_widget = [];

		foreach ( $mapping->get_mapping_items() as $mapping_item ) {
			$select = new Select();
			$select->set_option_id(
				$mapping_item->get_simplyin_method()
												->get_id()
			);
			$select_name = $this->build_select_name( $mapping_item->get_simplyin_method() );
			$select->set_name( $select_name );
			$select->set_label(
				$mapping_item->get_simplyin_method()
											->get_title()
			);
			$select->set_multiple( false );
			$options = [];

			foreach ( $mapping_item->get_integrations() as $integration ) {
				$option_key = $this->build_option_key( $integration );
				if ( ! isset( $integrations_for_widget[ $mapping_item->get_simplyin_method()->get_id() ][ $option_key ] ) ) {
					$integrations_for_widget[ $mapping_item
						->get_simplyin_method()
						->get_id() ][ $option_key ] = $integration->to_array();
				}
				$options[ $option_key ] = $integration->get_title();
			}

			if ( empty( $options ) ) {
				continue;
			}

			$options = [
				'none' => __(
					'None',
					'simplyin'
				),
			] + $options;

			$value = $this->get_mapping_value( $select_name );
			$select->set_selected_options( $value ? [ $value ] : [] );
			$select->set_available_options( $options );
			$selects[] = $select;
		}

		$this->save_integrations( $integrations_for_widget );

		foreach ( $this->shipping_mapping->get_shipping_zones() as $zone ) {
			$zone_id = $zone->get_id();

			foreach ( $this->shipping_mapping->get_mapping_items_for_zone( $zone ) as $mapping_item ) {
				if ( empty( $mapping_item->get_integrations() ) ) {
					continue;
				}

				$simplyin_method = $mapping_item->get_simplyin_method();
				$select          = new Select();
				$cache_key       = sprintf( '%s_zone_%d', $simplyin_method->get_id(), $zone_id );
				$select_name     = $this->build_select_name( $simplyin_method, $zone_id );

				$select->set_option_id( $cache_key );
				$select->set_name( $select_name );
				$select->set_label( $simplyin_method->get_title() );
				$select->set_multiple( false );

				$options = [ 'none' => __( 'None', 'simplyin' ) ];
				foreach ( $mapping_item->get_integrations() as $integration ) {
					$option_key             = $this->build_option_key( $integration );
					$options[ $option_key ] = $integration->get_title();
				}

				$value = $this->get_mapping_value( $select_name );
				$select->set_selected_options( $value ? [ $value ] : [] );
				$select->set_available_options( $options );
				$selects[] = $select;
			}
		}

		self::$shipping_mapping_fields = $selects;

		return $selects;
	}

	/**
	 * Returns selects grouped by WooCommerce shipping zone for the admin template.
	 * Zone_0 (Rest of the World / default zone) is always included and listed first.
	 *
	 * @return array{zones: array<int, array{zone_id: int, zone_name: string, is_default: bool, selects: Select[]}>}
	 */
	public function get_grouped_shipping_mapping_fields(): array {
		$all_selects = $this->get_shipping_mapping_fields();
		$grouped     = [ 'zones' => [] ];

		foreach ( $this->shipping_mapping->get_shipping_zones() as $zone ) {
			$zone_id = $zone->get_id();
			$suffix  = "_zone_{$zone_id}";

			$zone_selects = array_values(
				array_filter(
					$all_selects,
					function ( $s ) use ( $suffix ) {
						$id = $s->get_option_id();

						return substr( $id, - strlen( $suffix ) ) === $suffix;
					}
				)
			);

			if ( empty( $zone_selects ) ) {
				continue;
			}

			$grouped['zones'][ $zone_id ] = [
				'zone_id'    => $zone_id,
				'zone_name'  => $zone->get_zone_name(),
				'is_default' => ( $zone_id === 0 ),
				'selects'    => $zone_selects,
			];
		}

		return $grouped;
	}


	private function save_integrations( array $integrations_for_widget ): void {
		simplyin()->update_option(
			'SimplyInShippingIntegrations',
			$integrations_for_widget,
			'shipping_mapping'
		);
	}

	public function get_mapping_cache(): array {
		return (array) get_option( 'SimplyInShippingMappingCache' );
	}

	private function rebuild_mapping_cache(
		string $option_id,
		?string $new_value
	): void {
		$cache = (array) get_option( 'SimplyInShippingMappingCache' );
		$cache = array_filter( $cache );

		simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
			sprintf(
				'[rebuild_mapping_cache] %s',
				wp_json_encode(
					[
						'new_value' => $new_value,
						'option_id' => $option_id,
					]
				),
			),
			'shipping_mapping'
		);

		if ( ! $new_value ) {

			if ( isset( $cache[ $option_id ] ) ) {
				unset( $cache[ $option_id ] );

			} else {
				return;
			}
		} else {
			$cache[ $option_id ] = $new_value;
		}

		simplyin()->update_option(
			'SimplyInShippingMappingCache',
			$cache,
			'shipping_mapping'
		);
	}

	public function register_settings(): void {

		foreach ( $this->shipping_mapping->get_available_simplyin_methods() as $simplyin_method ) {
			$simplyin_method_id = $simplyin_method->get_id();
			$option_id          = $this->build_select_name( $simplyin_method );

			register_setting(
				'simply_settings_main',
				$option_id,
				[
					'type'              => 'string',
					'sanitize_callback' => 'sanitize_text_field',
				]
			);

			add_action(
				sprintf(
					'update_option_%s',
					$option_id
				),
				function (
					$old_value,
					$new_value
				) use (
					$simplyin_method_id,
					$option_id
				) {
					$val = is_string( $new_value ) && '' !== $new_value ? $new_value : null;
					$this->rebuild_mapping_cache(
						$simplyin_method_id,
						$val
					);
				},
				10,
				2
			);
		}

		// Register per-zone options.
		foreach ( $this->shipping_mapping->get_shipping_zones() as $zone ) {
			$zone_id = $zone->get_id();

			foreach ( $this->shipping_mapping->get_available_simplyin_methods() as $simplyin_method ) {
				$simplyin_method_id = $simplyin_method->get_id();
				$option_name        = $this->build_select_name( $simplyin_method, $zone_id );
				$cache_key          = "{$simplyin_method_id}_zone_{$zone_id}";

				register_setting(
					'simply_settings_main',
					$option_name,
					[
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					]
				);

				add_action(
					"update_option_{$option_name}",
					function ( $old_value, $new_value ) use ( $cache_key ) {
						// Empty string = "use global" → don't store in cache.
						$val = is_string( $new_value ) && '' !== $new_value ? $new_value : null;
						$this->rebuild_mapping_cache( $cache_key, $val );
					},
					10,
					2
				);
			}
		}
	}

	public function rebuild_mapping() {
		simplyin()->update_option(
			'SimplyInShippingMappingCache',
			[]
		);

		$shipping_mapping_fields = $this->get_shipping_mapping_fields();

		foreach ( $shipping_mapping_fields as $select ) {
			$option_id = $select->get_option_id();
			$this->rebuild_mapping_cache(
				$option_id,
				get_option( $select->get_name() ) ?: null
			);
		}
	}

	private function get_mapping_value( $option_name ): ?string {
		$result = get_option( $option_name );

		return $result ?: null;
	}

	private function build_option_key( Integration_Interface $integration ): string {
		return sprintf(
			'%s_%s',
			$integration->get_method(),
			$integration->get_instance_id()
		);
	}

	private function build_select_name(
		Simplyin_Method_Interface $simplyin_method,
		?int $zone_id = null
	): string {
		if ( $zone_id !== null ) {
			return sprintf(
				'simply_%s_zone_%d_mapping',
				$simplyin_method->get_id(),
				$zone_id
			);
		}

		return sprintf(
			'simply_%s_mapping',
			$simplyin_method->get_id()
		);
	}


	public function render_fields( array $args ) {

		simplyin()->locate_template(
			'shipping_mapping.php',
			[ 'args' => $args ],
			'src/Admin/partials'
		);
	}
}
