<?php
/**
 * Dataset Quality — Hookable facade for Meta Dataset Quality API data.
 *
 * FREE PLUGIN: This class does NOT call the Meta API itself.
 * It provides a clean interface for reading cached data and exposes
 * filters at every method for the Pro plugin to hook into.
 *
 * Data flow:
 *   Pro plugin → fetches from Meta API → saves to CACHE_OPTION
 *   This class → reads from CACHE_OPTION → returns to callers
 *   If Pro not active → all methods return sensible defaults (null, [])
 *
 * Daily cron (capiflow_fetch_dataset_quality) is still scheduled by
 * class-plugin-loader.php. Free: fetch_from_meta() is a no-op.
 * Pro: hooks into 'capiflow_dataset_quality_do_fetch' filter.
 *
 * @package CapiFlow
 */

namespace CapiFlow\Core;

defined( 'ABSPATH' ) || exit;

class Dataset_Quality {

	/** @var string WP option key for cached quality data. */
	const CACHE_OPTION = 'capiflow_dataset_quality_cache';

	/** @var string WP option key for temporary API failure cooldown. */
	const FAILURE_OPTION = 'capiflow_dataset_quality_failed_at';

	/** @var int Cache TTL for failure cooldown (6 hours). */
	const CACHE_TTL = 6 * HOUR_IN_SECONDS;

	/** @var string WP option key for last successful fetch timestamp. */
	const LAST_FETCHED_OPTION = 'capiflow_dataset_quality_last_fetched';

	/**
	 * Fetch quality data from Meta API.
	 *
	 * FREE: No-op (intentionally does nothing).
	 * PRO: Hooks into 'capiflow_dataset_quality_do_fetch' and performs
	 *      the real API call with correct endpoint, fields, and parsing.
	 *
	 * Called by: Daily WP-Cron via capiflow_fetch_dataset_quality action
	 *            (scheduled in class-plugin-loader.php).
	 */
	public static function fetch_from_meta(): void {
		/**
		 * Filter: Let Pro plugin handle the actual API fetch.
		 *
		 * Return true from this filter to indicate fetch was handled.
		 * Pro hooks in with corrected endpoint, fields, parsing, 403 handling.
		 *
		 * @param bool $handled Whether the fetch has been handled. Default false.
		 */
		$handled = apply_filters( 'capiflow_dataset_quality_do_fetch', false );

		if ( $handled ) {
			return; // Pro handled it.
		}

		// Free: intentionally no-op.
		// Daily cron harmlessly runs and exits.
		// No broken API call, no silent errors, no wasted bandwidth.
	}

	/**
	 * Get cached quality data from wp_options.
	 *
	 * Works for BOTH Free and Pro:
	 * - Free (Pro not active): Returns empty array (no data ever saved).
	 * - Pro active: Returns data that Pro's fetch saved to this option.
	 *
	 * @return array Cached quality data or empty array.
	 */
	public static function get_cached(): array {
		$data = get_option( self::CACHE_OPTION, array() );
		return is_array( $data ) ? $data : array();
	}

	/**
	 * Get overall EMQ score across all events.
	 *
	 * Calculates from cached data if available (Pro has fetched and saved).
	 * Returns null if no data (Free without Pro, or Pro hasn't fetched yet).
	 *
	 * @return int|null Score 1-10 or null.
	 */
	public static function get_overall_score(): ?int {
		$cached = self::get_cached();
		$score  = null;

		if ( ! empty( $cached['web'] ) && is_array( $cached['web'] ) ) {
			$total = 0;
			$count = 0;
			foreach ( $cached['web'] as $item ) {
				if ( isset( $item['event_match_quality']['composite_score'] ) ) {
					$total += (float) $item['event_match_quality']['composite_score'];
					$count++;
				}
			}
			$score = $count > 0 ? (int) round( $total / $count ) : null;
		}

		/**
		 * Filter: Override the overall EMQ score.
		 *
		 * @param int|null $score Calculated score or null.
		 */
		return apply_filters( 'capiflow_dataset_overall_score', $score );
	}

