<?php

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

/**
 * Niche / topic research: expand a free-text domain into keyword ideas,
 * then map each idea to improve / adapt / build page actions.
 */
final class IComm_SM_Niche_Research {

	private const TRANSIENT_LAST = 'icomm_sm_niche_last_v1';
	private const TRANSIENT_RATE = 'icomm_sm_niche_rate_v1';
	private const MAX_IDEAS = 18;
	private const MAX_SUGGEST_CALLS = 8;

	/**
	 * Last research result for the current admin (transient).
	 *
	 * @return array<string,mixed>|null
	 */
	public static function last_result(): ?array {
		$cached = get_transient(self::TRANSIENT_LAST);
		return is_array($cached) ? $cached : null;
	}

	public static function clear_last(): void {
		delete_transient(self::TRANSIENT_LAST);
	}

	/**
	 * @return array{
	 *   ok:bool,
	 *   error?:string,
	 *   topic?:string,
	 *   summary?:array{improve:int,adapt:int,build:int,total:int,from_gsc:int,from_ideas:int},
	 *   improve?:array<int,array<string,mixed>>,
	 *   adapt?:array<int,array<string,mixed>>,
	 *   build?:array<int,array<string,mixed>>,
	 *   keywords?:array<int,array<string,mixed>>
	 * }
	 */
	public static function research(string $topic): array {
		if (!IComm_SM_Features::can_use('opportunities') && !IComm_SM_Features::can_use('recommendations')) {
			return ['ok' => false, 'error' => 'locked'];
		}

		$topic = self::normalize_topic($topic);
		if ($topic === '') {
			return ['ok' => false, 'error' => 'empty'];
		}
		if (function_exists('mb_strlen') ? mb_strlen($topic) < 2 : strlen($topic) < 2) {
			return ['ok' => false, 'error' => 'short'];
		}

		$rate_key = self::TRANSIENT_RATE . '_' . get_current_user_id();
		if (get_transient($rate_key)) {
			$cached = self::last_result();
			if (is_array($cached) && (($cached['topic'] ?? '') === $topic)) {
				return array_merge(['ok' => true], $cached);
			}
			return ['ok' => false, 'error' => 'rate'];
		}
		set_transient($rate_key, 1, 20);

		$days = min(90, IComm_SM_Features::history_days());
		$gsc_rows = IComm_SM_DB::queries_related_to_topic($topic, $days, 50);
		$gsc_by_query = [];
		foreach ($gsc_rows as $row) {
			$key = IComm_SM_Recommendations::normalize_query_key((string) ($row['query'] ?? ''));
			if ($key !== '') {
				$gsc_by_query[$key] = $row;
			}
		}

		$idea_map = [];
		self::add_idea($idea_map, $topic, 'seed', 1.0);

		foreach ($gsc_rows as $row) {
			$q = trim((string) ($row['query'] ?? ''));
			$rel = 0.55 + min(0.45, (float) ($row['relevance'] ?? 0));
			self::add_idea($idea_map, $q, 'gsc', $rel);
		}

		foreach (self::modifier_seeds($topic) as $seed) {
			self::add_idea($idea_map, $seed, 'modifier', 0.35);
		}

		$suggest_calls = 0;
		foreach (self::suggest_seeds($topic) as $seed) {
			if ($suggest_calls >= self::MAX_SUGGEST_CALLS) {
				break;
			}
			$suggestions = self::google_suggest($seed);
			$suggest_calls++;
			foreach ($suggestions as $sug) {
				self::add_idea($idea_map, $sug, 'suggest', 0.7);
			}
		}

		uasort($idea_map, static function ($a, $b) {
			return ((float) ($b['score'] ?? 0)) <=> ((float) ($a['score'] ?? 0));
		});

		$board = [
			'improve' => [],
			'adapt' => [],
			'build' => [],
		];
		$keywords = [];
		$from_gsc = 0;
		$from_ideas = 0;
		$done_keys = IComm_SM_Recommendations::done_query_keys();

		foreach ($idea_map as $key => $idea) {
			if (count($keywords) >= self::MAX_IDEAS) {
				break;
			}
			$query = (string) ($idea['query'] ?? '');
			if ($query === '' || isset($done_keys[$key])) {
				continue;
			}

			$gsc = $gsc_by_query[$key] ?? null;
			$impr = is_array($gsc) ? (int) ($gsc['impressions'] ?? 0) : 0;
			$clk = is_array($gsc) ? (int) ($gsc['clicks'] ?? 0) : 0;
			$ctr = is_array($gsc) ? (float) ($gsc['ctr'] ?? 0) : 0.0;
			$pos = is_array($gsc) ? (float) ($gsc['position'] ?? 0) : 0.0;
			$source = (string) ($idea['source'] ?? 'idea');

			$row = [
				'impressions' => $impr,
				'clicks' => $clk,
				'ctr' => $ctr,
				'position' => $pos,
				'signals' => $impr > 0 ? ['niche_gsc'] : ['niche_idea'],
			];
			$card = IComm_SM_Recommendations::build_opportunity_card($query, $row, min(28, $days));
			if ($card === null) {
				continue;
			}

			$action = (string) ($card['action'] ?? 'build');
			if (!isset($board[$action])) {
				$action = 'build';
			}

			if ($impr > 0) {
				$from_gsc++;
				$card['metrics'] = sprintf(
					__('מ־GSC לתחום · חשיפות %1$d · CTR %2$s%% · מיקום %3$.1f', 'icomm-metrix'),
					$impr,
					(string) round($ctr * 100, 1),
					$pos
				);
			} else {
				$from_ideas++;
				$card['metrics'] = __('רעיון מחיפוש (עדיין בלי חשיפות באתר שלכם)', 'icomm-metrix');
				$card['guidance'] = self::idea_guidance($query, $action, (string) ($card['post_title'] ?? ''));
				if ($action === 'build' && empty($card['content_plan'])) {
					$card['content_plan'] = self::fallback_content_plan($query);
				}
			}

			$card['niche_source'] = $source;
			$card['niche_score'] = (float) ($idea['score'] ?? 0);
			$board[$action][] = $card;
			$keywords[] = [
				'query' => $query,
				'source' => $source,
				'impressions' => $impr,
				'action' => $action,
				'score' => (float) ($idea['score'] ?? 0),
			];
		}

		foreach (['improve', 'adapt', 'build'] as $bucket) {
			usort($board[$bucket], static function ($a, $b) {
				$ia = (int) ($a['impressions'] ?? 0);
				$ib = (int) ($b['impressions'] ?? 0);
				if ($ia !== $ib) {
					return $ib <=> $ia;
				}
				return ((float) ($b['niche_score'] ?? 0)) <=> ((float) ($a['niche_score'] ?? 0));
			});
			$board[$bucket] = array_slice($board[$bucket], 0, 10);
		}

		$summary = [
			'improve' => count($board['improve']),
			'adapt' => count($board['adapt']),
			'build' => count($board['build']),
			'total' => 0,
			'from_gsc' => $from_gsc,
			'from_ideas' => $from_ideas,
		];
		$summary['total'] = $summary['improve'] + $summary['adapt'] + $summary['build'];

		$result = [
			'topic' => $topic,
			'summary' => $summary,
			'improve' => $board['improve'],
			'adapt' => $board['adapt'],
			'build' => $board['build'],
			'keywords' => $keywords,
			'at' => (int) current_time('timestamp'),
		];

		set_transient(self::TRANSIENT_LAST, $result, 6 * HOUR_IN_SECONDS);

		$s = IComm_SM_Settings::get();
		$s['last_niche_topic'] = $topic;
		IComm_SM_Settings::save($s);

		return array_merge(['ok' => true], $result);
	}

