<?php
/**
 * TamRank_Outdated_Detector
 *
 * Pure detection class. Given a post ID, returns all outdated year
 * occurrences found across: meta title, meta description, URL slug,
 * and content headings (h2-h6). No database writes — only reads.
 *
 * Detection rules:
 * - Title, meta title, meta description, slug: year < current year
 * - Content headings (h2-h6): year < current year - 1
 * - Content body text: not scanned (too many false positives from
 *   historical references like "WordPress exists since 2003")
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class TamRank_Outdated_Detector {

	/**
	 * Returns the current year (injectable for testing).
	 *
	 * @return int
	 */
	public static function get_current_year() {
		return (int) gmdate( 'Y' );
	}

	/**
	 * Detect outdated years in a post.
	 *
	 * @param int $post_id
	 * @return array Array of detection hits, each with keys: field, year, value.
	 *               Empty array when no outdated years found.
	 */
	public static function detect( $post_id ) {
		$post = get_post( $post_id );
		if ( ! $post || $post->post_status !== 'publish' ) {
			return array();
		}

		$current_year = self::get_current_year();
		$results      = array();

		// --- Field: post title (H1) — strict: < current year ---
		$results = array_merge( $results, self::scan_field( 'title', (string) $post->post_title, $current_year ) );

		// --- Field: meta title (SEO) — strict: < current year ---
		$meta_title = (string) get_post_meta( $post_id, '_tam_rank_meta_title', true );
		if ( $meta_title !== '' ) {
			$results = array_merge( $results, self::scan_field( 'meta_title', $meta_title, $current_year ) );
		}

		// --- Field: meta description — strict: < current year ---
		$meta_desc = (string) get_post_meta( $post_id, '_tam_rank_meta_description', true );
		$results   = array_merge( $results, self::scan_field( 'description', $meta_desc, $current_year ) );

		// --- Field: URL slug — strict: < current year ---
		$custom_slug = (string) get_post_meta( $post_id, '_tam_rank_custom_slug', true );
		$slug        = $custom_slug !== '' ? $custom_slug : (string) $post->post_name;
		$results     = array_merge( $results, self::scan_field( 'slug', $slug, $current_year ) );

		// --- Field: content headings (h2-h6) — lenient: < current year - 1 ---
		$headings = self::extract_headings( (string) $post->post_content );
		foreach ( $headings as $heading_text ) {
			$results = array_merge( $results, self::scan_field( 'content', $heading_text, $current_year - 1 ) );
		}

		return $results;
	}

	/**
	 * Extract text from h2-h6 headings in HTML content.
	 *
	 * @param string $html Post content HTML.
	 * @return array Array of heading text strings.
	 */
	private static function extract_headings( $html ) {
		if ( empty( $html ) ) {
			return array();
		}

		$headings = array();
		if ( preg_match_all( '/<h[2-6][^>]*>(.*?)<\/h[2-6]>/si', $html, $matches ) ) {
			foreach ( $matches[1] as $heading_html ) {
				$headings[] = wp_strip_all_tags( $heading_html );
			}
		}

		return $headings;
	}

	/**
	 * Scan a single text value for outdated years.
	 *
	 * @param string $field        Field name identifier (title|meta_title|description|slug|content).
	 * @param string $value        Text to scan.
	 * @param int    $threshold    Years strictly less than this are flagged.
	 * @return array
	 */
	private static function scan_field( $field, $value, $threshold ) {
		if ( empty( $value ) ) {
			return array();
		}

		// Match 4-digit years: 1900-2099
		preg_match_all( '/\b((?:19|20)\d{2})\b/', $value, $matches );

		$hits = array();
		foreach ( array_unique( $matches[1] ) as $year_str ) {
			$year = (int) $year_str;
			if ( $year < $threshold ) {
				$hits[] = array(
					'field' => $field,
					'year'  => $year,
					'value' => $value,
				);
			}
		}

		return $hits;
	}
}
