<?php
defined( 'ABSPATH' ) || exit;

/**
 * AI integration — all OpenAI calls are proxied through the StoreSight API.
 *
 * The plugin is responsible for pre-fetching live WooCommerce data (which only
 * it can access) and sending it as context. StoreSight holds the OpenAI key,
 * enforces rate limits, and logs every request to the ai_requests table.
 */
class WAD_AI {

	// ─── Public entry points ──────────────────────────────────────────────────

	/**
	 * Store AI Assistant (chat).
	 * Pre-fetches relevant store data from WooCommerce, then sends to StoreSight.
	 */
	public static function handle_query( string $message, array $history ): WP_REST_Response|WP_Error {
		$context = self::prefetch_widget_data( $message );

		// Clean and trim history to last 10 exchanges.
		$clean_history = [];
		foreach ( array_slice( $history, -10 ) as $msg ) {
			$role    = ( isset( $msg['role'] ) && $msg['role'] === 'assistant' ) ? 'assistant' : 'user';
			$content = sanitize_textarea_field( $msg['content'] ?? '' );
			if ( $content ) {
				$clean_history[] = [ 'role' => $role, 'content' => $content ];
			}
		}

		return self::call_storesight( sanitize_textarea_field( $message ), $context, 'assistant', $clean_history );
	}

	/**
	 * Dashboard widget data.
	 * Pre-fetches store data and requests a specific JSON structure from StoreSight.
	 */
	public static function handle_widget_query( string $prompt, string $type ): WP_REST_Response|WP_Error {
		$context = self::prefetch_widget_data( $prompt );

		// Tell StoreSight exactly what JSON format is required for this widget type.
		$format = self::widget_format_spec( $type );
		$full_prompt = "Widget type: \"{$type}\". Return ONLY valid JSON matching this exact format:\n{$format}\n\n"
			. "Rules: use only the provided store data; format money as numbers without currency symbol; "
			. "for kpi_card the value field must be a display string (e.g. \"1,234.56\"); "
			. "max 50 table rows, max 24 chart points.\n\n"
			. "User prompt: {$prompt}";

		$result = self::call_storesight( $full_prompt, $context, 'widget' );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		$text = $result->get_data()['response'] ?? '';

		// Strip markdown fences if present.
		$text = preg_replace( '/^```(?:json)?\s*/i', '', trim( $text ) );
		$text = preg_replace( '/\s*```$/', '', $text );

		$parsed = json_decode( $text, true );
		if ( json_last_error() !== JSON_ERROR_NONE ) {
			return new WP_Error( 'ai_parse_error', __( 'AI returned invalid JSON for widget data.', 'woo-analytics-dashboard' ), [ 'status' => 502 ] );
		}

		return rest_ensure_response( $parsed );
	}

	/**
	 * Report section text.
	 * Pre-fetches store data and requests analytical prose from StoreSight.
	 */
	public static function handle_report_section( string $prompt ): WP_REST_Response|WP_Error {
		$context = self::prefetch_widget_data( $prompt );
		$result  = self::call_storesight( $prompt, $context, 'report' );

		if ( is_wp_error( $result ) ) {
			return $result;
		}

		return rest_ensure_response( [ 'text' => $result->get_data()['response'] ?? '' ] );
	}

	// ─── StoreSight HTTP call ────────────────────────────────────────────────

	private static function call_storesight(
		string $prompt,
		string $context,
		string $type,
		array $history = []
	): WP_REST_Response|WP_Error {
		$token = WAD_License::get_token();
		if ( ! $token ) {
			return new WP_Error(
				'license_invalid',
				__( 'No active license token. Please activate your license in WooCommerce > Analytics Settings.', 'woo-analytics-dashboard' ),
				[ 'status' => 403 ]
			);
		}

		$body = [
			'prompt'  => $prompt,
			'context' => $context,
			'type'    => $type,
		];

		if ( ! empty( $history ) ) {
			$body['history'] = $history;
		}

		$response = wp_remote_post( WAD_STORESIGHT_API_URL . '/ai/prompt', [
			'timeout' => 60,
			'headers' => [
				'Content-Type'   => 'application/json',
				'Accept'         => 'application/json',
				'Authorization'  => 'Bearer ' . $token,
				'X-License-Token' => $token, // fallback if Authorization is stripped by server
			],
			'body' => wp_json_encode( $body ),
		] );

		if ( is_wp_error( $response ) ) {
			return new WP_Error( 'ai_connection', $response->get_error_message(), [ 'status' => 502 ] );
		}

		$code         = wp_remote_retrieve_response_code( $response );
		$decoded_body = json_decode( wp_remote_retrieve_body( $response ), true );

		if ( $code === 429 ) {
			return new WP_Error(
				'ai_rate_limit',
				$decoded_body['error'] ?? __( 'Daily AI query limit reached. Please try again tomorrow.', 'woo-analytics-dashboard' ),
				[ 'status' => 429 ]
			);
		}

		if ( $code !== 200 ) {
			return new WP_Error(
				'ai_error',
				$decoded_body['error'] ?? __( 'AI service returned an error.', 'woo-analytics-dashboard' ),
				[ 'status' => $code ?: 502 ]
			);
		}

		return rest_ensure_response( $decoded_body );
	}

