<?php
/**
 * CrUX / Core Web Vitals via PageSpeed Insights (field data).
 *
 * Note: PageSpeed Insights uses an API key or anonymous quota — not the GSC service-account OAuth token.
 */
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! function_exists( 'newsai_crux_get_api_key' ) ) {
	function newsai_crux_get_api_key() {
		return trim( (string) get_option( 'newsai_psi_api_key', '' ) );
	}
}

if ( ! function_exists( 'newsai_crux_has_service_account' ) ) {
	function newsai_crux_has_service_account() {
		if ( function_exists( 'newsai_gsc_has_service_account' ) ) {
			return newsai_gsc_has_service_account();
		}
		$json_raw = function_exists( 'newsai_secret_get' )
			? newsai_secret_get( 'indexing_service_json' )
			: (string) get_option( 'newsai_indexing_service_json', '' );
		return trim( $json_raw ) !== '';
	}
}

if ( ! function_exists( 'newsai_crux_guess_url_from_gsc_property' ) ) {
	/**
	 * Map Search Console property → PageSpeed test URL (full https://).
	 *
	 * @param string $sc_property GSC property string.
	 * @return string Empty when not derivable.
	 */
	function newsai_crux_guess_url_from_gsc_property( $sc_property ) {
		$sc = trim( (string) $sc_property );
		if ( $sc === '' ) {
			return '';
		}
		if ( preg_match( '#^https?://#i', $sc ) ) {
			return esc_url_raw( trailingslashit( $sc ) );
		}
		if ( stripos( $sc, 'sc-domain:' ) === 0 ) {
			$host = trim( substr( $sc, 10 ) );
			if ( $host !== '' ) {
				return esc_url_raw( 'https://' . $host . '/' );
			}
		}
		if ( strpos( $sc, '://' ) === false && strpos( $sc, ' ' ) === false ) {
			return esc_url_raw( 'https://' . ltrim( $sc, '/' ) . '/' );
		}
		return '';
	}
}

if ( ! function_exists( 'newsai_crux_origin_url' ) ) {
	function newsai_crux_origin_url() {
		$custom = trim( (string) get_option( 'newsai_crux_origin_url', '' ) );
		if ( $custom !== '' ) {
			return esc_url_raw( trailingslashit( $custom ) );
		}
		$from_gsc = newsai_crux_guess_url_from_gsc_property( (string) get_option( 'newsai_indexing_sc_property', '' ) );
		if ( $from_gsc !== '' ) {
			return $from_gsc;
		}
		return esc_url_raw( trailingslashit( home_url( '/' ) ) );
	}
}

if ( ! function_exists( 'newsai_crux_psi_error_message' ) ) {
	/**
	 * @param array|null $body Decoded JSON error body.
	 * @param int        $code HTTP code.
	 */
	function newsai_crux_psi_error_message( $body, $code ) {
		if ( is_array( $body ) && isset( $body['error']['message'] ) ) {
			return (string) $body['error']['message'];
		}
		if ( is_array( $body ) && ! empty( $body['error'] ) && is_string( $body['error'] ) ) {
			return (string) $body['error'];
		}
		if ( 403 === $code ) {
			return __( 'PageSpeed Insights API is not enabled or the API key is invalid. Enable the API in Google Cloud (see Settings → Instant Indexing).', 'newsroom-ai-assistant' );
		}
		return sprintf(
			/* translators: %d: HTTP status code */
			__( 'PageSpeed API error (HTTP %d).', 'newsroom-ai-assistant' ),
			(int) $code
		);
	}
}

