<?php
/**
 * MYAIO SEO Continuity
 *
 * Two modes:
 * 1) Main plugin runtime: MYAIO_SAC_Loader calls MYAIO_SEO_Continuity::init_runtime()
 * 2) MU-style continuity: when main plugin is NOT active, this file can still output last-deployed tags
 *
 * Safe behavior:
 * - Never writes/deletes SEO meta values.
 * - If another SEO plugin is active, it exits (to avoid duplicates).
 */

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

/* -------------------------------------------------------------------------
 * Helpers (functions) - safe to declare globally
 * ------------------------------------------------------------------------- */
if ( ! function_exists('myaio__clean_text') ) {
	function myaio__clean_text( $value ) {
		$value = trim( wp_strip_all_tags( (string) $value ) );
		if ( $value === '' ) return '';
		$value = sanitize_text_field( $value );
		$value = preg_replace( '/[[:cntrl:]]/u', '', $value );
		return trim( (string) $value );
	}
}

if ( ! function_exists('myaio__normalize_robots_meta') ) {
	function myaio__normalize_robots_meta( $value ) {
		$allowed = [
			'index', 'noindex', 'follow', 'nofollow', 'noarchive', 'nosnippet', 'noimageindex',
		];

		$push_tokens = static function( &$tokens, $raw ) use ( $allowed ) {
			if ( ! is_scalar( $raw ) ) {
				return;
			}

			$raw = strtolower( trim( wp_strip_all_tags( (string) $raw ) ) );
			if ( $raw === '' ) {
				return;
			}

			foreach ( preg_split( '/\s*,\s*|\s+/', $raw ) as $part ) {
				$part = trim( (string) $part );
				if ( $part === '' ) {
					continue;
				}

				if ( in_array( $part, $allowed, true ) || preg_match( '/^(?:max-snippet:-?\d+|max-image-preview:(?:none|standard|large)|max-video-preview:-?\d+|unavailable_after:.+)$/', $part ) ) {
					$tokens[] = $part;
				}
			}
		};

		$is_truthy = static function( $raw ) {
			if ( is_bool( $raw ) ) {
				return $raw;
			}
			if ( is_int( $raw ) || is_float( $raw ) ) {
				return (int) $raw === 1;
			}
			if ( is_string( $raw ) ) {
				$raw = strtolower( trim( $raw ) );
				return in_array( $raw, [ '1', 'true', 'yes', 'on', 'default', 'inherit', 'index', 'follow', 'enabled' ], true );
			}
			return false;
		};

		$walk = null;
		$walk = static function( $item, &$tokens ) use ( &$walk, $push_tokens, $is_truthy, $allowed ) {
			$item = maybe_unserialize( $item );
			if ( is_string( $item ) ) {
				$json = json_decode( $item, true );
				if ( json_last_error() === JSON_ERROR_NONE && is_array( $json ) ) {
					$item = $json;
				}
			}

			if ( is_array( $item ) ) {
				foreach ( $item as $k => $v ) {
					$key = strtolower( trim( (string) $k ) );

					if ( ! is_int( $k ) && in_array( $key, $allowed, true ) ) {
						if ( is_array( $v ) ) {
							$before = count( $tokens );
							$walk( $v, $tokens );
							if ( count( $tokens ) === $before && isset( $v['value'] ) && $is_truthy( $v['value'] ) ) {
								$tokens[] = $key;
							}
						} elseif ( $is_truthy( $v ) || strtolower( trim( (string) $v ) ) === $key ) {
							$tokens[] = $key;
						}
						continue;
					}

					$walk( $v, $tokens );
				}
				return;
			}

			$push_tokens( $tokens, $item );
		};

		$tokens = [];
		$walk( $value, $tokens );
		$tokens = array_values( array_unique( array_filter( array_map( 'trim', $tokens ) ) ) );

		if ( in_array( 'noindex', $tokens, true ) ) {
			$tokens = array_values( array_diff( $tokens, [ 'index' ] ) );
		} elseif ( in_array( 'index', $tokens, true ) && ! in_array( 'follow', $tokens, true ) && ! in_array( 'nofollow', $tokens, true ) ) {
			$tokens[] = 'follow';
		}

		if ( in_array( 'nofollow', $tokens, true ) ) {
			$tokens = array_values( array_diff( $tokens, [ 'follow' ] ) );
		} elseif ( in_array( 'follow', $tokens, true ) === false && ( in_array( 'index', $tokens, true ) || in_array( 'noindex', $tokens, true ) ) ) {
			$tokens[] = 'follow';
		}

		if ( ! in_array( 'index', $tokens, true ) && ! in_array( 'noindex', $tokens, true ) && ( in_array( 'follow', $tokens, true ) || in_array( 'nofollow', $tokens, true ) ) ) {
			array_unshift( $tokens, 'index' );
		}

		$preferred_order = [ 'noindex', 'index', 'nofollow', 'follow', 'noarchive', 'nosnippet', 'noimageindex' ];
		usort( $tokens, static function( $a, $b ) use ( $preferred_order ) {
			$pa = array_search( $a, $preferred_order, true );
			$pb = array_search( $b, $preferred_order, true );
			$pa = ( $pa === false ) ? 999 : $pa;
			$pb = ( $pb === false ) ? 999 : $pb;
			if ( $pa === $pb ) {
				return strcmp( $a, $b );
			}
			return $pa <=> $pb;
		} );

		return implode( ',', $tokens );
	}
}