	private static function normalize_topic(string $topic): string {
		$topic = sanitize_text_field($topic);
		$topic = trim(preg_replace('/\s+/u', ' ', $topic) ?? $topic);
		$max = 120;
		if (function_exists('mb_substr')) {
			return (string) mb_substr($topic, 0, $max);
		}
		return substr($topic, 0, $max);
	}

	/**
	 * @param array<string, array{query:string,source:string,score:float}> $map
	 */
	private static function add_idea(array &$map, string $query, string $source, float $score): void {
		$query = trim(preg_replace('/\s+/u', ' ', $query) ?? $query);
		$key = IComm_SM_Recommendations::normalize_query_key($query);
		$len = function_exists('mb_strlen') ? mb_strlen($query) : strlen($query);
		if ($key === '' || $len < 2 || $len > 120) {
			return;
		}
		if (!isset($map[$key]) || $score > (float) ($map[$key]['score'] ?? 0)) {
			$map[$key] = [
				'query' => $query,
				'source' => $source,
				'score' => $score,
			];
		} else {
			$map[$key]['score'] = (float) $map[$key]['score'] + ($score * 0.15);
			if ($source === 'gsc') {
				$map[$key]['source'] = 'gsc';
			}
		}
	}

	/**
	 * @return string[]
	 */
	private static function modifier_seeds(string $topic): array {
		$mods = [
			'מחיר',
			'עלות',
			'איך',
			'מה זה',
			'מדריך',
			'השוואה',
			'מומלץ',
			'שירות',
			'חברה',
			'ליד',
			'קרוב אליי',
			'טיפים',
			'דוגמאות',
			'ישראל',
		];
		$out = [];
		foreach ($mods as $m) {
			$out[] = $topic . ' ' . $m;
			$out[] = $m . ' ' . $topic;
		}
		return array_slice($out, 0, 24);
	}

