<?php

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

/**
 * Resolves natural-language option changes against one selected live product.
 *
 * The model handles multilingual intent and contrast; the backend accepts only
 * an exact group/value pair declared by WooCommerce for that product.
 */
class Niwa_AI_Frontend_Selected_Product_Option_Resolver {
	/** @var Niwa_AI_AI_Client_Interface */
	private $client;

	public function __construct( Niwa_AI_AI_Client_Interface $client ) {
		$this->client = $client;
	}

	public function resolve( $query, $conversation_context, $product_name, $availability, $model, $auth_mode, $credentials ) {
		$groups = $this->bounded_groups( $availability['groups'] ?? array() );
		if ( '' === trim( (string) $query ) || empty( $groups ) ) {
			return array( 'success' => false, 'status' => 'not_option_follow_up' );
		}

		$group_keys = array_keys( $groups );
		$values     = array();
		foreach ( $groups as $group ) {
			$values = array_merge( $values, (array) $group['values'] );
		}
		$values = array_values( array_unique( $values ) );
		$prompt_context = is_array( $conversation_context )
			? trim( (string) ( $conversation_context['prompt_context'] ?? '' ) )
			: '';
		$system = implode(
			"\n",
			array(
				'Classify the current message for the already selected storefront product.',
				'This classifier is multilingual. Interpret meaning and conversation context, not language-specific keywords.',
				'Select an option only when the visitor is changing or choosing one declared live option of this exact product.',
				'When the message contrasts an old value with a requested replacement, select the requested target value, never the rejected or superseded value.',
				'Use requested_option_unavailable when the visitor clearly requests a target option that is not present in LIVE_OPTIONS. Never substitute a declared option for an unavailable requested target.',
				'Use not_option_follow_up for a new independent product request or a question that does not choose an option.',
				'Use ambiguous when more than one declared target remains plausible.',
				'For selected, copy group and value exactly from LIVE_OPTIONS. Never translate, invent, or normalize the returned value.',
				'Return only the required resolve_selected_product_option tool call.',
				'',
				'[SELECTED_PRODUCT]',
				trim( (string) $product_name ),
				'[/SELECTED_PRODUCT]',
				'[LIVE_OPTIONS]',
				wp_json_encode( $groups, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ),
				'[/LIVE_OPTIONS]',
				'' !== $prompt_context ? "[RECENT_CONVERSATION]\n{$prompt_context}\n[/RECENT_CONVERSATION]" : '',
			)
		);
		$tools = array(
			array(
				'type'     => 'function',
				'function' => array(
					'name'        => 'resolve_selected_product_option',
					'description' => 'Return the selected live option or explain that this is not one unambiguous option selection.',
					'parameters'  => array(
						'type'                 => 'object',
						'properties'           => array(
							'status' => array(
								'type' => 'string',
								'enum' => array( 'selected', 'requested_option_unavailable', 'not_option_follow_up', 'ambiguous' ),
							),
							'group'  => array(
								'type' => 'string',
								'enum' => $group_keys,
							),
							'value'  => array(
								'type' => 'string',
								'enum' => $values,
							),
						),
						'required'             => array( 'status' ),
						'additionalProperties' => false,
					),
				),
			),
		);
		$result = $this->client->chat_complete(
			(string) $model,
			array(
				array( 'role' => 'system', 'content' => $system ),
				array( 'role' => 'user', 'content' => (string) $query ),
			),
			(string) $auth_mode,
			(array) $credentials,
			25,
			$tools,
			'required'
		);
		if ( empty( $result['success'] ) || empty( $result['tool_calls'][0]['arguments'] ) ) {
			return array(
				'success' => false,
				'status'  => 'resolver_failed',
				'error'   => (string) ( $result['error'] ?? 'Selected-product option resolver returned no tool call.' ),
			);
		}

		$args   = json_decode( (string) $result['tool_calls'][0]['arguments'], true );
		$status = is_array( $args ) ? sanitize_key( (string) ( $args['status'] ?? '' ) ) : '';
		if ( 'selected' !== $status ) {
			return array(
				'success' => true,
				'status'  => in_array( $status, array( 'requested_option_unavailable', 'not_option_follow_up', 'ambiguous' ), true ) ? $status : 'ambiguous',
			);
		}

		$group_key = (string) ( $args['group'] ?? '' );
		$value     = $this->declared_value( $args['value'] ?? '', $groups[ $group_key ]['values'] ?? array() );
		if ( '' === $group_key || '' === $value || ! isset( $groups[ $group_key ] ) ) {
			return array( 'success' => false, 'status' => 'invalid_selection' );
		}

		return array(
			'success' => true,
			'status'  => 'selected',
			'option'  => array(
				'group' => $group_key,
				'label' => (string) $groups[ $group_key ]['label'],
				'value' => $value,
			),
		);
	}

	private function bounded_groups( $groups ) {
		$out = array();
		foreach ( array_slice( (array) $groups, 0, 12, true ) as $group_key => $group ) {
			if ( ! is_array( $group ) ) {
				continue;
			}
			$values = array_values(
				array_unique(
					array_filter(
						array_map(
							static function ( $value ) {
								return mb_substr( trim( wp_strip_all_tags( (string) $value ) ), 0, 120 );
							},
							array_merge(
								(array) ( $group['parent_values'] ?? array() ),
								(array) ( $group['available_values'] ?? array() )
							)
						)
					)
				)
			);
			if ( empty( $values ) ) {
				continue;
			}
			$key = sanitize_key( (string) $group_key );
			if ( '' === $key ) {
				continue;
			}
			$label = trim( wp_strip_all_tags( (string) ( $group['label'] ?? '' ) ) );
			$out[ $key ] = array(
				'label'  => '' !== $label ? mb_substr( $label, 0, 120 ) : $key,
				'values' => array_slice( $values, 0, 80 ),
			);
		}
		return $out;
	}

	private function declared_value( $candidate, $values ) {
		$candidate_key = $this->normalize( $candidate );
		foreach ( (array) $values as $value ) {
			if ( '' !== $candidate_key && $candidate_key === $this->normalize( $value ) ) {
				return (string) $value;
			}
		}
		return '';
	}

	private function normalize( $value ) {
		$value = mb_strtolower( trim( wp_strip_all_tags( (string) $value ) ), 'UTF-8' );
		if ( function_exists( 'remove_accents' ) ) {
			$value = remove_accents( $value );
		}
		return trim( preg_replace( '/\s+/u', ' ', $value ) );
	}
}
