<?php
/**
 * Odysseo SEO — <head> output with the smart fallback chain.
 *
 * Single source of the document title, meta description and OG/Twitter tags.
 * Priority: manual/AI field -> existing data (title, excerpt-then-content,
 * featured-then-default image). Tags are never empty.
 *
 * @package    Odysseo
 * @author     Chandrabhan Shekhawat
 * @company    Gigai Kripa Services
 * @link       https://gigaikripaservices.com/
 * @copyright  Copyright (c) 2026, Gigai Kripa Services
 */

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

/**
 * Builds and prints the head meta.
 */
class Odysseo_SEO_Head {

	/**
	 * Hook up. GSC verification always runs; the meta/OG output defers to a real
	 * SEO plugin if one is active.
	 */
	public function __construct() {
		add_action( 'wp_head', array( $this, 'output_gsc' ), 1 );

		if ( odysseo_seo_other_plugin_active() ) {
			return;
		}
		add_filter( 'pre_get_document_title', array( $this, 'filter_title' ), 20 );
		add_action( 'wp_head', array( $this, 'output' ), 1 );
		add_action( 'init', array( $this, 'retire_legacy' ), 99 );
	}

	/**
	 * Detaches the theme's inline head-meta hook so this class is the sole source.
	 */
	public function retire_legacy() {
		if ( function_exists( 'odysseo_output_seo_meta' ) ) {
			remove_action( 'wp_head', 'odysseo_output_seo_meta', 1 );
		}
	}

	/* ---------------------------------------------------------------------- *
	 *  Value resolvers (the fallback chain).
	 * ---------------------------------------------------------------------- */

	/**
	 * A per-post SEO field for the current singular view (empty elsewhere).
	 *
	 * @param string $key Field key.
	 * @return string
	 */
	private function field( $key ) {
		if ( is_singular() ) {
			return Odysseo_SEO_Metabox::get_value( get_queried_object_id(), $key );
		}
		return '';
	}

	/**
	 * SEO title: field -> front-page (name + tagline) -> singular (title + name)
	 * -> WP default.
	 *
	 * @return string
	 */
	public function get_title() {
		$f = $this->field( 'title' );
		if ( '' !== $f ) {
			return $f;
		}
		if ( is_front_page() ) {
			$name = get_bloginfo( 'name' );
			$tag  = get_bloginfo( 'description' );
			return $tag ? $name . ' — ' . $tag : $name;
		}
		if ( is_singular() ) {
			return wp_strip_all_tags( get_the_title( get_queried_object_id() ) ) . ' — ' . get_bloginfo( 'name' );
		}
		return wp_get_document_title();
	}

	/**
	 * Only override the <title> tag when a manual SEO title is set; otherwise let
	 * WordPress's title-tag default stand.
	 *
	 * @param string $title Default title.
	 * @return string
	 */
	public function filter_title( $title ) {
		$f = $this->field( 'title' );
		return '' !== $f ? $f : $title;
	}

	/**
	 * Description: field -> excerpt -> trimmed clean content -> term desc -> tagline.
	 *
	 * @return string
	 */
	public function get_description() {
		$f = $this->field( 'desc' );
		if ( '' !== $f ) {
			return $f;
		}
		if ( is_singular() ) {
			$post = get_queried_object();
			if ( $post instanceof WP_Post ) {
				if ( '' !== trim( (string) $post->post_excerpt ) ) {
					return wp_strip_all_tags( $post->post_excerpt );
				}
				if ( '' !== trim( (string) $post->post_content ) ) {
					return wp_trim_words( wp_strip_all_tags( strip_shortcodes( $post->post_content ) ), 30, '…' );
				}
			}
		}
		if ( is_category() || is_tag() || is_tax() ) {
			$d = term_description();
			if ( $d ) {
				return wp_strip_all_tags( $d );
			}
		}
		// Final fallbacks so the description is never empty: site tagline -> site name.
		$tagline = get_bloginfo( 'description' );
		return '' !== trim( (string) $tagline ) ? $tagline : get_bloginfo( 'name' );
	}

