<?php
/**
 * Yoast SEO Compatibility Layer.
 *
 * When Yoast is active, Dennis SEO fields take priority over Yoast's output.
 * If a Dennis field is filled → suppress Yoast's output for that field, output Dennis's version.
 * If a Dennis field is empty → let Yoast handle it.
 *
 * For features Yoast doesn't have (llms.txt, AI crawlers, enhanced schema), always output.
 *
 * @package Dennis_SEO
 * @license GPL-2.0-or-later
 */

defined( 'ABSPATH' ) || exit;

class Dennis_SEO_Yoast_Compat {

	/**
	 * Is Yoast SEO active?
	 */
	public static function is_yoast_active(): bool {
		return defined( 'WPSEO_VERSION' );
	}

	public function __construct() {
		if ( ! self::is_yoast_active() ) {
			return;
		}

		// Selectively remove Yoast presenters when Dennis has data.
		add_filter( 'wpseo_frontend_presenter_classes', array( $this, 'filter_yoast_presenters' ), 999 );

		// Handle title tag — suppress Yoast's title when Dennis has one.
		add_filter( 'wpseo_title', array( $this, 'filter_yoast_title' ), 999 );

		// Handle robots — let Dennis manage robots when it has per-page settings.
		add_filter( 'wpseo_robots', array( $this, 'filter_yoast_robots' ), 999 );

		// Disable Yoast's schema when Dennis has schema type set or enhanced schema features.
		add_filter( 'wpseo_json_ld_output', array( $this, 'filter_yoast_schema' ), 999 );

		// Disable Yoast sitemap when Dennis sitemap is active.
		add_action( 'init', array( $this, 'maybe_disable_yoast_sitemap' ), 20 );
	}

	/**
	 * Remove Yoast presenter classes when Dennis has data for those fields.
	 */
	public function filter_yoast_presenters( array $presenters ): array {
		if ( ! is_singular() && ! is_front_page() ) {
			return $presenters;
		}

		$post_id = get_queried_object_id();
		if ( ! $post_id ) {
			return $presenters;
		}

		$remove = array();

		// Meta description.
		if ( $this->dennis_has_value( $post_id, '_dennis_seo_description' ) || $this->has_homepage_description() ) {
			$remove[] = 'Yoast\WP\SEO\Presenters\Meta_Description_Presenter';
		}

		// Canonical.
		if ( $this->dennis_has_value( $post_id, '_dennis_seo_canonical' ) ) {
			$remove[] = 'Yoast\WP\SEO\Presenters\Canonical_Presenter';
		}

		// Open Graph — if Dennis has OG title OR OG description, take over all OG.
		if ( $this->dennis_has_value( $post_id, '_dennis_seo_og_title' ) ||
			$this->dennis_has_value( $post_id, '_dennis_seo_og_description' ) ||
			$this->dennis_has_value( $post_id, '_dennis_seo_og_image' ) ) {
			$remove = array_merge( $remove, array(
				'Yoast\WP\SEO\Presenters\Open_Graph\Title_Presenter',
				'Yoast\WP\SEO\Presenters\Open_Graph\Description_Presenter',
				'Yoast\WP\SEO\Presenters\Open_Graph\Image_Presenter',
				'Yoast\WP\SEO\Presenters\Open_Graph\Url_Presenter',
				'Yoast\WP\SEO\Presenters\Open_Graph\Type_Presenter',
				'Yoast\WP\SEO\Presenters\Open_Graph\Site_Name_Presenter',
				'Yoast\WP\SEO\Presenters\Open_Graph\Locale_Presenter',
				'Yoast\WP\SEO\Presenters\Open_Graph\Article_Publisher_Presenter',
				'Yoast\WP\SEO\Presenters\Open_Graph\Article_Author_Presenter',
				'Yoast\WP\SEO\Presenters\Open_Graph\Article_Published_Time_Presenter',
				'Yoast\WP\SEO\Presenters\Open_Graph\Article_Modified_Time_Presenter',
			) );
		}

		// Twitter Cards — if Dennis has OG data, take over Twitter too (Dennis mirrors OG → Twitter).
		if ( $this->dennis_has_value( $post_id, '_dennis_seo_og_title' ) ||
			$this->dennis_has_value( $post_id, '_dennis_seo_og_description' ) ) {
			$remove = array_merge( $remove, array(
				'Yoast\WP\SEO\Presenters\Twitter\Card_Presenter',
				'Yoast\WP\SEO\Presenters\Twitter\Title_Presenter',
				'Yoast\WP\SEO\Presenters\Twitter\Description_Presenter',
				'Yoast\WP\SEO\Presenters\Twitter\Image_Presenter',
				'Yoast\WP\SEO\Presenters\Twitter\Creator_Presenter',
				'Yoast\WP\SEO\Presenters\Twitter\Site_Presenter',
			) );
		}

		if ( ! empty( $remove ) ) {
			$presenters = array_values( array_diff( $presenters, $remove ) );
		}

		return $presenters;
	}