	// ─── Widget JSON format specs ─────────────────────────────────────────────

	private static function widget_format_spec( string $type ): string {
		return match ( $type ) {
			'kpi_card'    => '{ "title": "...", "value": "1,234.56", "change": "+12.5%", "positive": true }',
			'table'       => '{ "title": "...", "headers": ["Col1","Col2",...], "rows": [["val","val",...], ...] }',
			'donut_chart' => '{ "title": "...", "data": [{ "name": "...", "value": 123 }, ...] }',
			'comparison'  => '{ "title": "...", "data": [{ "label": "...", "value": 123, "value2": 456 }, ...], "series": ["Series A","Series B"], "yFormat": "currency" }',
			default       => '{ "title": "...", "data": [{ "label": "...", "value": 123 }, ...], "yFormat": "currency" }',
		};
	}

	// ─── WooCommerce data pre-fetch ───────────────────────────────────────────
	// These methods run inside WordPress and gather live store data to send as
	// context. StoreSight has no access to WooCommerce directly.

	private static function prefetch_widget_data( string $prompt ): string {
		$p        = strtolower( $prompt );
		$currency = html_entity_decode( get_woocommerce_currency_symbol(), ENT_QUOTES, 'UTF-8' );
		$sections = [];

		$range = self::detect_range( $p );
		$dates = WAD_Data::get_date_range( $range );

		// ── Revenue / Sales / KPIs ──────────────────────────────────────────
		if ( preg_match( '/revenue|sales?|income|earning|total|average|avg|aov|order value/i', $p ) ) {
			$overview = WAD_Data::get_overview( $range );
			$kpis     = $overview['kpis'] ?? [];

			$lines   = [ "REVENUE & ORDER KPIs ({$range} range, {$dates['start']} to {$dates['end']}):" ];
			$lines[] = "  Revenue: {$currency}" . number_format( $kpis['revenue']['value'] ?? 0, 2 )
				. " (change: " . ( $kpis['revenue']['change'] ?? 0 ) . "%)";
			$lines[] = "  Orders: " . ( $kpis['orders']['value'] ?? 0 )
				. " (change: " . ( $kpis['orders']['change'] ?? 0 ) . "%, avg: {$currency}" . number_format( $kpis['orders']['avg'] ?? 0, 2 ) . ")";
			$lines[] = "  Customers: " . ( $kpis['customers']['value'] ?? 0 )
				. " (change: " . ( $kpis['customers']['change'] ?? 0 ) . "%)";

			if ( ! empty( $overview['revenue_chart'] ) ) {
				$lines[] = "  Monthly revenue:";
				foreach ( $overview['revenue_chart'] as $row ) {
					$lines[] = "    {$row['month']}: {$currency}" . number_format( (float) $row['revenue'], 2 )
						. " ({$row['orders']} orders"
						. ( ! empty( $row['lastYear'] ) ? ", prev year: {$currency}" . number_format( (float) $row['lastYear'], 2 ) : '' ) . ")";
				}
			}

			$sections[] = implode( "\n", $lines );
		}

		// ── Products ────────────────────────────────────────────────────────
		if ( preg_match( '/product|best.?sell|top.?\d|item|stock|sku|categor/i', $p ) ) {
			$limit_match = [];
			preg_match( '/top\s*(\d+)/i', $p, $limit_match );
			$limit = ! empty( $limit_match[1] ) ? min( 20, (int) $limit_match[1] ) : 10;

			$top   = WAD_Data::get_top_products( $limit, $dates['start'], $dates['end'] );
			$lines = [ "TOP {$limit} PRODUCTS BY REVENUE ({$range}):" ];
			foreach ( $top as $pr ) {
				$stock   = $pr['stock'] !== null ? $pr['stock'] : 'unmanaged';
				$lines[] = "  {$pr['name']}: revenue {$currency}" . number_format( $pr['revenue'], 2 )
					. ", sold {$pr['sold']}, price {$currency}" . number_format( $pr['price'], 2 )
					. ", stock: {$stock}, cat: " . ( $pr['cat'] ?: '—' );
			}
			$sections[] = implode( "\n", $lines );

			$cats = WAD_Data::get_category_breakdown( $dates['start'], $dates['end'] );
			if ( $cats ) {
				$lines = [ "CATEGORY BREAKDOWN:" ];
				foreach ( $cats as $cat ) {
					$lines[] = "  {$cat['name']}: {$cat['value']}%";
				}
				$sections[] = implode( "\n", $lines );
			}
		}

		// ── Customers ───────────────────────────────────────────────────────
		if ( preg_match( '/customer|buyer|spend|tier|loyal/i', $p ) ) {
			$result = WAD_Data::get_customers_list( [ 'sort' => 'spent', 'per_page' => 20, 'page' => 1 ] );
			$lines  = [ "TOP CUSTOMERS BY SPEND (total: {$result['total']}):" ];
			foreach ( array_slice( $result['customers'], 0, 15 ) as $c ) {
				$lines[] = "  {$c['name']} ({$c['email']}): spent {$currency}" . number_format( $c['spent'], 2 )
					. ", {$c['orders']} orders, tier: {$c['tier']}, joined: " . ( $c['joined'] ?? '—' );
			}
			$sections[] = implode( "\n", $lines );

			$growth = WAD_Data::get_customer_growth();
			if ( $growth ) {
				$lines = [ "CUSTOMER GROWTH (last 6 months):" ];
				foreach ( $growth as $g ) {
					$lines[] = "  {$g['month']}: new {$g['new']}, returning {$g['returning']}";
				}
				$sections[] = implode( "\n", $lines );
			}
		}

		// ── Orders ──────────────────────────────────────────────────────────
		if ( preg_match( '/order|status|recent|refund|cancel|pending|process/i', $p ) ) {
			$status_filter = 'any';
			if ( preg_match( '/refund/i', $p ) )         $status_filter = 'refunded';
			elseif ( preg_match( '/cancel/i', $p ) )     $status_filter = 'cancelled';
			elseif ( preg_match( '/pending/i', $p ) )    $status_filter = 'pending';
			elseif ( preg_match( '/processing/i', $p ) ) $status_filter = 'processing';
			elseif ( preg_match( '/completed/i', $p ) )  $status_filter = 'completed';

			$result = WAD_Data::get_orders_list( [ 'status' => $status_filter, 'per_page' => 30, 'page' => 1 ] );
			$lines  = [ "ORDERS (status: {$status_filter}, total: {$result['total']}, showing page 1):" ];

			if ( ! empty( $result['status_counts'] ) ) {
				$counts = [];
				foreach ( $result['status_counts'] as $s => $n ) {
					$counts[] = "{$s}: {$n}";
				}
				$lines[] = "  Status counts: " . implode( ', ', $counts );
			}

			foreach ( array_slice( $result['orders'], 0, 25 ) as $o ) {
				$lines[] = "  {$o['number']}: {$o['customer']}, {$currency}" . number_format( $o['total'], 2 )
					. ", {$o['status']}, {$o['date']}";
			}
			$sections[] = implode( "\n", $lines );
		}

		// ── Daily revenue (current week) ────────────────────────────────────
		if ( preg_match( '/daily|today|this week|day.?by.?day/i', $p ) ) {
			$daily = WAD_Data::get_daily_revenue();
			$lines = [ "DAILY REVENUE (current week):" ];
			foreach ( $daily as $d ) {
				$lines[] = "  {$d['day']}: {$currency}" . number_format( $d['amount'], 2 );
			}
			$sections[] = implode( "\n", $lines );
		}

		// Fallback: general overview when nothing specific matched.
		if ( empty( $sections ) ) {
			$overview = WAD_Data::get_overview( $range );
			$kpis     = $overview['kpis'] ?? [];
			$lines    = [ "GENERAL STORE OVERVIEW ({$range}):" ];
			$lines[]  = "  Revenue: {$currency}" . number_format( $kpis['revenue']['value'] ?? 0, 2 );
			$lines[]  = "  Orders: " . ( $kpis['orders']['value'] ?? 0 );
			$lines[]  = "  Customers: " . ( $kpis['customers']['value'] ?? 0 );
			if ( ! empty( $overview['revenue_chart'] ) ) {
				$lines[] = "  Monthly:";
				foreach ( $overview['revenue_chart'] as $row ) {
					$lines[] = "    {$row['month']}: {$currency}" . number_format( (float) $row['revenue'], 2 );
				}
			}
			$sections[] = implode( "\n", $lines );
		}

		return implode( "\n\n", $sections );
	}

	private static function detect_range( string $p ): string {
		if ( preg_match( '/last\s*7\s*day|past\s*week|this\s*week/i', $p ) )                return '7d';
		if ( preg_match( '/last\s*(1\s*)?month|past\s*month|this\s*month/i', $p ) )         return '1m';
		if ( preg_match( '/last\s*3\s*month|past\s*3|quarter/i', $p ) )                     return '3m';
		if ( preg_match( '/last\s*(6\s*month|half)|past\s*6/i', $p ) )                      return '6m';
		if ( preg_match( '/last\s*(12\s*month|year)|past\s*year|this\s*year|annual/i', $p ) ) return '1y';
		return '6m';
	}
}
