<?php
/**
 * Robots.txt analyzer.
 *
 * Analyzes robots.txt and search engine visibility settings.
 *
 * @package MonitorCat\Modules\Seo\Analyzer
 */

declare(strict_types=1);

namespace MonitorCat\Modules\Seo\Analyzer;

defined( 'ABSPATH' ) || exit;

/**
 * Analyzes robots.txt configuration and search engine visibility.
 */
final class RobotsAnalyzer {

	/**
	 * Run the robots analysis on a post.
	 *
	 * @param int $post_id The post ID to analyze (used for context, robots is site-wide).
	 * @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 { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- shared analyzer interface.
		$checks = array();

		$checks[] = $this->check_blog_public();
		$checks[] = $this->check_robots_txt_exists();
		$checks[] = $this->check_restrictive_rules();
		$checks[] = $this->check_sitemap_reference();

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

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

	/**
	 * Check if the site is visible to search engines.
	 *
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_blog_public(): array {
		$blog_public = get_option( 'blog_public', '1' );

		if ( '1' === (string) $blog_public ) {
			return array(
				'label'   => __( 'Search Engine Visibility', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'Site is visible to search engines.', 'monitor-cat' ),
				'value'   => __( 'Visible', 'monitor-cat' ),
			);
		}

		return array(
			'label'   => __( 'Search Engine Visibility', 'monitor-cat' ),
			'status'  => 'fail',
			'message' => __( 'Search engines are discouraged from indexing this site. Change this in Settings > Reading if this is a production site.', 'monitor-cat' ),
			'value'   => __( 'Discouraged', 'monitor-cat' ),
		);
	}

	/**
	 * Check if robots.txt is accessible.
	 *
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_robots_txt_exists(): array {
		// Check for physical file first.
		$physical_path = ABSPATH . 'robots.txt';

		if ( file_exists( $physical_path ) ) {
			return array(
				'label'   => __( 'Robots.txt File', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'Physical robots.txt file exists at the site root.', 'monitor-cat' ),
				'value'   => __( 'Physical file', 'monitor-cat' ),
			);
		}

		// WordPress generates a virtual robots.txt.
		$robots_url = site_url( '/robots.txt' );
		$response   = wp_remote_head( $robots_url, array( 'timeout' => 5 ) );

		if ( is_wp_error( $response ) ) {
			return array(
				'label'   => __( 'Robots.txt File', 'monitor-cat' ),
				'status'  => 'warning',
				/* translators: %s: error message */
				'message' => sprintf( __( 'Could not check for robots.txt: %s', 'monitor-cat' ), $response->get_error_message() ),
				'value'   => null,
			);
		}

		$status_code = wp_remote_retrieve_response_code( $response );

		if ( 200 === $status_code ) {
			return array(
				'label'   => __( 'Robots.txt File', 'monitor-cat' ),
				'status'  => 'pass',
				'message' => __( 'WordPress virtual robots.txt is accessible.', 'monitor-cat' ),
				'value'   => __( 'Virtual (WordPress)', 'monitor-cat' ),
			);
		}

		return array(
			'label'   => __( 'Robots.txt File', 'monitor-cat' ),
			'status'  => 'fail',
			'message' => __( 'No robots.txt found. WordPress should generate one automatically.', 'monitor-cat' ),
			'value'   => null,
		);
	}

	/**
	 * Check for overly restrictive robots.txt rules.
	 *
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_restrictive_rules(): array {
		$robots_url = site_url( '/robots.txt' );
		$response   = wp_remote_get( $robots_url, array( 'timeout' => 5 ) );

		if ( is_wp_error( $response ) ) {
			return array(
				'label'   => __( 'Restrictive Rules', 'monitor-cat' ),
				'status'  => 'warning',
				'message' => __( 'Could not retrieve robots.txt to check for restrictive rules.', 'monitor-cat' ),
				'value'   => null,
			);
		}

		$body = wp_remote_retrieve_body( $response );

		if ( empty( $body ) ) {
			return array(
				'label'   => __( 'Restrictive Rules', 'monitor-cat' ),
				'status'  => 'warning',
				'message' => __( 'Robots.txt is empty.', 'monitor-cat' ),
				'value'   => null,
			);
		}

		// Check for "Disallow: /" which blocks everything.
		if ( preg_match( '/^Disallow:\s*\/\s*$/m', $body ) ) {
			return array(
				'label'   => __( 'Restrictive Rules', 'monitor-cat' ),
				'status'  => 'fail',
				'message' => __( 'Robots.txt contains "Disallow: /" which blocks all crawlers from the entire site.', 'monitor-cat' ),
				'value'   => 'Disallow: /',
			);
		}

		return array(
			'label'   => __( 'Restrictive Rules', 'monitor-cat' ),
			'status'  => 'pass',
			'message' => __( 'No overly restrictive rules found in robots.txt.', 'monitor-cat' ),
			'value'   => null,
		);
	}

	/**
	 * Check if robots.txt references a sitemap.
	 *
	 * @return array{label: string, status: string, message: string, value: string|null}
	 */
	private function check_sitemap_reference(): array {
		$robots_url = site_url( '/robots.txt' );
		$response   = wp_remote_get( $robots_url, array( 'timeout' => 5 ) );

		if ( is_wp_error( $response ) ) {
			return array(
				'label'   => __( 'Sitemap in Robots.txt', 'monitor-cat' ),
				'status'  => 'warning',
				'message' => __( 'Could not retrieve robots.txt to check for sitemap reference.', 'monitor-cat' ),
				'value'   => null,
			);
		}

		$body = wp_remote_retrieve_body( $response );

		if ( preg_match( '/^Sitemap:\s*(.+)$/im', $body, $match ) ) {
			return array(
				'label'   => __( 'Sitemap in Robots.txt', 'monitor-cat' ),
				'status'  => 'pass',
				/* translators: %s: sitemap URL */
				'message' => sprintf( __( 'Sitemap reference found: %s', 'monitor-cat' ), trim( $match[1] ) ),
				'value'   => trim( $match[1] ),
			);
		}

		return array(
			'label'   => __( 'Sitemap in Robots.txt', 'monitor-cat' ),
			'status'  => 'warning',
			'message' => __( 'No Sitemap directive found in robots.txt.', 'monitor-cat' ),
			'value'   => 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( 40, 20, 25, 15 );
		$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';
	}
}
