<?php
/**
 * Google Trends RSS — shared fetch with circuit breaker, backoff, and stale fallback.
 *
 * @package Newsroom_AI_Assistant
 */

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

/** Failures within the window before opening the circuit. */
if ( ! defined( 'NEWSAI_TRENDS_FAIL_THRESHOLD' ) ) {
	define( 'NEWSAI_TRENDS_FAIL_THRESHOLD', 3 );
}

/** Base circuit cooldown (seconds); doubles with streak, capped at max. */
if ( ! defined( 'NEWSAI_TRENDS_CIRCUIT_BASE' ) ) {
	define( 'NEWSAI_TRENDS_CIRCUIT_BASE', 15 * MINUTE_IN_SECONDS );
}

if ( ! defined( 'NEWSAI_TRENDS_CIRCUIT_MAX' ) ) {
	define( 'NEWSAI_TRENDS_CIRCUIT_MAX', HOUR_IN_SECONDS );
}

/** After a failed fetch, skip outbound HTTP for this long (per geo). */
if ( ! defined( 'NEWSAI_TRENDS_NEGATIVE_CACHE_TTL' ) ) {
	define( 'NEWSAI_TRENDS_NEGATIVE_CACHE_TTL', 2 * MINUTE_IN_SECONDS );
}

/** Sliding window for consecutive failure counting. */
if ( ! defined( 'NEWSAI_TRENDS_FAIL_WINDOW' ) ) {
	define( 'NEWSAI_TRENDS_FAIL_WINDOW', 10 * MINUTE_IN_SECONDS );
}

if ( ! defined( 'NEWSAI_TRENDS_STALE_TTL' ) ) {
	define( 'NEWSAI_TRENDS_STALE_TTL', DAY_IN_SECONDS );
}

if ( ! function_exists( 'newsai_google_trends_normalize_geo' ) ) {
	/**
	 * @param string $geo Raw geo code.
	 * @return string Two-letter geo.
	 */
	function newsai_google_trends_normalize_geo( $geo ) {
		$geo = strtoupper( preg_replace( '/[^A-Z]/i', '', (string) $geo ) );
		if ( $geo === '' ) {
			$geo = function_exists( 'newsai_get_target_geo' ) ? newsai_get_target_geo() : 'US';
		}
		return $geo;
	}
}

if ( ! function_exists( 'newsai_google_trends_rss_url' ) ) {
	/**
	 * @param string $geo Normalized geo.
	 * @return string
	 */
	function newsai_google_trends_rss_url( $geo ) {
		return 'https://trends.google.com/trending/rss?geo=' . rawurlencode( newsai_google_trends_normalize_geo( $geo ) );
	}
}

if ( ! function_exists( 'newsai_google_trends_fail_key' ) ) {
	function newsai_google_trends_fail_key( $geo ) {
		return 'newsai_trends_fail_' . newsai_google_trends_normalize_geo( $geo );
	}
}

if ( ! function_exists( 'newsai_google_trends_circuit_key' ) ) {
	function newsai_google_trends_circuit_key( $geo ) {
		return 'newsai_trends_circuit_' . newsai_google_trends_normalize_geo( $geo );
	}
}

if ( ! function_exists( 'newsai_google_trends_negative_key' ) ) {
	function newsai_google_trends_negative_key( $geo ) {
		return 'newsai_trends_neg_' . newsai_google_trends_normalize_geo( $geo );
	}
}

if ( ! function_exists( 'newsai_google_trends_stale_items_key' ) ) {
	function newsai_google_trends_stale_items_key( $geo ) {
		return 'newsai_trends_items_stale_' . newsai_google_trends_normalize_geo( $geo );
	}
}

if ( ! function_exists( 'newsai_google_trends_stale_html_key' ) ) {
	function newsai_google_trends_stale_html_key( $geo ) {
		return 'nros_trends_html_stale_v2_' . newsai_google_trends_normalize_geo( $geo );
	}
}