if ( ! function_exists('myaio__first_nonempty') ) {
	function myaio__first_nonempty( ...$values ) {
		foreach ( $values as $v ) {
			$v = myaio__clean_text( $v );
			if ( $v !== '' ) return $v;
		}
		return '';
	}
}

if ( ! function_exists('myaio__is_main_plugin_active') ) {
	function myaio__is_main_plugin_active(): bool {
		$needle  = 'myaio-your-ai-powered-co-founder.php';
		$plugins = (array) get_option( 'active_plugins', [] );

		foreach ( $plugins as $p ) {
			if ( is_string($p) && substr( $p, -strlen($needle) ) === $needle ) return true;
		}

		if ( function_exists('get_site_option') ) {
			$sitewide = (array) get_site_option( 'active_sitewide_plugins', [] );
			foreach ( array_keys($sitewide) as $p ) {
				if ( is_string($p) && substr( $p, -strlen($needle) ) === $needle ) return true;
			}
		}

		return false;
	}
}

/* -------------------------------------------------------------------------
 * Class that your sac-loader.php expects
 * ------------------------------------------------------------------------- */
if ( ! class_exists('MYAIO_SEO_Continuity') ) {

	class MYAIO_SEO_Continuity {

		private static $booted = false;

		/**
		 * Boot runtime continuity (safe to call multiple times).
		 */
		public static function init_runtime() {
			if ( self::$booted ) return;
			self::$booted = true;

			// Title continuity: prefer stored MYAIO title.
			add_filter( 'pre_get_document_title', [ __CLASS__, 'filter_document_title' ], 9999 );

			// Start buffering early so we can de-duplicate theme tags and control placement.
			add_action( 'template_redirect', [ __CLASS__, 'start_buffer' ], 0 );

			// Output tags too (buffer will de-duplicate and re-place them after </title>).
			// Priority after WP title tag (usually priority 1).
			add_action( 'wp_head', [ __CLASS__, 'output_head_tags' ], 20 );
		}

		/**
		 * Optional: called by your installer deploy step.
		 * Keep it safe/no-op unless you actually have tables to ensure.
		 */
		public static function ensure_tables() {
			return true;
		}

		public static function filter_document_title( $title ) {
			if ( ! is_singular() ) return $title;

			$post_id = (int) get_queried_object_id();
			if ( ! $post_id ) return $title;

			$seo_title = myaio__clean_text( get_post_meta( $post_id, '_myaio_seo_title', true ) );
			return ( $seo_title !== '' ) ? $seo_title : $title;
		}

		public static function start_buffer() {
			if ( ! is_singular() ) return;
			ob_start( [ __CLASS__, 'rewrite_head_meta' ] );
		}

		public static function output_head_tags() {
			if ( ! is_singular() ) return;

			$post_id = (int) get_queried_object_id();
			if ( ! $post_id ) return;

			$m = self::get_last_deployed_meta( $post_id );

			if ( ! empty($m['description']) ) echo "\n<meta name=\"description\" content=\"" . esc_attr( $m['description'] ) . "\" />\n";
			if ( ! empty($m['keywords']) ) echo "<meta name=\"keywords\" content=\"" . esc_attr( $m['keywords'] ) . "\" />\n";
			if ( ! empty($m['robots']) ) echo "<meta name=\"robots\" content=\"" . esc_attr( $m['robots'] ) . "\" />\n";
			if ( ! empty($m['canonical']) ) echo "<link rel=\"canonical\" href=\"" . esc_url( $m['canonical'] ) . "\" />\n";

			if ( ! empty($m['og_locale']) ) echo "<meta property=\"og:locale\" content=\"" . esc_attr( $m['og_locale'] ) . "\" />\n";
			if ( ! empty($m['og_type']) ) echo "<meta property=\"og:type\" content=\"" . esc_attr( $m['og_type'] ) . "\" />\n";
			if ( ! empty($m['og_title']) ) echo "<meta property=\"og:title\" content=\"" . esc_attr( $m['og_title'] ) . "\" />\n";
			if ( ! empty($m['og_description']) ) echo "<meta property=\"og:description\" content=\"" . esc_attr( $m['og_description'] ) . "\" />\n";
			if ( ! empty($m['og_image']) ) echo "<meta property=\"og:image\" content=\"" . esc_url( $m['og_image'] ) . "\" />\n";
			if ( ! empty($m['og_url']) ) echo "<meta property=\"og:url\" content=\"" . esc_url( $m['og_url'] ) . "\" />\n";
			if ( ! empty($m['og_site_name']) ) echo "<meta property=\"og:site_name\" content=\"" . esc_attr( $m['og_site_name'] ) . "\" />\n";
			if ( ! empty($m['og_updated_time']) ) echo "<meta property=\"og:updated_time\" content=\"" . esc_attr( $m['og_updated_time'] ) . "\" />\n";
			if ( ! empty($m['article_published']) ) echo "<meta property=\"article:published_time\" content=\"" . esc_attr( $m['article_published'] ) . "\" />\n";
			if ( ! empty($m['article_modified']) ) echo "<meta property=\"article:modified_time\" content=\"" . esc_attr( $m['article_modified'] ) . "\" />\n";

			if ( ! empty($m['twitter_card']) ) echo "<meta name=\"twitter:card\" content=\"" . esc_attr( $m['twitter_card'] ) . "\" />\n";
			if ( ! empty($m['twitter_title']) ) echo "<meta name=\"twitter:title\" content=\"" . esc_attr( $m['twitter_title'] ) . "\" />\n";
			if ( ! empty($m['twitter_description']) ) echo "<meta name=\"twitter:description\" content=\"" . esc_attr( $m['twitter_description'] ) . "\" />\n";
			if ( ! empty($m['twitter_image']) ) echo "<meta name=\"twitter:image\" content=\"" . esc_url( $m['twitter_image'] ) . "\" />\n";
			if ( ! empty($m['twitter_site']) ) echo "<meta name=\"twitter:site\" content=\"" . esc_attr( $m['twitter_site'] ) . "\" />\n";
		}

		/**
		 * Buffer callback: remove duplicates and re-insert MYAIO last-deployed values.
		 * We insert AFTER </title> if present (RankMath-like). Otherwise before </head>.
		 */
		public static function rewrite_head_meta( $html ) {
			if ( ! is_singular() ) return $html;

			$post_id = (int) get_queried_object_id();
			if ( ! $post_id ) return $html;

			$m = self::get_last_deployed_meta( $post_id );

			$desc      = $m['description'] ?? '';
			$keywords  = $m['keywords'] ?? '';
			$robots    = $m['robots'] ?? '';
			$canonical = $m['canonical'] ?? '';

			if ( $desc !== '' ) {
				$html = preg_replace( '~<meta\b[^>]*\bname\s*=\s*(["\'])description\1[^>]*>\s*~i', '', $html );
			}
			if ( $keywords !== '' ) {
				$html = preg_replace( '~<meta\b[^>]*\bname\s*=\s*(["\'])keywords\1[^>]*>\s*~i', '', $html );
			}
			if ( $robots !== '' ) {
				$html = preg_replace( '~<meta\b[^>]*\bname\s*=\s*(["\'])robots\1[^>]*>\s*~i', '', $html );
			}
			if ( $canonical !== '' ) {
				$html = preg_replace( '~<link\b[^>]*\brel\s*=\s*(["\'])canonical\1[^>]*>\s*~i', '', $html );
			}

			$og_title = $m['og_title'] ?? '';
			$og_desc  = $m['og_description'] ?? '';
			$og_image = $m['og_image'] ?? '';
			$og_url   = $m['og_url'] ?? '';
			$og_locale = $m['og_locale'] ?? '';
			$og_type   = $m['og_type'] ?? '';
			$og_site   = $m['og_site_name'] ?? '';
			$og_upd    = $m['og_updated_time'] ?? '';
			$art_pub   = $m['article_published'] ?? '';
			$art_mod   = $m['article_modified'] ?? '';

			$tw_card  = $m['twitter_card'] ?? '';
			$tw_title = $m['twitter_title'] ?? '';
			$tw_desc  = $m['twitter_description'] ?? '';
			$tw_image = $m['twitter_image'] ?? '';
			$tw_site  = $m['twitter_site'] ?? '';

			if ( $og_title !== '' || $og_desc !== '' || $og_image !== '' || $og_url !== '' || $og_locale !== '' || $og_type !== '' || $og_site !== '' || $og_upd !== '' ) {
				$html = preg_replace( '~<meta\b[^>]*\bproperty\s*=\s*(["\'])og:(locale|type|title|description|image|url|site_name|updated_time)\1[^>]*>\s*~i', '', $html );
			}
			if ( $art_pub !== '' || $art_mod !== '' ) {
				$html = preg_replace( '~<meta\b[^>]*\bproperty\s*=\s*(["\'])article:(published_time|modified_time)\1[^>]*>\s*~i', '', $html );
			}
			if ( $tw_card !== '' || $tw_title !== '' || $tw_desc !== '' || $tw_site !== '' || $tw_image !== '' ) {
				$html = preg_replace( '~<meta\b[^>]*\bname\s*=\s*(["\'])twitter:(card|title|description|site|image)\1[^>]*>\s*~i', '', $html );
			}

			$inserts = '';

			if ( $desc !== '' )      $inserts .= "\n<meta name=\"description\" content=\"" . esc_attr($desc) . "\" />\n";
			if ( $keywords !== '' )  $inserts .= "<meta name=\"keywords\" content=\"" . esc_attr($keywords) . "\" />\n";
			if ( $robots !== '' )    $inserts .= "<meta name=\"robots\" content=\"" . esc_attr($robots) . "\" />\n";
			if ( $canonical !== '' ) $inserts .= "<link rel=\"canonical\" href=\"" . esc_url($canonical) . "\" />\n";

			if ( $og_locale !== '' ) $inserts .= "<meta property=\"og:locale\" content=\"" . esc_attr($og_locale) . "\" />\n";
			if ( $og_type !== '' )   $inserts .= "<meta property=\"og:type\" content=\"" . esc_attr($og_type) . "\" />\n";
			if ( $og_title !== '' )  $inserts .= "<meta property=\"og:title\" content=\"" . esc_attr($og_title) . "\" />\n";
			if ( $og_desc !== '' )   $inserts .= "<meta property=\"og:description\" content=\"" . esc_attr($og_desc) . "\" />\n";
			if ( $og_image !== '' )  $inserts .= "<meta property=\"og:image\" content=\"" . esc_url($og_image) . "\" />\n";
			if ( $og_url !== '' )    $inserts .= "<meta property=\"og:url\" content=\"" . esc_url($og_url) . "\" />\n";
			if ( $og_site !== '' )   $inserts .= "<meta property=\"og:site_name\" content=\"" . esc_attr($og_site) . "\" />\n";
			if ( $og_upd !== '' )    $inserts .= "<meta property=\"og:updated_time\" content=\"" . esc_attr($og_upd) . "\" />\n";
			if ( $art_pub !== '' )   $inserts .= "<meta property=\"article:published_time\" content=\"" . esc_attr($art_pub) . "\" />\n";
			if ( $art_mod !== '' )   $inserts .= "<meta property=\"article:modified_time\" content=\"" . esc_attr($art_mod) . "\" />\n";

			if ( $tw_card !== '' )   $inserts .= "<meta name=\"twitter:card\" content=\"" . esc_attr($tw_card) . "\" />\n";
			if ( $tw_title !== '' )  $inserts .= "<meta name=\"twitter:title\" content=\"" . esc_attr($tw_title) . "\" />\n";
			if ( $tw_desc !== '' )   $inserts .= "<meta name=\"twitter:description\" content=\"" . esc_attr($tw_desc) . "\" />\n";
			if ( $tw_image !== '' )  $inserts .= "<meta name=\"twitter:image\" content=\"" . esc_url($tw_image) . "\" />\n";
			if ( $tw_site !== '' )   $inserts .= "<meta name=\"twitter:site\" content=\"" . esc_attr($tw_site) . "\" />\n";

			if ( $inserts === '' ) return $html;

			// ✅ RankMath-like placement: right after </title> if possible
			if ( stripos( $html, '</title>' ) !== false ) {
				$html = preg_replace( '~</title>~i', "</title>\n" . $inserts, $html, 1 );
				return $html;
			}

			// Fallback: before </head>
			if ( stripos( $html, '</head>' ) !== false ) {
				$html = preg_replace( '~</head>~i', $inserts . '</head>', $html, 1 );
			} else {
				$html .= $inserts;
			}

			return $html;
		}

		/**
		 * Returns "last deployed" values (stored by MYAIO in post meta).
		 */
		private static function get_last_deployed_meta( int $post_id ): array {
			$seo_title = myaio__clean_text( get_post_meta( $post_id, '_myaio_seo_title', true ) );

			$seo_desc = myaio__first_nonempty(
				get_post_meta( $post_id, '_myaio_seo_description', true ),
				get_post_meta( $post_id, '_myaio_meta_description', true ),
				get_post_field( 'post_excerpt', $post_id )
			);

			$keywords = myaio__first_nonempty(
				get_post_meta( $post_id, '_myaio_seo_keywords', true ),
				get_post_meta( $post_id, '_myaio_meta_keywords', true )
			);

			$robots = myaio__normalize_robots_meta( get_post_meta( $post_id, '_myaio_seo_robots', true ) );
			if ( $robots === '' ) $robots = myaio__normalize_robots_meta( get_post_meta( $post_id, '_myaio_meta_robots', true ) );
			if ( $robots === '' ) $robots = myaio__normalize_robots_meta( get_post_meta( $post_id, '_myaio_robots', true ) );

			$canonical = myaio__first_nonempty(
				get_post_meta( $post_id, '_myaio_seo_canonical', true ),
				get_post_meta( $post_id, '_myaio_canonical_url', true )
			);

			$og_title = myaio__clean_text( get_post_meta( $post_id, '_myaio_og_title', true ) );
			$og_desc  = myaio__clean_text( get_post_meta( $post_id, '_myaio_og_description', true ) );
			$og_image = myaio__first_nonempty(
				get_post_meta( $post_id, '_myaio_og_image', true ),
				get_post_meta( $post_id, '_myaio_social_image', true )
			);

			$og_url = myaio__first_nonempty(
				get_post_meta( $post_id, '_myaio_og_url', true )
			);

			$tw_card  = myaio__clean_text( get_post_meta( $post_id, '_myaio_twitter_card', true ) );
			$tw_title = myaio__clean_text( get_post_meta( $post_id, '_myaio_twitter_title', true ) );
			$tw_desc  = myaio__clean_text( get_post_meta( $post_id, '_myaio_twitter_description', true ) );
			$tw_site  = myaio__clean_text( get_post_meta( $post_id, '_myaio_twitter_site', true ) );
			$tw_image = myaio__first_nonempty(
				get_post_meta( $post_id, '_myaio_twitter_image', true ),
				$og_image
			);

			// Derived/structural OG fields (RankMath-like defaults)
			$og_locale   = myaio__clean_text( str_replace('_', '-', (string) get_locale() ) );
			$og_site     = myaio__clean_text( get_bloginfo('name') );
			$is_front    = function_exists('is_front_page') && is_front_page();
			$post_type   = get_post_type( $post_id );
			$og_type     = $is_front ? 'website' : ( ($post_type === 'post' || $post_type === 'page') ? 'article' : 'website' );
			$published_g = get_post_time( 'c', true, $post_id );
			$modified_g  = get_post_modified_time( 'c', true, $post_id );
			$og_updated  = $modified_g ? $modified_g : '';

			if ( $canonical === '' ) {
				if ( function_exists('wp_get_canonical_url') ) {
					$canonical = myaio__clean_text( wp_get_canonical_url( $post_id ) );
				}
				if ( $canonical === '' ) {
					$canonical = myaio__clean_text( get_permalink( $post_id ) );
				}
			}

			// Fallback for og:url
			if ( $og_url === '' ) {
				$og_url = ( $canonical !== '' ) ? $canonical : myaio__clean_text( get_permalink( $post_id ) );
			}

			if ( $robots === '' ) $robots = 'index,follow';

			// IMPORTANT: Do NOT automatically derive social meta from SEO title/description.
			// Social tags should only be output when explicitly set (migrated or deployed).

			return [
				'seo_title'            => $seo_title,
				'description'          => $seo_desc,
				'keywords'             => $keywords,
				'robots'               => $robots,
				'canonical'            => $canonical,
				'og_locale'            => $og_locale,
				'og_type'              => $og_type,
				'og_site_name'         => $og_site,
				'og_updated_time'      => $og_updated,
				'article_published'     => $published_g ?: '',
				'article_modified'      => $modified_g ?: '',
				'og_title'             => $og_title,
				'og_description'       => $og_desc,
				'og_image'             => $og_image,
				'og_url'               => $og_url,
				'twitter_card'         => $tw_card,
				'twitter_title'        => $tw_title,
				'twitter_description'  => $tw_desc,
				'twitter_site'         => $tw_site,
				'twitter_image'        => $tw_image,
			];
		}
	}
}

/* -------------------------------------------------------------------------
 * MU-style auto boot (ONLY when main plugin is inactive + no other SEO plugin)
 * ------------------------------------------------------------------------- */
if ( ! myaio__is_main_plugin_active() ) {
	// If a dedicated SEO plugin is active, do not output head tags here to avoid duplicates.
	if ( defined('RANK_MATH_VERSION') || defined('WPSEO_VERSION') || defined('AIOSEO_VERSION') ) {
		return;
	}
	// Auto-init continuity when MYAIO main plugin is off.
	MYAIO_SEO_Continuity::init_runtime();
}