if ( ! function_exists( 'newsai_crux_fetch_metrics' ) ) {
	/**
	 * @param string $url Page URL (https://…).
	 * @return array{ok:bool, data:array, error:string}
	 */
	function newsai_crux_fetch_metrics( $url ) {
		$url = esc_url_raw( trailingslashit( (string) $url ) );
		if ( $url === '' || ! preg_match( '#^https?://#i', $url ) ) {
			return [
				'ok'    => false,
				'data'  => [],
				'error' => __( 'Enter a full page URL starting with https:// (not sc-domain:).', 'newsroom-ai-assistant' ),
			];
		}

		$query = [
			'url'      => $url,
			'strategy' => 'mobile',
			'category' => 'performance',
		];
		$api_key = newsai_crux_get_api_key();
		if ( $api_key !== '' ) {
			$query['key'] = $api_key;
		}

		$endpoint = add_query_arg( $query, 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed' );
		$res      = wp_remote_get(
			$endpoint,
			[
				'timeout' => 45,
				'headers' => [ 'Accept' => 'application/json' ],
			]
		);

		if ( is_wp_error( $res ) ) {
			return [ 'ok' => false, 'data' => [], 'error' => $res->get_error_message() ];
		}

		$code = (int) wp_remote_retrieve_response_code( $res );
		$body = json_decode( (string) wp_remote_retrieve_body( $res ), true );
		if ( $code !== 200 || ! is_array( $body ) ) {
			return [
				'ok'    => false,
				'data'  => [],
				'error' => newsai_crux_psi_error_message( is_array( $body ) ? $body : null, $code ),
			];
		}

		$loading = isset( $body['loadingExperience'] ) && is_array( $body['loadingExperience'] )
			? $body['loadingExperience']
			: [];
		$metrics = isset( $loading['metrics'] ) && is_array( $loading['metrics'] ) ? $loading['metrics'] : [];

		$pick = static function ( $key ) use ( $metrics ) {
			if ( ! isset( $metrics[ $key ] ) || ! is_array( $metrics[ $key ] ) ) {
				return null;
			}
			$m = $metrics[ $key ];
			return [
				'percentile' => isset( $m['percentile'] ) ? (float) $m['percentile'] : null,
				'category'   => isset( $m['category'] ) ? sanitize_key( (string) $m['category'] ) : '',
			];
		};

		$data = [
			'url'      => $url,
			'checked'  => gmdate( 'c' ),
			'lcp'      => $pick( 'LARGEST_CONTENTFUL_PAINT_MS' ),
			'inp'      => $pick( 'INTERACTION_TO_NEXT_PAINT' ) ?? $pick( 'EXPERIMENTAL_INTERACTION_TO_NEXT_PAINT' ),
			'cls'      => $pick( 'CUMULATIVE_LAYOUT_SHIFT_SCORE' ),
			'origin'   => isset( $loading['origin_fallback'] ) ? (bool) $loading['origin_fallback'] : false,
			'strategy' => 'mobile',
		];

		set_transient( 'newsai_crux_last_snapshot', $data, 12 * HOUR_IN_SECONDS );

		return [ 'ok' => true, 'data' => $data, 'error' => '' ];
	}
}

if ( ! function_exists( 'newsai_crux_format_metric' ) ) {
	function newsai_crux_format_metric( $metric, $kind = 'lcp' ) {
		if ( ! is_array( $metric ) || ! isset( $metric['percentile'] ) ) {
			return [
				'display'  => '—',
				'class'    => 'is-neutral',
				'category' => '',
			];
		}
		$val   = (float) $metric['percentile'];
		$cat   = sanitize_key( (string) ( $metric['category'] ?? '' ) );
		$class = 'is-neutral';
		if ( $cat === 'FAST' ) {
			$class = 'is-good';
		} elseif ( $cat === 'AVERAGE' ) {
			$class = 'is-warn';
		} elseif ( $cat === 'SLOW' ) {
			$class = 'is-bad';
		}
		if ( 'cls' === $kind ) {
			$display = number_format_i18n( $val / 100, 3 );
		} elseif ( 'inp' === $kind ) {
			$display = number_format_i18n( $val, 0 ) . ' ms';
		} else {
			$display = number_format_i18n( $val / 1000, 2 ) . ' s';
		}
		return [
			'display'  => $display,
			'class'    => $class,
			'category' => $cat,
		];
	}
}

if ( ! function_exists( 'newsai_crux_render_panel' ) ) {
	function newsai_crux_render_panel() {
		if ( ! current_user_can( 'edit_others_posts' ) ) {
			return;
		}
		$snap = get_transient( 'newsai_crux_last_snapshot' );
		$url  = newsai_crux_origin_url();
		$has_key = newsai_crux_get_api_key() !== '';
		?>
		<div class="nros-crux-panel" id="nros-crux-panel">
			<div class="nros-crux-panel__head">
				<div>
					<h3><?php echo esc_html__( 'Core Web Vitals (CrUX)', 'newsroom-ai-assistant' ); ?></h3>
					<p class="nros-crux-panel__sub"><?php echo esc_html__( 'Real-user field data via PageSpeed Insights (mobile).', 'newsroom-ai-assistant' ); ?></p>
				</div>
				<button type="button" class="button button-secondary" id="nros-crux-check-btn">
					<?php echo esc_html__( 'Check now', 'newsroom-ai-assistant' ); ?>
				</button>
			</div>
			<p class="nros-crux-panel__hint">
				<?php
				if ( $has_key ) {
					echo esc_html__( 'Using your PageSpeed Insights API key from Settings → Instant Indexing.', 'newsroom-ai-assistant' );
				} else {
					echo esc_html__( 'Enable PageSpeed Insights API in Google Cloud, then add an optional API key under Settings → Instant Indexing for reliable checks.', 'newsroom-ai-assistant' );
				}
				?>
			</p>
			<p class="nros-crux-panel__url"><code><?php echo esc_html( $url ); ?></code></p>
			<div class="nros-crux-panel__metrics" id="nros-crux-metrics">
				<?php echo newsai_crux_render_metrics_html( is_array( $snap ) ? $snap : [] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
			</div>
		</div>
		<?php
	}
}

if ( ! function_exists( 'newsai_crux_render_metrics_html' ) ) {
	function newsai_crux_render_metrics_html( array $snap ) {
		if ( empty( $snap ) ) {
			return '<p class="nros-crux-panel__empty">' . esc_html__( 'No CWV data yet. Click Check now after enabling PageSpeed Insights API.', 'newsroom-ai-assistant' ) . '</p>';
		}
		$lcp     = newsai_crux_format_metric( $snap['lcp'] ?? null, 'lcp' );
		$inp     = newsai_crux_format_metric( $snap['inp'] ?? null, 'inp' );
		$cls     = newsai_crux_format_metric( $snap['cls'] ?? null, 'cls' );
		$checked = isset( $snap['checked'] ) ? sanitize_text_field( (string) $snap['checked'] ) : '';
		ob_start();
		?>
		<div class="nros-crux-metric">
			<div class="nros-crux-metric__lbl">LCP</div>
			<div class="nros-crux-metric__val <?php echo esc_attr( $lcp['class'] ); ?>"><?php echo esc_html( $lcp['display'] ); ?></div>
		</div>
		<div class="nros-crux-metric">
			<div class="nros-crux-metric__lbl">INP</div>
			<div class="nros-crux-metric__val <?php echo esc_attr( $inp['class'] ); ?>"><?php echo esc_html( $inp['display'] ); ?></div>
		</div>
		<div class="nros-crux-metric">
			<div class="nros-crux-metric__lbl">CLS</div>
			<div class="nros-crux-metric__val <?php echo esc_attr( $cls['class'] ); ?>"><?php echo esc_html( $cls['display'] ); ?></div>
		</div>
		<?php if ( $checked !== '' ) : ?>
			<p class="nros-crux-panel__meta"><?php echo esc_html( sprintf( /* translators: %s: ISO datetime */ __( 'Last check: %s UTC', 'newsroom-ai-assistant' ), $checked ) ); ?></p>
		<?php endif; ?>
		<?php
		return (string) ob_get_clean();
	}
}

if ( ! function_exists( 'newsai_ajax_crux_check' ) ) {
	function newsai_ajax_crux_check() {
		check_ajax_referer( 'newsai_ajax_nonce', 'nonce' );
		if ( ! current_user_can( 'edit_others_posts' ) ) {
			wp_send_json_error( [ 'message' => 'forbidden' ], 403 );
		}
		if ( ! function_exists( 'newsai_is_pro' ) || ! newsai_is_pro() ) {
			wp_send_json_error( [ 'message' => 'pro_required' ], 403 );
		}
		$url = isset( $_POST['url'] ) ? esc_url_raw( wp_unslash( (string) $_POST['url'] ) ) : newsai_crux_origin_url();
		$res = newsai_crux_fetch_metrics( $url );
		if ( empty( $res['ok'] ) ) {
			wp_send_json_error( [ 'message' => (string) $res['error'] ], 400 );
		}
		wp_send_json_success(
			[
				'data' => $res['data'],
				'html' => newsai_crux_render_metrics_html( $res['data'] ),
			]
		);
	}
}
add_action( 'wp_ajax_newsai_crux_check', 'newsai_ajax_crux_check' );

if ( ! function_exists( 'newsai_crux_save_settings' ) ) {
	function newsai_crux_save_settings() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		if ( isset( $_POST['newsai_psi_api_key'] ) ) {
			update_option( 'newsai_psi_api_key', sanitize_text_field( wp_unslash( (string) $_POST['newsai_psi_api_key'] ) ), false );
		}
		if ( isset( $_POST['newsai_crux_origin_url'] ) ) {
			$raw = trim( (string) wp_unslash( $_POST['newsai_crux_origin_url'] ) );
			update_option( 'newsai_crux_origin_url', $raw !== '' ? esc_url_raw( trailingslashit( $raw ) ) : '', false );
		}
	}
}