if ( ! function_exists( 'newsai_google_trends_is_circuit_open' ) ) {
	/**
	 * @param string $geo Geo code.
	 * @return bool
	 */
	function newsai_google_trends_is_circuit_open( $geo ) {
		return (bool) get_transient( newsai_google_trends_circuit_key( $geo ) );
	}
}

if ( ! function_exists( 'newsai_google_trends_circuit_backoff_seconds' ) ) {
	/**
	 * Exponential backoff from failure streak (after threshold).
	 *
	 * @param int $streak Consecutive failures.
	 * @return int Seconds.
	 */
	function newsai_google_trends_circuit_backoff_seconds( $streak ) {
		$streak = max( 0, (int) $streak );
		if ( $streak < NEWSAI_TRENDS_FAIL_THRESHOLD ) {
			return 0;
		}
		$exp = min( 4, $streak - NEWSAI_TRENDS_FAIL_THRESHOLD );
		$sec = (int) ( NEWSAI_TRENDS_CIRCUIT_BASE * pow( 2, $exp ) );
		return min( NEWSAI_TRENDS_CIRCUIT_MAX, $sec );
	}
}

if ( ! function_exists( 'newsai_google_trends_log_failure_once' ) ) {
	/**
	 * At most one log line per geo per circuit window (avoids log floods).
	 *
	 * @param string $geo     Geo code.
	 * @param string $reason  Short reason.
	 * @param int    $streak  Failure count.
	 * @return void
	 */
	function newsai_google_trends_log_failure_once( $geo, $reason, $streak = 0 ) {
		$geo = newsai_google_trends_normalize_geo( $geo );
		if ( ! apply_filters( 'newsai_google_trends_log_failures', ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ) ) {
			return;
		}
		$log_key = 'newsai_trends_logged_' . $geo;
		if ( get_transient( $log_key ) ) {
			return;
		}
		$ttl = newsai_google_trends_circuit_backoff_seconds( $streak );
		if ( $ttl < 1 ) {
			$ttl = NEWSAI_TRENDS_NEGATIVE_CACHE_TTL;
		}
		set_transient( $log_key, '1', $ttl );
		// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
		error_log(
			sprintf(
				'[Newsroom OS] Google Trends RSS unavailable (%s, geo=%s, streak=%d). Circuit/backoff active.',
				$reason,
				$geo,
				(int) $streak
			)
		);
	}
}

if ( ! function_exists( 'newsai_google_trends_record_success' ) ) {
	/**
	 * @param string $geo Geo code.
	 * @return void
	 */
	function newsai_google_trends_record_success( $geo ) {
		$geo = newsai_google_trends_normalize_geo( $geo );
		delete_transient( newsai_google_trends_fail_key( $geo ) );
		delete_transient( newsai_google_trends_circuit_key( $geo ) );
		delete_transient( newsai_google_trends_negative_key( $geo ) );
		delete_transient( 'newsai_trends_logged_' . $geo );
	}
}

if ( ! function_exists( 'newsai_google_trends_record_failure' ) ) {
	/**
	 * @param string $geo    Geo code.
	 * @param string $reason Short reason for logging.
	 * @return int New failure streak.
	 */
	function newsai_google_trends_record_failure( $geo, $reason = 'fetch_failed' ) {
		$geo    = newsai_google_trends_normalize_geo( $geo );
		$key    = newsai_google_trends_fail_key( $geo );
		$streak = (int) get_transient( $key ) + 1;
		set_transient( $key, $streak, NEWSAI_TRENDS_FAIL_WINDOW );
		set_transient( newsai_google_trends_negative_key( $geo ), '1', NEWSAI_TRENDS_NEGATIVE_CACHE_TTL );

		$backoff = newsai_google_trends_circuit_backoff_seconds( $streak );
		if ( $backoff > 0 ) {
			set_transient( newsai_google_trends_circuit_key( $geo ), '1', $backoff );
			newsai_google_trends_log_failure_once( $geo, $reason, $streak );
		}

		return $streak;
	}
}

