<?php
/**
 * Meta tag generator.
 *
 * Automatically generates meta title, description, Open Graph,
 * Twitter Card, and canonical tags when no SEO plugin is active.
 *
 * @package MonitorCat\Modules\Seo\Generator
 */

declare(strict_types=1);

namespace MonitorCat\Modules\Seo\Generator;

defined( 'ABSPATH' ) || exit;

use MonitorCat\Settings;

/**
 * Generates and outputs meta tags via wp_head.
 */
final class MetaTagGenerator {

	/**
	 * Maximum description length.
	 *
	 * @var int
	 */
	private const MAX_DESCRIPTION_LENGTH = 160;

	/**
	 * Plugin settings.
	 *
	 * @var Settings
	 */
	private Settings $settings;

	/**
	 * Constructor.
	 *
	 * @param Settings $settings Plugin settings.
	 */
	public function __construct( Settings $settings ) {
		$this->settings = $settings;
	}

	/**
	 * Register hooks.
	 */
	public function boot(): void {
		if ( ! $this->settings->get( 'seo.auto_meta_tags', true ) ) {
			return;
		}

		// Skip if a major SEO plugin handles meta tags.
		if ( defined( 'WPSEO_VERSION' ) || defined( 'AIOSEO_VERSION' ) || defined( 'RANK_MATH_VERSION' ) ) {
			return;
		}

		add_filter( 'pre_get_document_title', array( $this, 'filter_title' ), 10 );
		add_action( 'wp_head', array( $this, 'render' ), 1 );
	}

	/**
	 * Filter the document title using the template.
	 *
	 * @param string $title The current title.
	 * @return string The filtered title.
	 */
	public function filter_title( string $title ): string {
		if ( ! is_singular() ) {
			return $title;
		}

		$post = get_queried_object();
		if ( ! $post || ! isset( $post->ID ) ) {
			return $title;
		}

		return $this->build_title( $post );
	}

	/**
	 * Build the page title from template.
	 *
	 * @param object $post The post object.
	 * @return string The built title.
	 */
	public function build_title( object $post ): string {
		$template  = $this->settings->get( 'seo.meta_title_template', '{post_title} {separator} {site_name}' );
		$template  = is_string( $template ) ? $template : '{post_title} {separator} {site_name}';
		$separator = $this->settings->get( 'seo.meta_separator', '|' );
		$separator = is_string( $separator ) ? $separator : '|';

		$replacements = array(
			'{post_title}' => get_the_title( $post->ID ),
			'{site_name}'  => get_bloginfo( 'name' ),
			'{separator}'  => $separator,
		);

		return str_replace( array_keys( $replacements ), array_values( $replacements ), $template );
	}

	/**
	 * Build the meta description from post excerpt or content.
	 *
	 * @param object $post The post object.
	 * @return string The meta description.
	 */
	public function build_description( object $post ): string {
		$excerpt = get_the_excerpt( $post->ID );

		if ( ! empty( $excerpt ) ) {
			$text = wp_strip_all_tags( $excerpt );
		} else {
			$content = get_post_field( 'post_content', $post->ID );
			$content = is_string( $content ) ? $content : '';
			$text    = wp_strip_all_tags( $content );
		}

		$text = trim( preg_replace( '/\s+/', ' ', $text ) ?? $text );

		if ( mb_strlen( $text ) > self::MAX_DESCRIPTION_LENGTH ) {
			$text = mb_substr( $text, 0, self::MAX_DESCRIPTION_LENGTH - 3 ) . '...';
		}

		return $text;
	}

	/**
	 * Output meta tags.
	 */
	public function render(): void {
		if ( ! is_singular() ) {
			return;
		}

		$post = get_queried_object();
		if ( ! $post || ! isset( $post->ID ) ) {
			return;
		}

		$title       = $this->build_title( $post );
		$description = $this->build_description( $post );
		$url         = get_permalink( $post->ID );
		$site_name   = get_bloginfo( 'name' );

		// Meta description.
		if ( ! empty( $description ) ) {
			echo '<meta name="description" content="' . esc_attr( $description ) . '" />' . "\n";
		}

		// Canonical.
		echo '<link rel="canonical" href="' . esc_url( $url ) . '" />' . "\n";

		// Open Graph.
		echo '<meta property="og:type" content="article" />' . "\n";
		echo '<meta property="og:title" content="' . esc_attr( $title ) . '" />' . "\n";
		if ( ! empty( $description ) ) {
			echo '<meta property="og:description" content="' . esc_attr( $description ) . '" />' . "\n";
		}
		echo '<meta property="og:url" content="' . esc_url( $url ) . '" />' . "\n";
		echo '<meta property="og:site_name" content="' . esc_attr( $site_name ) . '" />' . "\n";

		// OG Image.
		$image_url = get_the_post_thumbnail_url( $post->ID, 'large' );
		if ( $image_url ) {
			echo '<meta property="og:image" content="' . esc_url( $image_url ) . '" />' . "\n";
		}

		// Twitter Card.
		echo '<meta name="twitter:card" content="summary_large_image" />' . "\n";
		echo '<meta name="twitter:title" content="' . esc_attr( $title ) . '" />' . "\n";
		if ( ! empty( $description ) ) {
			echo '<meta name="twitter:description" content="' . esc_attr( $description ) . '" />' . "\n";
		}
		if ( $image_url ) {
			echo '<meta name="twitter:image" content="' . esc_url( $image_url ) . '" />' . "\n";
		}
	}
}
