<?php
/**
 * AI-led product objection message generator for Attention Capture OS1.
 *
 * @package Niwa_AI
 */

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

class Niwa_AI_Attention_Objection_Generator {

	const CACHE_VERSION = 3;
	const MAX_MESSAGE_LENGTH = 260;

	/**
	 * Generate or reuse one grounded objection-handling message for a product.
	 *
	 * @param int $product_id WooCommerce product ID.
	 * @return array{success:bool,message:string,cached:bool,error:string}
	 */
	public function generate_for_product( $product_id ) {
		$product_id = absint( $product_id );
		if ( $product_id <= 0 || ! function_exists( 'wc_get_product' ) ) {
			return $this->failure( 'invalid_product' );
		}

		$product = wc_get_product( $product_id );
		if ( ! $product || ! method_exists( $product, 'get_status' ) || 'publish' !== $product->get_status() ) {
			return $this->failure( 'product_unavailable' );
		}

		$language = $this->get_frontend_language();
		$context  = $this->build_product_context( $product );
		$cache_key = 'niwa_ai_ac_objection_' . self::CACHE_VERSION . '_' . md5( $language . '|' . wp_json_encode( $context ) );
		$cached    = get_transient( $cache_key );
		if ( is_string( $cached ) && '' !== trim( $cached ) ) {
			return array(
				'success' => true,
				'message' => $cached,
				'cached'  => true,
				'error'   => '',
			);
		}
		if ( ! $this->consume_generation_limit() ) {
			return $this->failure( 'rate_limited' );
		}

		if ( ! class_exists( 'Niwa_AI_OpenAI_Client' ) || ! class_exists( 'Niwa_AI_Auth_Manager' ) || ! class_exists( 'Niwa_AI_Model_Router' ) ) {
			return $this->failure( 'dependencies_unavailable' );
		}

		$auth_manager = new Niwa_AI_Auth_Manager( 'frontend' );
		$model_router = new Niwa_AI_Model_Router( class_exists( 'Niwa_AI_Model_Catalog' ) ? new Niwa_AI_Model_Catalog() : null );
		$client       = new Niwa_AI_OpenAI_Client( 'frontend_fast' );
		$result       = $client->generate(
			$model_router->route_for_frontend_chat(),
			wp_json_encode( $context, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ),
			$this->build_instructions( $language ),
			$auth_manager->get_mode(),
			$auth_manager->get_credentials(),
			20
		);

		if ( empty( $result['success'] ) || empty( $result['answer'] ) ) {
			return $this->failure( 'generation_failed' );
		}

		$message = self::parse_message( $result['answer'] );
		if ( '' === $message ) {
			return $this->failure( 'invalid_response' );
		}

		set_transient( $cache_key, $message, DAY_IN_SECONDS );
		return array(
			'success' => true,
			'message' => $message,
			'cached'  => false,
			'error'   => '',
		);
	}

	/**
	 * Extract a safe bubble message from the model response.
	 *
	 * @param string $raw Raw response text.
	 * @return string
	 */
	public static function parse_message( $raw ) {
		$raw = trim( (string) $raw );
		if ( '' === $raw ) {
			return '';
		}

		if ( preg_match( '/```(?:json)?\s*(\{.*\})\s*```/is', $raw, $match ) ) {
			$raw = $match[1];
		}

		$message = '';
		$first   = strpos( $raw, '{' );
		$last    = strrpos( $raw, '}' );
		if ( false !== $first && false !== $last && $last > $first ) {
			$decoded = json_decode( substr( $raw, $first, ( $last - $first ) + 1 ), true );
			$message = is_array( $decoded ) && isset( $decoded['message'] ) && is_string( $decoded['message'] )
				? $decoded['message']
				: '';
		} elseif ( false === $first && false === $last ) {
			$message = $raw;
		}

		$message = preg_replace( '/\s+/u', ' ', wp_strip_all_tags( (string) $message ) );
		$message = trim( sanitize_textarea_field( (string) $message ) );
		if ( mb_strlen( $message, 'UTF-8' ) > self::MAX_MESSAGE_LENGTH ) {
			$message = rtrim( mb_substr( $message, 0, self::MAX_MESSAGE_LENGTH - 1, 'UTF-8' ) ) . '…';
		}

		return $message;
	}