if ( ! function_exists( 'newsai_google_trends_get_stale_items' ) ) {
	/**
	 * @param string $geo Geo code.
	 * @return list<array{title:string,permalink:string,traffic:string,numeric_traffic:int}>
	 */
	function newsai_google_trends_get_stale_items( $geo ) {
		$cached = get_transient( newsai_google_trends_stale_items_key( $geo ) );
		return is_array( $cached ) ? $cached : [];
	}
}

if ( ! function_exists( 'newsai_google_trends_store_stale_items' ) ) {
	/**
	 * @param string $geo   Geo code.
	 * @param array  $items Parsed items.
	 * @return void
	 */
	function newsai_google_trends_store_stale_items( $geo, array $items ) {
		if ( $items === [] ) {
			return;
		}
		set_transient( newsai_google_trends_stale_items_key( $geo ), $items, NEWSAI_TRENDS_STALE_TTL );
	}
}

if ( ! function_exists( 'newsai_google_trends_item_traffic' ) ) {
	/**
	 * @param object $item SimplePie item.
	 * @return array{traffic:string,numeric_traffic:int}
	 */
	function newsai_google_trends_item_traffic( $item ) {
		$traffic = '';
		$tags    = [
			[ 'https://trends.google.com/trending/rss', 'approx_traffic' ],
			[ 'http://trends.google.com/trending/rss', 'approx_traffic' ],
			[ 'https://trends.google.com/trends/trendingsearches/realtime/rss', 'approx_traffic' ],
			[ 'http://trends.google.com/trends/trendingsearches/realtime/rss', 'approx_traffic' ],
		];
		foreach ( $tags as $tag ) {
			$ht_data = $item->get_item_tags( $tag[0], $tag[1] );
			if ( $ht_data ) {
				$traffic = (string) $ht_data[0]['data'];
				break;
			}
		}
		return [
			'traffic'          => $traffic,
			'numeric_traffic'  => (int) preg_replace( '/[^0-9]/', '', $traffic ),
		];
	}
}

if ( ! function_exists( 'newsai_google_trends_parse_feed_items' ) ) {
	/**
	 * @param object $feed SimplePie feed.
	 * @param int    $limit Max items.
	 * @return list<array{title:string,permalink:string,traffic:string,numeric_traffic:int}>
	 */
	function newsai_google_trends_parse_feed_items( $feed, $limit = 8 ) {
		$items = $feed->get_items( 0, $limit );
		if ( ! is_array( $items ) ) {
			return [];
		}
		$out = [];
		foreach ( $items as $item ) {
			$title = trim( (string) $item->get_title() );
			if ( $title === '' ) {
				continue;
			}
			$traffic = newsai_google_trends_item_traffic( $item );
			$out[]   = [
				'title'            => $title,
				'permalink'        => (string) $item->get_permalink(),
				'traffic'          => $traffic['traffic'],
				'numeric_traffic'  => $traffic['numeric_traffic'],
			];
		}
		return $out;
	}
}

if ( ! function_exists( 'newsai_google_trends_fetch_feed' ) ) {
	/**
	 * Low-level RSS fetch (no circuit logic).
	 *
	 * @param string $geo Geo code.
	 * @return \WP_Error|object SimplePie feed.
	 */
	function newsai_google_trends_fetch_feed( $geo ) {
		$geo = newsai_google_trends_normalize_geo( $geo );
		add_filter( 'wp_feed_cache_transient_lifetime', '__return_false' );
		$nros_timeout = static function () {
			return 3;
		};
		add_filter( 'http_request_timeout', $nros_timeout, 999 );
		try {
			$rss = fetch_feed( newsai_google_trends_rss_url( $geo ) );
		} finally {
			remove_filter( 'http_request_timeout', $nros_timeout, 999 );
		}
		return $rss;
	}
}