	/**
	 * Seeds for Google Suggest (limited calls).
	 *
	 * @return string[]
	 */
	private static function suggest_seeds(string $topic): array {
		$seeds = [
			$topic,
			$topic . ' ',
			$topic . ' מחיר',
			$topic . ' איך',
			$topic . ' מה זה',
			$topic . ' מדריך',
			$topic . ' שירות',
			$topic . ' מומלץ',
		];
		return array_values(array_unique($seeds));
	}

	/**
	 * Autocomplete phrases from Google Suggest (fixed host; q is sanitized).
	 *
	 * @return string[]
	 */
	private static function google_suggest(string $seed): array {
		$seed = trim($seed);
		if ($seed === '') {
			return [];
		}
		$cache_key = 'icomm_sm_gsug_' . md5($seed);
		$cached = get_transient($cache_key);
		if (is_array($cached)) {
			return array_values(array_filter(array_map('strval', $cached)));
		}

		$url = 'https://suggestqueries.google.com/complete/search?' . http_build_query(
			[
				'client' => 'firefox',
				'hl' => 'he',
				'q' => $seed,
			],
			'',
			'&',
			PHP_QUERY_RFC3986
		);

		$res = wp_remote_get($url, [
			'timeout' => 8,
			'redirection' => 0,
			'headers' => [
				'Accept' => 'application/json',
			],
			'user-agent' => 'WordPress/' . get_bloginfo('version') . '; ' . home_url('/'),
		]);

		$out = [];
		if (!is_wp_error($res) && (int) wp_remote_retrieve_response_code($res) === 200) {
			$body = (string) wp_remote_retrieve_body($res);
			$data = json_decode($body, true);
			if (is_array($data) && isset($data[1]) && is_array($data[1])) {
				foreach ($data[1] as $item) {
					$s = trim((string) $item);
					if ($s !== '') {
						$out[] = $s;
					}
				}
			}
		}

		$out = array_slice(array_values(array_unique($out)), 0, 12);
		set_transient($cache_key, $out, 12 * HOUR_IN_SECONDS);
		return $out;
	}

	private static function idea_guidance(string $query, string $action, string $post_title): string {
		if ($action === 'improve' && $post_title !== '') {
			return sprintf(
				__('המילה “%1$s” רלוונטית לתחום שכתבתם, ויש כבר עמוד “%2$s”. שפרו כותרת, פתיח ו־FAQ סביב הביקוש הזה.', 'icomm-metrix'),
				$query,
				$post_title
			);
		}
		if ($action === 'adapt' && $post_title !== '') {
			return sprintf(
				__('“%1$s” קרוב לתחום, ויש עמוד קרוב (“%2$s”) שצריך דיוק מסר לכוונת החיפוש.', 'icomm-metrix'),
				$query,
				$post_title
			);
		}
		return sprintf(
			__('“%s” נראית כמילת חיפוש רלוונטית לתחום. אין עמוד מתאים באתר. מומלץ להקים עמוד ייעודי לפי תוכנית התוכן.', 'icomm-metrix'),
			$query
		);
	}

	private static function fallback_content_plan(string $query): string {
		// Re-run classify-style plan via a temporary card build for niche mode.
		$card = IComm_SM_Recommendations::build_opportunity_card($query, [
			'impressions' => 0,
			'clicks' => 0,
			'ctr' => 0,
			'position' => 0,
			'signals' => ['niche_idea'],
		]);
		return is_array($card) ? (string) ($card['content_plan'] ?? '') : '';
	}
}
