<?php
/**
 * Schema / structured data analyzer.
 *
 * Checks for structured data support via SEO plugins or theme.
 *
 * @package MonitorCat\Modules\Seo\Analyzer
 */

declare(strict_types=1);

namespace MonitorCat\Modules\Seo\Analyzer;

defined( 'ABSPATH' ) || exit;

/**
 * Analyzes structured data (JSON-LD / Schema.org) readiness.
 */
final class SchemaAnalyzer {

	/**
	 * Run the schema 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_schema();
		$checks[] = $this->check_schema_plugin();
		$checks[] = $this->check_json_ld_in_content( $post_id );
		$checks[] = $this->check_recommended_schema( $post_id );

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

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

	/**
	 * Check if a major SEO plugin provides schema support.
	 *
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_seo_plugin_schema(): array {
		// Check if Monitor.Cat auto-schema is enabled.
		$mc_settings = get_option( 'monitorcat_settings', array() );
		$mc_settings = is_array( $mc_settings ) ? $mc_settings : array();
		$auto_schema = $mc_settings['seo']['auto_schema'] ?? true;

		if ( $auto_schema && ! defined( 'WPSEO_VERSION' ) && ! defined( 'AIOSEO_VERSION' ) && ! defined( 'RANK_MATH_VERSION' ) ) {
			return array(
				'label'   => __( 'SEO Plugin Schema', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'Monitor.Cat is generating JSON-LD structured data (WebSite, Organization, Article, BreadcrumbList, FAQPage).', 'monitor-cat' ),
				'value'   => 'Monitor.Cat',
			);
		}

		if ( defined( 'WPSEO_VERSION' ) ) {
			return array(
				'label'   => __( 'SEO Plugin Schema', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'Yoast SEO is active and provides structured data output.', 'monitor-cat' ),
				'value'   => 'Yoast SEO',
			);
		}

		if ( defined( 'AIOSEO_VERSION' ) ) {
			return array(
				'label'   => __( 'SEO Plugin Schema', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'All in One SEO is active and provides structured data output.', 'monitor-cat' ),
				'value'   => 'All in One SEO',
			);
		}

		if ( defined( 'RANK_MATH_VERSION' ) ) {
			return array(
				'label'   => __( 'SEO Plugin Schema', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'Rank Math is active and provides structured data output.', 'monitor-cat' ),
				'value'   => 'Rank Math',
			);
		}

		return array(
			'label'   => __( 'SEO Plugin Schema', 'monitor-cat' ),
			'status'  => 'warning',
			'message' => __( 'No schema generation is active. Enable auto-schema in Monitor.Cat settings.', 'monitor-cat' ),
			'value'   => null,
		);
	}

	/**
	 * Check if a dedicated schema plugin is active.
	 *
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_schema_plugin(): array {
		$schema_plugins = array(
			'wp-schema-pro/wp-schema-pro.php' => 'Schema Pro',
			'schema/schema.php'               => 'Schema',
			'schema-and-structured-data-for-wp/schema-and-structured-data-for-wp.php' => 'Schema & Structured Data for WP',
		);

		if ( ! function_exists( 'is_plugin_active' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}

		foreach ( $schema_plugins as $plugin_file => $plugin_name ) {
			if ( is_plugin_active( $plugin_file ) ) {
				return array(
					'label'   => __( 'Schema Plugin', 'monitor-cat' ),
					'status'  => 'pass',
					/* translators: %s: plugin name */
					'message' => sprintf( __( '%s is active for additional structured data.', 'monitor-cat' ), $plugin_name ),
					'value'   => $plugin_name,
				);
			}
		}

		// If Monitor.Cat or an SEO plugin already handles schema, don't penalize
		// for missing a dedicated schema plugin — it's not needed.
		if ( $this->has_schema_generation() ) {
			return array(
				'label'   => __( 'Schema Plugin', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'Schema is already handled by your SEO setup. A dedicated schema plugin is optional.', 'monitor-cat' ),
				'value'   => null,
			);
		}

		return array(
			'label'   => __( 'Schema Plugin', 'monitor-cat' ),
			'status'  => 'warning',
			'message' => __( 'No schema generation detected. Enable auto-schema in Monitor.Cat settings or install an SEO plugin.', 'monitor-cat' ),
			'value'   => null,
		);
	}

	/**
	 * Check if schema generation is active from any source.
	 *
	 * @return bool
	 */
	private function has_schema_generation(): bool {
		if ( defined( 'WPSEO_VERSION' ) || defined( 'AIOSEO_VERSION' ) || defined( 'RANK_MATH_VERSION' ) ) {
			return true;
		}

		$mc_settings = get_option( 'monitorcat_settings', array() );
		$mc_settings = is_array( $mc_settings ) ? $mc_settings : array();

		return (bool) ( $mc_settings['seo']['auto_schema'] ?? true );
	}

	/**
	 * Check for JSON-LD in the post content.
	 *
	 * @param int $post_id The post ID.
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_json_ld_in_content( int $post_id ): array {
		$content = get_post_field( 'post_content', $post_id );
		$content = is_string( $content ) ? $content : '';

		if ( preg_match( '/<script\s+type=["\']application\/ld\+json["\']/i', $content ) ) {
			return array(
				'label'   => __( 'Inline JSON-LD', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'JSON-LD structured data found in post content.', 'monitor-cat' ),
				'value'   => __( 'Present', 'monitor-cat' ),
			);
		}

		return array(
			'label'   => __( 'Inline JSON-LD', 'monitor-cat' ),
			'status'  => 'warning',
			'message' => __( 'No inline JSON-LD found in content. This is normal if a plugin handles schema output.', 'monitor-cat' ),
			'value'   => null,
		);
	}

	/**
	 * Recommend appropriate schema type for the post.
	 *
	 * @param int $post_id The post ID.
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_recommended_schema( int $post_id ): array {
		$post_type = get_post_type( $post_id );

		if ( 'post' === $post_type ) {
			$recommendation = 'Article';
		} elseif ( 'page' === $post_type ) {
			$recommendation = 'WebPage';
		} elseif ( 'product' === $post_type ) {
			$recommendation = 'Product';
		} else {
			$recommendation = 'WebPage';
		}

		return array(
			'label'   => __( 'Recommended Schema', 'monitor-cat' ),
			'status'  => 'pass',
			/* translators: 1: schema type, 2: post type */
			'message' => sprintf( __( 'Recommended schema type for this %2$s: %1$s.', 'monitor-cat' ), $recommendation, (string) $post_type ),
			'value'   => $recommendation,
		);
	}

	/**
	 * 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( 40, 20, 20, 20 );
		$total   = 0;

		foreach ( $checks as $index => $check ) {
			$weight     = $weights[ $index ] ?? 20;
			$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';
	}
}