	/**
	 * Get EMQ score for a specific event (e.g., 'Purchase', 'AddToCart').
	 *
	 * Reads from cached data. Returns null if event not found or no data.
	 *
	 * @param string $event_name Meta event name (case-insensitive match).
	 * @return float|null Score or null.
	 */
	public static function get_event_score( string $event_name ): ?float {
		$cached = self::get_cached();
		$score  = null;

		if ( ! empty( $cached['web'] ) && is_array( $cached['web'] ) ) {
			foreach ( $cached['web'] as $item ) {
				if ( isset( $item['event_name'] )
				     && strtolower( $item['event_name'] ) === strtolower( $event_name )
				     && isset( $item['event_match_quality']['composite_score'] ) ) {
					$score = (float) $item['event_match_quality']['composite_score'];
					break;
				}
			}
		}

		/**
		 * Filter: Override per-event EMQ score.
		 *
		 * @param float|null $score  Event score or null.
		 * @param string     $event_name Event name queried.
		 */
		return apply_filters( 'capiflow_dataset_event_score', $score, $event_name );
	}

	/**
	 * Get EMQ diagnostics from all events.
	 *
	 * Called by: admin/views/system-health.php line 263.
	 * Free: Returns empty array (no diagnostics without API data).
	 * Pro: Returns via filter OR from cached data.
	 *
	 * @return array Array of diagnostic items, each with 'event_name' attached.
	 */
	public static function get_diagnostics(): array {
		$cached  = self::get_cached();
		$results = array();

		if ( ! empty( $cached['web'] ) && is_array( $cached['web'] ) ) {
			foreach ( $cached['web'] as $item ) {
				$event = $item['event_name'] ?? 'Unknown';
				$diags = $item['event_match_quality']['diagnostics'] ?? array();
				foreach ( $diags as $d ) {
					$d['event_name'] = $event;
					$results[]       = $d;
				}
			}
		}

		/**
		 * Filter: Override EMQ diagnostics array.
		 *
		 * @param array $results Diagnostic items.
		 */
		return apply_filters( 'capiflow_dataset_diagnostics', $results );
	}

	/**
	 * Get ACR (Additional Conversions Reported) summary per event.
	 *
	 * Free: Returns empty array.
	 * Pro: Returns via filter from cached data.
	 *
	 * @return array Array of [ 'event_name' => '...', 'percentage' => 37.9, 'description' => '...' ]
	 */
	public static function get_acr_summary(): array {
		/**
		 * Filter: Provide ACR summary data.
		 * Pro hooks in to extract from cached API response.
		 *
		 * @param array $acr_data Default empty array.
		 */
		return apply_filters( 'capiflow_dataset_acr_summary', array() );
	}

	/**
	 * Get historical EMQ snapshots (last 30 days).
	 *
	 * Free: Returns empty array.
	 * Pro: Returns via filter from wp_options history.
	 *
	 * @return array Array of daily snapshots.
	 */
	public static function get_history(): array {
		/**
		 * Filter: Provide EMQ history data.
		 * Pro hooks in to read from capiflow_emq_history option.
		 *
		 * @param array $history Default empty array.
		 */
		return apply_filters( 'capiflow_dataset_history', array() );
	}

	/**
	 * Get timestamp of last successful API fetch.
	 *
	 * Free: Returns null (never fetched).
	 * Pro: Returns via filter from wp_options.
	 *
	 * @return string|null Unix timestamp as string, or null.
	 */
	public static function get_last_fetched(): ?string {
		/**
		 * Filter: Provide last fetch timestamp.
		 * Pro hooks in to read from LAST_FETCHED_OPTION.
		 *
		 * @param string|null $timestamp Default null.
		 */
		return apply_filters( 'capiflow_dataset_last_fetched', null );
	}

	/**
	 * Get the EMQ score for the Purchase event.
	 *
	 * Convenience alias for get_event_score('Purchase').
	 * Called by: class-admin-settings.php line 466, class-dashboard-widget.php line 66.
	 * Both callers use method_exists() guard.
	 *
	 * @return int|null EMQ score 0-10, or null if not yet available.
	 */
	public static function get_purchase_emq(): ?int {
		$score = self::get_event_score( 'Purchase' );
		return null !== $score ? (int) round( $score ) : null;
	}
}
