<?php

namespace WPDRMS\ASP\AI\Service;

use WPDRMS\ASP\AI\AbstractCachedAIFeatureService;
use WPDRMS\ASP\AI\AIInsufficientDataException;
use WPDRMS\ASP\Statistics\ORM\Interaction as StatInteraction;
use WPDRMS\ASP\Statistics\ORM\Result as StatResult;
use WPDRMS\ASP\Statistics\ORM\Search as StatSearch;
use WPDRMS\PluginCore\Traits\SingletonTrait;

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

class AIQualityReportService extends AbstractCachedAIFeatureService {
	use SingletonTrait;

	private function __construct() {}

	/**
	 * @param int  $asp_id  0 = all instances
	 * @param int  $days
	 * @param bool $force
	 * @return array<string, mixed>
	 * @throws AIInsufficientDataException When fewer than 10 searches exist.
	 */
	public function generate( int $asp_id, int $days, bool $force = false ): array {
		return $this->runCached(
			array(
				'asp_id' => $asp_id,
				'days'   => $days,
			),
			$force 
		);
	}

	protected function getFeatureSlug(): string {
		return 'quality_report';
	}

	protected function getAgentId(): string {
		return 'search_quality_report';
	}

	protected function getTtl(): int {
		return DAY_IN_SECONDS;
	}

	protected function buildCacheKey( array $args ): string {
		return md5( $args['asp_id'] . '_' . $args['days'] );
	}

	protected function collectData( array $args ): array {
		return array(
			'stats'  => $this->buildQualityStats( $args['asp_id'], $args['days'] ),
			'asp_id' => $args['asp_id'],
			'days'   => $args['days'],
		);
	}

	protected function validateData( array $data ): void {
		if ( $data['stats']['total_searches'] < 10 ) {
			throw new AIInsufficientDataException( __( 'Not enough search data to generate a report (minimum 10 searches required).', 'ajax-search-pro' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
		}
	}

	protected function buildPrompt( array $data ): string {
		return $this->buildQualityPrompt( $data['stats'], $data['days'], $data['asp_id'] );
	}

	protected function buildPayload( array $data, string $ai_result ): array {
		return array(
			'report'       => $ai_result,
			'stats'        => $data['stats'],
			'generated_at' => current_time( 'c' ),
		);
	}

	/**
	 * @param int $asp_id  0 = all instances
	 * @param int $days
	 * @return array<string, mixed>
	 */
	private function buildQualityStats( int $asp_id, int $days ): array {
		global $wpdb;

		$s = StatSearch::getTableName();
		$r = StatResult::getTableName();
		$i = StatInteraction::getTableName();

		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$asp_cond = $asp_id > 0 ? $wpdb->prepare( 'AND asp_id = %d', $asp_id ) : '';

		$overall = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->prepare(
				"SELECT
					COUNT(*) AS total_searches,
					SUM(CASE WHEN found_results = 0 THEN 1 ELSE 0 END) AS zero_results_count,
					ROUND(AVG(found_results), 1) AS avg_results,
					COUNT(DISTINCT phrase) AS unique_phrases,
					SUM(CASE WHEN device_type = 1 THEN 1 ELSE 0 END) AS desktop_count,
					SUM(CASE WHEN device_type = 2 THEN 1 ELSE 0 END) AS tablet_count,
					SUM(CASE WHEN device_type = 3 THEN 1 ELSE 0 END) AS mobile_count,
					SUM(CASE WHEN device_type = 1 AND found_results = 0 THEN 1 ELSE 0 END) AS desktop_zero,
					SUM(CASE WHEN device_type = 2 AND found_results = 0 THEN 1 ELSE 0 END) AS tablet_zero,
					SUM(CASE WHEN device_type = 3 AND found_results = 0 THEN 1 ELSE 0 END) AS mobile_zero
				FROM {$s}
				WHERE date >= DATE_SUB(NOW(), INTERVAL %d DAY) {$asp_cond}",
				$days
			),
			ARRAY_A
		);

		$clicks = (int) $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->prepare(
				"SELECT COUNT(DISTINCT s.id)
				 FROM {$s} s
				 INNER JOIN {$r} res ON res.search_id = s.id
				 INNER JOIN {$i} inter ON inter.result_id = res.id
				 WHERE s.date >= DATE_SUB(NOW(), INTERVAL %d DAY) {$asp_cond}",
				$days
			)
		);

		$top_zero = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->prepare(
				"SELECT phrase, COUNT(*) AS count
				 FROM {$s}
				 WHERE found_results = 0
				   AND date >= DATE_SUB(NOW(), INTERVAL %d DAY)
				   AND CHAR_LENGTH(phrase) > 1
				   {$asp_cond}
				 GROUP BY phrase
				 ORDER BY count DESC
				 LIMIT 10",
				$days
			),
			ARRAY_A
		);
		// phpcs:enable

		$total         = (int) ( $overall['total_searches'] ?? 0 );
		$zero          = (int) ( $overall['zero_results_count'] ?? 0 );
		$desktop_count = (int) ( $overall['desktop_count'] ?? 0 );
		$tablet_count  = (int) ( $overall['tablet_count'] ?? 0 );
		$mobile_count  = (int) ( $overall['mobile_count'] ?? 0 );

		return array(
			'total_searches'       => $total,
			'zero_results_count'   => $zero,
			'zero_results_rate'    => $total > 0 ? round( $zero / $total * 100, 1 ) : 0,
			'avg_results'          => (float) ( $overall['avg_results'] ?? 0 ),
			'unique_phrases'       => (int) ( $overall['unique_phrases'] ?? 0 ),
			'searches_with_clicks' => $clicks,
			'click_through_rate'   => $total > 0 ? round( $clicks / $total * 100, 1 ) : 0,
			'device'               => array(
				'desktop' => array(
					'count'     => $desktop_count,
					'zero_rate' => $desktop_count > 0 ? round( (int) ( $overall['desktop_zero'] ?? 0 ) / $desktop_count * 100, 1 ) : 0,
				),
				'tablet'  => array(
					'count'     => $tablet_count,
					'zero_rate' => $tablet_count > 0 ? round( (int) ( $overall['tablet_zero'] ?? 0 ) / $tablet_count * 100, 1 ) : 0,
				),
				'mobile'  => array(
					'count'     => $mobile_count,
					'zero_rate' => $mobile_count > 0 ? round( (int) ( $overall['mobile_zero'] ?? 0 ) / $mobile_count * 100, 1 ) : 0,
				),
			),
			'top_zero_results'     => array_map(
				fn( $row ) => array(
					'phrase' => $row['phrase'],
					'count'  => (int) $row['count'],
				),
				$top_zero ?? array()
			),
		);
	}

	/**
	 * @param array<string, mixed> $stats
	 * @param int                  $days
	 * @param int                  $asp_id
	 * @return string
	 */
	private function buildQualityPrompt( array $stats, int $days, int $asp_id ): string {
		return (string) wp_json_encode(
			array(
				'scope'                => $asp_id > 0 ? "Search instance ID {$asp_id}" : 'All search instances',
				'period_days'          => $days,
				'total_searches'       => $stats['total_searches'],
				'unique_phrases'       => $stats['unique_phrases'],
				'zero_results_rate'    => $stats['zero_results_rate'],
				'zero_results_count'   => $stats['zero_results_count'],
				'avg_results'          => $stats['avg_results'],
				'click_through_rate'   => $stats['click_through_rate'],
				'searches_with_clicks' => $stats['searches_with_clicks'],
				'device'               => $stats['device'],
				'top_zero_phrases'     => $stats['top_zero_results'],
			)
		);
	}
}