if ( ! function_exists( 'newsai_google_trends_get_items' ) ) {
	/**
	 * Fetch trend items with circuit breaker, negative cache, and stale fallback.
	 *
	 * @param string $geo   Geo code.
	 * @param int    $limit Max items.
	 * @return array{items:list<array>,stale:bool,circuit:bool}|\WP_Error
	 */
	function newsai_google_trends_get_items( $geo, $limit = 8 ) {
		$geo     = newsai_google_trends_normalize_geo( $geo );
		$limit   = max( 1, min( 20, (int) $limit ) );
		$circuit = newsai_google_trends_is_circuit_open( $geo );
		$skip    = $circuit || (bool) get_transient( newsai_google_trends_negative_key( $geo ) );

		if ( $skip ) {
			$stale = newsai_google_trends_get_stale_items( $geo );
			if ( $stale !== [] ) {
				return [
					'items'   => array_slice( $stale, 0, $limit ),
					'stale'   => true,
					'circuit' => $circuit,
				];
			}
			return new WP_Error(
				'trends_circuit_open',
				__( 'Google Trends is temporarily unavailable. Please try again later.', 'newsroom-ai-assistant' ),
				[ 'circuit' => $circuit ]
			);
		}

		$rss = newsai_google_trends_fetch_feed( $geo );
		if ( is_wp_error( $rss ) ) {
			newsai_google_trends_record_failure( $geo, $rss->get_error_code() );
			$stale = newsai_google_trends_get_stale_items( $geo );
			if ( $stale !== [] ) {
				return [
					'items'   => array_slice( $stale, 0, $limit ),
					'stale'   => true,
					'circuit' => newsai_google_trends_is_circuit_open( $geo ),
				];
			}
			return $rss;
		}

		$items = newsai_google_trends_parse_feed_items( $rss, $limit );
		if ( $items === [] ) {
			newsai_google_trends_record_failure( $geo, 'empty_feed' );
			$stale = newsai_google_trends_get_stale_items( $geo );
			if ( $stale !== [] ) {
				return [
					'items'   => array_slice( $stale, 0, $limit ),
					'stale'   => true,
					'circuit' => newsai_google_trends_is_circuit_open( $geo ),
				];
			}
			return new WP_Error(
				'trends_empty',
				__( 'No trending topics were returned.', 'newsroom-ai-assistant' )
			);
		}

		newsai_google_trends_record_success( $geo );
		newsai_google_trends_store_stale_items( $geo, $items );

		return [
			'items'   => $items,
			'stale'   => false,
			'circuit' => false,
		];
	}
}

if ( ! function_exists( 'newsai_radar_row_action_html' ) ) {
	/**
	 * Per-row action button: desk brief vs editor copy.
	 *
	 * @param string $title   Row headline / trend term.
	 * @param string $context desk|editor.
	 * @return string
	 */
	function newsai_radar_row_action_html( $title, $context = 'desk' ) {
		$title = (string) $title;
		if ( $title === '' ) {
			return '';
		}
		$context = ( $context === 'editor' ) ? 'editor' : 'desk';
		if ( $context === 'editor' ) {
			$label = esc_attr__( 'Copy headline', 'newsroom-ai-assistant' );
			$html  = '<button type="button" class="nros-radar-row__action nros-radar-copy-btn" data-title="' . esc_attr( $title ) . '" aria-label="' . $label . '">';
			$html .= '<span class="nros-radar-row__action-icon" aria-hidden="true">⎘</span>';
			$html .= '<span class="nros-radar-row__action-label">' . esc_html__( 'Copy', 'newsroom-ai-assistant' ) . '</span>';
			$html .= '</button>';
			return $html;
		}
		$brief = esc_attr__( 'Add to brief', 'newsroom-ai-assistant' );
		$html  = '<button type="button" class="nros-radar-row__action nros-copy-task-btn" data-title="' . esc_attr( $title ) . '" aria-label="' . $brief . '">';
		$html .= '<span class="nros-radar-row__action-icon" aria-hidden="true">+</span>';
		$html .= '<span class="nros-radar-row__action-label">' . esc_html__( 'Brief', 'newsroom-ai-assistant' ) . '</span>';
		$html .= '</button>';
		return $html;
	}
}