	/**
	 * OG title: field -> SEO title.
	 *
	 * @return string
	 */
	public function get_og_title() {
		$f = $this->field( 'og_title' );
		return '' !== $f ? $f : $this->get_title();
	}

	/**
	 * OG description: field -> description.
	 *
	 * @return string
	 */
	public function get_og_description() {
		$f = $this->field( 'og_desc' );
		return '' !== $f ? $f : $this->get_description();
	}

	/**
	 * OG image: featured image -> theme default.
	 *
	 * @return string
	 */
	public function get_image() {
		if ( is_singular() && has_post_thumbnail( get_queried_object_id() ) ) {
			$url = get_the_post_thumbnail_url( get_queried_object_id(), 'full' );
			if ( $url ) {
				return $url;
			}
		}
		return get_template_directory_uri() . '/assets/images/logo.png';
	}

	/* ---------------------------------------------------------------------- *
	 *  Output.
	 * ---------------------------------------------------------------------- */

	/**
	 * Google Search Console verification (independent of the rest).
	 */
	public function output_gsc() {
		$s = odysseo_seo_get_settings();
		if ( ! empty( $s['gsc_verification'] ) ) {
			printf( '<meta name="google-site-verification" content="%s">' . "\n", esc_attr( $s['gsc_verification'] ) );
		}
	}

	/**
	 * Print description, robots, canonical, OG and Twitter tags.
	 */
	public function output() {
		$desc     = $this->get_description();
		$og_title = $this->get_og_title();
		$og_desc  = $this->get_og_description();
		$url      = is_singular() ? get_permalink() : home_url( add_query_arg( array() ) );
		$site     = get_bloginfo( 'name' );
		$image    = $this->get_image();
		$type     = is_singular( 'post' ) ? 'article' : 'website';
		$robots   = ( is_singular() || is_front_page() || is_home() || is_archive() ) ? 'index, follow, max-image-preview:large' : 'noindex, follow';

		echo "\n<!-- Odysseo SEO -->\n";

		if ( '' !== $desc ) {
			printf( '<meta name="description" content="%s">' . "\n", esc_attr( $desc ) );
		}
		printf( '<meta name="robots" content="%s">' . "\n", esc_attr( $robots ) );
		printf( '<link rel="canonical" href="%s">' . "\n", esc_url( $url ) );

		printf( '<meta property="og:locale" content="%s">' . "\n", esc_attr( get_locale() ) );
		printf( '<meta property="og:type" content="%s">' . "\n", esc_attr( $type ) );
		printf( '<meta property="og:title" content="%s">' . "\n", esc_attr( $og_title ) );
		if ( '' !== $og_desc ) {
			printf( '<meta property="og:description" content="%s">' . "\n", esc_attr( $og_desc ) );
		}
		printf( '<meta property="og:url" content="%s">' . "\n", esc_url( $url ) );
		printf( '<meta property="og:site_name" content="%s">' . "\n", esc_attr( $site ) );
		if ( '' !== $image ) {
			printf( '<meta property="og:image" content="%s">' . "\n", esc_url( $image ) );
			echo '<meta property="og:image:width" content="1200">' . "\n";
			echo '<meta property="og:image:height" content="630">' . "\n";
		}
		if ( is_singular( 'post' ) ) {
			printf( '<meta property="article:published_time" content="%s">' . "\n", esc_attr( get_the_date( 'c' ) ) );
			printf( '<meta property="article:modified_time" content="%s">' . "\n", esc_attr( get_the_modified_date( 'c' ) ) );
		}

		echo '<meta name="twitter:card" content="summary_large_image">' . "\n";
		printf( '<meta name="twitter:title" content="%s">' . "\n", esc_attr( $og_title ) );
		if ( '' !== $og_desc ) {
			printf( '<meta name="twitter:description" content="%s">' . "\n", esc_attr( $og_desc ) );
		}
		if ( '' !== $image ) {
			printf( '<meta name="twitter:image" content="%s">' . "\n", esc_url( $image ) );
		}

		echo "<!-- /Odysseo SEO -->\n";
	}
}