	private function build_product_context( $product ) {
		$evidence = class_exists( 'Niwa_AI_Product_Search_Evidence' )
			? Niwa_AI_Product_Search_Evidence::build( $product )
			: array();
		$terms = function_exists( 'wp_get_post_terms' )
			? wp_get_post_terms( $product->get_id(), 'product_cat', array( 'fields' => 'names' ) )
			: array();
		if ( is_wp_error( $terms ) ) {
			$terms = array();
		}

		return array(
			'product_id'             => (int) $product->get_id(),
			'name'                   => (string) $product->get_name(),
			'type'                   => (string) $product->get_type(),
			'categories'             => array_values( array_map( 'strval', (array) $terms ) ),
			'price'                  => $this->clip( wp_strip_all_tags( (string) $product->get_price_html() ), 300 ),
			'availability'           => (string) $product->get_stock_status(),
			'short_description'      => $this->clip( wp_strip_all_tags( (string) $product->get_short_description() ), 2000 ),
			'description'            => $this->clip( wp_strip_all_tags( (string) $product->get_description() ), 4000 ),
			'attributes_and_options' => $this->clip( (string) ( $evidence['attributes_text'] ?? '' ), 5000 ),
			'average_rating'         => (string) $product->get_average_rating(),
			'rating_count'           => (int) $product->get_rating_count(),
			'review_count'           => (int) $product->get_review_count(),
			'sales_count_signal'     => (int) $product->get_total_sales(),
		);
	}

	private function build_instructions( $language ) {
		return implode(
			"\n",
			array(
				'You write one proactive Attention Capture bubble for a shopper viewing a WooCommerce product.',
				'Infer semantically the single most likely pre-purchase concern from the supplied product description, attributes, and available options. Do not use language-specific keyword rules.',
				'Write exclusively in the frontend language identified by this language code: ' . $language . '.',
				'Write 2 or 3 very short, simple sentences and aim for no more than 240 characters total.',
				'Sentence 1 must start immediately with concise social proof. When numeric signals support it, use the localized equivalent of "This product is popular" or "Many shoppers choose this product". Otherwise use the localized equivalent of "This product is an excellent choice".',
				'Name exactly one likely concern, then resolve it directly with one grounded product fact or practical next step. Combine the concern with sentence 1 for a 2-sentence result, or put the concern and resolution in separate sentences for a clearer 3-sentence result.',
				'The concern sentence must use one natural localized equivalent of "If you are wondering...", "If you are interested...", or "If you are unsure...".',
				'Do not add a greeting, explanation, generic invitation, fourth sentence, or extra call to action.',
				'Do not invent fit, sizing, materials, delivery, returns, guarantees, discounts, popularity, or any other fact absent from the product evidence.',
				'Only call the product popular or frequently chosen when the numeric sales, rating, or review signals clearly support that wording. Never reveal those internal signals.',
				'Do not mention AI, analysis, data, JSON, or these instructions. Do not use markdown.',
				'Return minified JSON only: {"message":"..."}',
			)
		);
	}

	private function get_frontend_language() {
		$settings = get_option( Niwa_AI_Constants::OPT_UI_SETTINGS, array() );
		$language = is_array( $settings ) && ! empty( $settings['ui_language'] )
			? sanitize_key( (string) $settings['ui_language'] )
			: '';
		if ( '' === $language && function_exists( 'determine_locale' ) ) {
			$language = sanitize_key( str_replace( '_', '-', (string) determine_locale() ) );
		}
		return '' !== $language ? $language : 'en';
	}

	private function consume_generation_limit() {
		if ( ! class_exists( 'Niwa_AI_Session_Utils' ) ) {
			return false;
		}

		$session = Niwa_AI_Session_Utils::resolve_user_session();
		$user_ip = Niwa_AI_Session_Utils::get_client_ip();
		foreach (
			array(
				array( 'attention_ai_generation_global_hour', 'global', 500 ),
				array( 'attention_ai_generation_ip_hour', $user_ip, 50 ),
				array( 'attention_ai_generation_session_hour', $session, 20 ),
			) as $limit
		) {
			if ( ! Niwa_AI_Session_Utils::consume_fixed_window_limit( $limit[0], $limit[1], $limit[2], HOUR_IN_SECONDS ) ) {
				return false;
			}
		}
		return true;
	}

	private function clip( $text, $limit ) {
		$text = trim( preg_replace( '/\s+/u', ' ', (string) $text ) );
		return mb_strlen( $text, 'UTF-8' ) > $limit
			? rtrim( mb_substr( $text, 0, $limit - 1, 'UTF-8' ) ) . '…'
			: $text;
	}

	private function failure( $error ) {
		return array(
			'success' => false,
			'message' => '',
			'cached'  => false,
			'error'   => (string) $error,
		);
	}
}