if ( ! function_exists( 'newsai_google_trends_build_sidebar_html' ) ) {
	/**
	 * Render sidebar / radar HTML from parsed items.
	 *
	 * @param list<array{title:string,permalink:string,traffic:string,numeric_traffic:int}> $items Items.
	 * @param bool                                                                           $stale Whether data is from stale cache.
	 * @param string                                                                         $context desk|editor.
	 * @return string HTML.
	 */
	function newsai_google_trends_build_sidebar_html( array $items, $stale = false, $context = 'desk' ) {
		$is_gr    = function_exists( 'newsai_get_ui_lang' ) && newsai_get_ui_lang() === 'el';
		$srch_txt = $is_gr ? ' αναζητήσεις' : ' searches';
		$tr_txt   = $is_gr ? 'Τάση' : 'Trend';

		$html = '';
		if ( $stale ) {
			$notice = $is_gr
				? 'Εμφανίζονται αποθηκευμένα trends (προσωρινή διακοπή σύνδεσης με Google).'
				: 'Showing cached trends (Google Trends temporarily unreachable).';
			$html .= '<p class="nros-radar-stale-notice">' . esc_html( $notice ) . '</p>';
		}

		foreach ( $items as $item ) {
			$traffic         = (string) $item['traffic'];
			$numeric_traffic = (int) $item['numeric_traffic'];
			$display_traffic = $traffic ? $traffic . $srch_txt : $tr_txt;

			if ( $numeric_traffic >= 20000 ) {
				$badge_class = 'nros-radar-badge nros-radar-badge--mega';
				$badge_text  = '🚨 MEGA (' . esc_html( $display_traffic ) . ')';
			} elseif ( $numeric_traffic >= 5000 ) {
				$badge_class = 'nros-radar-badge nros-radar-badge--hot';
				$badge_text  = '🔥 HOT (' . esc_html( $display_traffic ) . ')';
			} else {
				$badge_class = 'nros-radar-badge nros-radar-badge--default';
				$badge_text  = '📈 ' . esc_html( $display_traffic );
			}

			$html .= '<div class="nros-radar-row">';
			$html .= '<div class="nros-radar-row__body">';
			$html .= '<span class="' . esc_attr( $badge_class ) . '">' . $badge_text . '</span>';
			$html .= '<a href="' . esc_url( $item['permalink'] ) . '" target="_blank" rel="noopener noreferrer" class="nros-radar-row__link" data-trend-term="' . esc_attr( $item['title'] ) . '">' . esc_html( $item['title'] ) . '</a>';
			$html .= '</div>';
			$html .= function_exists( 'newsai_radar_row_action_html' )
				? newsai_radar_row_action_html( $item['title'], $context )
				: '';
			$html .= '</div>';
		}

		return $html;
	}
}

if ( ! function_exists( 'newsai_google_trends_get_sidebar_html' ) ) {
	/**
	 * Full pipeline for AJAX sidebar: fetch items + render HTML.
	 *
	 * @param string $geo Geo code.
	 * @param string $context desk|editor.
	 * @return array{html:string,stale:bool}|\WP_Error
	 */
	function newsai_google_trends_get_sidebar_html( $geo, $context = 'desk' ) {
		$result = newsai_google_trends_get_items( $geo, 8 );
		if ( is_wp_error( $result ) ) {
			$stale_html = get_transient( newsai_google_trends_stale_html_key( $geo ) );
			if ( is_string( $stale_html ) && $stale_html !== '' ) {
				return [
					'html'  => $stale_html,
					'stale' => true,
				];
			}
			return $result;
		}

		$html = newsai_google_trends_build_sidebar_html( $result['items'], ! empty( $result['stale'] ), $context );
		if ( empty( $result['stale'] ) && $html !== '' ) {
			set_transient(
				newsai_google_trends_stale_html_key( $geo ),
				newsai_google_trends_build_sidebar_html( $result['items'], true, 'desk' ),
				NEWSAI_TRENDS_STALE_TTL
			);
		}

		return [
			'html'  => $html,
			'stale' => ! empty( $result['stale'] ),
		];
	}
}
