<?php
/**
 * Open Graph analyzer.
 *
 * Checks Open Graph and Twitter Card meta tag readiness.
 *
 * @package MonitorCat\Modules\Seo\Analyzer
 */

declare(strict_types=1);

namespace MonitorCat\Modules\Seo\Analyzer;

defined( 'ABSPATH' ) || exit;

/**
 * Analyzes Open Graph and Twitter Card meta tag presence.
 */
final class OpenGraphAnalyzer {

	/**
	 * SEO plugin meta keys for OG title.
	 *
	 * @var array<int, string>
	 */
	private const OG_TITLE_KEYS = array(
		'_yoast_wpseo_opengraph-title',
		'_aioseo_og_title',
		'rank_math_facebook_title',
	);

	/**
	 * SEO plugin meta keys for OG description.
	 *
	 * @var array<int, string>
	 */
	private const OG_DESC_KEYS = array(
		'_yoast_wpseo_opengraph-description',
		'_aioseo_og_description',
		'rank_math_facebook_description',
	);

	/**
	 * Run the Open Graph analysis on a post.
	 *
	 * @param int $post_id The post ID to analyze.
	 * @return array{score: int, status: string, checks: array<int, array{label: string, status: string, message: string, value: string|null}>}
	 */
	public function analyze( int $post_id ): array {
		$checks = array();

		$checks[] = $this->check_seo_plugin_active();
		$checks[] = $this->check_og_title( $post_id );
		$checks[] = $this->check_og_description( $post_id );
		$checks[] = $this->check_og_image( $post_id );

		$score  = $this->calculate_score( $checks );
		$status = $this->determine_status( $score );

		return array(
			'score'  => $score,
			'status' => $status,
			'checks' => $checks,
		);
	}

	/**
	 * Check if an SEO plugin that handles OG tags is active.
	 *
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_seo_plugin_active(): array {
		$plugin = $this->detect_seo_plugin();

		if ( null !== $plugin ) {
			return array(
				'label'   => __( 'SEO Plugin', 'monitor-cat' ),
				'status'  => 'pass',
				/* translators: %s: SEO plugin name */
				'message' => sprintf( __( '%s is active and handles Open Graph tags.', 'monitor-cat' ), $plugin ),
				'value'   => $plugin,
			);
		}

		return array(
			'label'   => __( 'SEO Plugin', 'monitor-cat' ),
			'status'  => 'warning',
			'message' => __( 'No SEO plugin detected. Open Graph tags may not be generated automatically.', 'monitor-cat' ),
			'value'   => null,
		);
	}

	/**
	 * Check for OG title meta.
	 *
	 * @param int $post_id The post ID.
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_og_title( int $post_id ): array {
		foreach ( self::OG_TITLE_KEYS as $key ) {
			$value = get_post_meta( $post_id, $key, true );
			if ( ! empty( $value ) && is_string( $value ) ) {
				return array(
					'label'   => __( 'OG Title', 'monitor-cat' ),
					'status'  => 'pass',
					'message' => __( 'Open Graph title is set.', 'monitor-cat' ),
					'value'   => $value,
				);
			}
		}

		// If an SEO plugin is active, it likely uses the post title as fallback.
		if ( null !== $this->detect_seo_plugin() ) {
			return array(
				'label'   => __( 'OG Title', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'OG title will use the post title via the active SEO plugin.', 'monitor-cat' ),
				'value'   => get_the_title( $post_id ),
			);
		}

		return array(
			'label'   => __( 'OG Title', 'monitor-cat' ),
			'status'  => 'warning',
			'message' => __( 'No explicit OG title set and no SEO plugin detected to generate one.', 'monitor-cat' ),
			'value'   => null,
		);
	}

	/**
	 * Check for OG description meta.
	 *
	 * @param int $post_id The post ID.
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_og_description( int $post_id ): array {
		foreach ( self::OG_DESC_KEYS as $key ) {
			$value = get_post_meta( $post_id, $key, true );
			if ( ! empty( $value ) && is_string( $value ) ) {
				return array(
					'label'   => __( 'OG Description', 'monitor-cat' ),
					'status'  => 'pass',
					'message' => __( 'Open Graph description is set.', 'monitor-cat' ),
					'value'   => $value,
				);
			}
		}

		if ( null !== $this->detect_seo_plugin() ) {
			return array(
				'label'   => __( 'OG Description', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'OG description will be generated by the active SEO plugin.', 'monitor-cat' ),
				'value'   => null,
			);
		}

		return array(
			'label'   => __( 'OG Description', 'monitor-cat' ),
			'status'  => 'warning',
			'message' => __( 'No OG description set and no SEO plugin detected to generate one.', 'monitor-cat' ),
			'value'   => null,
		);
	}

	/**
	 * Check for OG image (featured image).
	 *
	 * @param int $post_id The post ID.
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_og_image( int $post_id ): array {
		if ( has_post_thumbnail( $post_id ) ) {
			$image_url = get_the_post_thumbnail_url( $post_id, 'full' );

			return array(
				'label'   => __( 'OG Image', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'Featured image is set, which serves as the OG image.', 'monitor-cat' ),
				'value'   => is_string( $image_url ) ? $image_url : null,
			);
		}

		return array(
			'label'   => __( 'OG Image', 'monitor-cat' ),
			'status'  => 'fail',
			'message' => __( 'No featured image set. Social shares will lack a preview image.', 'monitor-cat' ),
			'value'   => null,
		);
	}

	/**
	 * Detect which SEO plugin is active.
	 *
	 * @return string|null The plugin name, or null if none detected.
	 */
	private function detect_seo_plugin(): ?string {
		if ( defined( 'WPSEO_VERSION' ) ) {
			return 'Yoast SEO';
		}

		if ( defined( 'AIOSEO_VERSION' ) ) {
			return 'All in One SEO';
		}

		if ( defined( 'RANK_MATH_VERSION' ) ) {
			return 'Rank Math';
		}

		// Check if Monitor.Cat auto meta tags are enabled.
		$mc_settings = get_option( 'monitorcat_settings', array() );
		$mc_settings = is_array( $mc_settings ) ? $mc_settings : array();
		$auto_meta   = $mc_settings['seo']['auto_meta_tags'] ?? true;

		if ( $auto_meta ) {
			return 'Monitor.Cat';
		}

		return null;
	}

	/**
	 * Calculate weighted score from checks.
	 *
	 * @param array<int, array{label: string, status: string, message: string, value: string|null}> $checks The checks array.
	 * @return int Score from 0 to 100.
	 */
	private function calculate_score( array $checks ): int {
		if ( empty( $checks ) ) {
			return 0;
		}

		$weights = array( 20, 25, 25, 30 );
		$total   = 0;

		foreach ( $checks as $index => $check ) {
			$weight     = $weights[ $index ] ?? 25;
			$multiplier = 'pass' === $check['status'] ? 1.0 : ( 'warning' === $check['status'] ? 0.5 : 0.0 );
			$total     += $weight * $multiplier;
		}

		return (int) round( $total );
	}

	/**
	 * Determine overall status from score.
	 *
	 * @param int $score The calculated score.
	 * @return string 'pass', 'warning', or 'fail'.
	 */
	private function determine_status( int $score ): string {
		if ( $score >= 80 ) {
			return 'pass';
		}

		if ( $score >= 50 ) {
			return 'warning';
		}

		return 'fail';
	}
}