	/**
	 * Filter Yoast's title output — replace with Dennis's title when set.
	 * Since Dennis doesn't hook pre_get_document_title when Yoast is active,
	 * we inject Dennis's title through Yoast's own filter.
	 */
	public function filter_yoast_title( string $title ): string {
		if ( is_front_page() || is_home() ) {
			$homepage_title = Dennis_SEO_Settings::get( 'homepage_title' );
			if ( ! empty( $homepage_title ) ) {
				return $homepage_title;
			}
		}

		if ( is_singular() ) {
			$post_id = get_queried_object_id();
			if ( $post_id ) {
				$dennis_title = get_post_meta( $post_id, '_dennis_seo_title', true );
				if ( ! empty( $dennis_title ) ) {
					return $dennis_title;
				}
			}
		}

		return $title; // No Dennis title — keep Yoast's.
	}

	/**
	 * Filter Yoast's robots output — return empty when Dennis has robots settings.
	 */
	public function filter_yoast_robots( string $robots ): string {
		if ( ! is_singular() ) {
			// Dennis outputs robots on all page types — let Dennis handle non-singular.
			return '';
		}

		$post_id = get_queried_object_id();
		if ( ! $post_id ) {
			return $robots;
		}

		// If Dennis has any robots setting (even '0'/empty from unchecked), Dennis is managing this page.
		// Dennis deletes the meta key when unchecked, so if the key exists, Dennis is active.
		$noindex = get_post_meta( $post_id, '_dennis_seo_robots_noindex', true );
		$nofollow = get_post_meta( $post_id, '_dennis_seo_robots_nofollow', true );

		// If either key has been explicitly set (not empty string), Dennis manages robots.
		if ( '1' === $noindex || '1' === $nofollow ) {
			return ''; // Dennis will output its own robots meta.
		}

		// Otherwise let Yoast handle it.
		return $robots;
	}

	/**
	 * Filter Yoast's schema output.
	 * If Dennis has a schema type override on this page, or if Dennis has enhanced schema
	 * (Organization with geo, hours, etc.), suppress Yoast's schema entirely for this page.
	 */
	public function filter_yoast_schema( $output ) {
		if ( ! is_singular() && ! is_front_page() ) {
			return $output;
		}

		$post_id = get_queried_object_id();

		// If Dennis has a schema type set on this page, Dennis takes over schema.
		if ( $post_id && $this->dennis_has_value( $post_id, '_dennis_seo_schema_type' ) ) {
			return false; // Disable Yoast schema, Dennis outputs its own @graph.
		}

		// If Dennis has enhanced Organization schema configured (geo, hours, parent org),
		// let Dennis handle the full schema to avoid duplicate/conflicting Organization blocks.
		$has_enhanced = ! empty( Dennis_SEO_Settings::get( 'org_geo_lat' ) )
			|| ! empty( Dennis_SEO_Settings::get( 'org_opening_hours' ) )
			|| ! empty( Dennis_SEO_Settings::get( 'org_parent_name' ) )
			|| ! empty( Dennis_SEO_Settings::get( 'org_service_area' ) );

		if ( $has_enhanced ) {
			return false; // Dennis's schema is richer, use it.
		}

		// Otherwise let Yoast handle schema.
		return $output;
	}

	/**
	 * Disable Yoast's XML sitemap when Dennis has its own.
	 */
	public function maybe_disable_yoast_sitemap(): void {
		// Only disable if Dennis sitemap is active (check if the class exists and rewrite is registered).
		if ( class_exists( 'Dennis_SEO_Sitemap' ) ) {
			add_filter( 'wpseo_sitemaps_enabled', '__return_false' );
		}
	}

	/**
	 * Check if a Dennis SEO field has a non-empty value.
	 */
	private function dennis_has_value( int $post_id, string $key ): bool {
		$value = get_post_meta( $post_id, $key, true );
		return '' !== $value && false !== $value;
	}

	/**
	 * Check if Dennis has a homepage description set in global settings.
	 */
	private function has_homepage_description(): bool {
		if ( ! is_front_page() ) {
			return false;
		}
		return ! empty( Dennis_SEO_Settings::get( 'homepage_description' ) );
	}
}
