<?php
/**
 * AI Visibility - LLMs.txt Serving
 *
 * @package SEOvaultSEO
 */

namespace SEOvaultSEO\AiVisibility;

use SEOvaultSEO\Utils\Logger;

/**
 * Handles llms.txt serving
 */
class Llms {

	/**
	 * Initialize llms.txt serving
	 */
	public static function init() {
		if ( ! \SEOvaultSEO\Compatibility\Detector::should_output_seo() ) {
			return;
		}

		if ( ! \SEOvaultSEO\Core\Options::is_llms_enabled() ) {
			return;
		}

		add_action( 'init', array( __CLASS__, 'add_rewrite_rules' ) );
		add_action( 'template_redirect', array( __CLASS__, 'serve_llms_txt' ) );
		add_filter( 'query_vars', array( __CLASS__, 'add_query_vars' ) );
	}

	/**
	 * Add rewrite rules for llms.txt
	 */
	public static function add_rewrite_rules() {
		add_rewrite_rule( '^llms\.txt$', 'index.php?seovault_llms=1', 'top' );
		add_rewrite_rule( '^llms-full\.txt$', 'index.php?seovault_llms_full=1', 'top' );
	}

	/**
	 * Add query vars
	 *
	 * @param array $vars Query vars
	 * @return array
	 */
	public static function add_query_vars( $vars ) {
		$vars[] = 'seovault_llms';
		$vars[] = 'seovault_llms_full';
		return $vars;
	}

	/**
	 * Serve llms.txt
	 */
	public static function serve_llms_txt() {
		if ( get_query_var( 'seovault_llms' ) ) {
			$result = self::get_llms_response( false );
			self::send_llms_response( $result );
		}

		if ( get_query_var( 'seovault_llms_full' ) ) {
			$result = self::get_llms_response( true );
			self::send_llms_response( $result );
		}
	}

	/**
	 * Build llms.txt response data without exiting.
	 *
	 * @param bool $full Whether to output full version
	 * @return array {
	 *     @type int    $status HTTP status code
	 *     @type string $body   Response body
	 *     @type array  $headers HTTP headers
	 * }
	 */
	public static function get_llms_response( $full = false ) {
		if ( ! \SEOvaultSEO\Core\Options::is_llms_enabled() ) {
			return array(
				'status'  => 404,
				'body'    => 'llms.txt is not enabled',
				'headers' => array(),
			);
		}

		$content = $full
			? \SEOvaultSEO\Core\Options::get_llms_full_txt_content()
			: \SEOvaultSEO\Core\Options::get_llms_txt_content();

		if ( empty( $content ) ) {
			return array(
				'status'  => 404,
				'body'    => 'llms.txt content is empty',
				'headers' => array(),
			);
		}

		return array(
			'status'  => 200,
			// Body is served as text/plain and already sanitized on publish via
			// Sanitizer::sanitize_llms_content(); HTML-escaping here would corrupt
			// plain text (e.g. "&" in URL query strings becoming "&amp;").
			'body'    => $content,
			'headers' => array(
				'Content-Type' => 'text/plain; charset=utf-8',
				'X-Served-By'  => \SEOvaultSEO\Core\Options::get_llms_served_by(),
			),
		);
	}

	/**
	 * Send llms.txt response and exit.
	 *
	 * @param array $result Response data from get_llms_response
	 */
	private static function send_llms_response( $result ) {
		status_header( $result['status'] );
		foreach ( $result['headers'] as $name => $value ) {
			header( $name . ': ' . $value );
		}
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Body is plain text (Content-Type: text/plain), already sanitized on publish; HTML-escaping would corrupt it.
		echo $result['body'];
		exit;
	}

	/**
	 * Get llms status for API
	 *
	 * @return array
	 */
	public static function get_status() {
		return array(
			'enabled'     => \SEOvaultSEO\Core\Options::is_llms_enabled(),
			'served_by'   => \SEOvaultSEO\Core\Options::get_llms_served_by(),
			'has_content' => ! empty( \SEOvaultSEO\Core\Options::get_llms_txt_content() ),
			'has_full'    => ! empty( \SEOvaultSEO\Core\Options::get_llms_full_txt_content() ),
		);
	}

	/**
	 * Preview llms content
	 *
	 * @param string $content Content to preview
	 * @return array
	 */
	public static function preview( $content ) {
		$sanitized = \SEOvaultSEO\Utils\Sanitizer::sanitize_llms_content( $content );
		return array(
			'success' => true,
			'preview' => $sanitized,
			'length'  => strlen( $sanitized ),
		);
	}

	/**
	 * Publish llms content
	 *
	 * @param string $content Content to publish
	 * @param bool   $full Whether this is full version
	 * @return array
	 */
	public static function publish( $content, $full = false ) {
		Logger::log(
			'Llms::publish: entered',
			array(
				'full'           => (bool) $full,
				'content_length' => strlen( (string) $content ),
			)
		);

		$sanitized = \SEOvaultSEO\Utils\Sanitizer::sanitize_llms_content( $content );

		if ( $full ) {
			\SEOvaultSEO\Core\Options::set_llms_full_txt_content( $sanitized );
		} else {
			\SEOvaultSEO\Core\Options::set_llms_txt_content( $sanitized );
		}

		\SEOvaultSEO\Core\Options::set_llms_served_by( 'seovault_ai' );
		\SEOvaultSEO\Core\Options::set_llms_enabled( 'yes' );

		Logger::log(
			'Llms::publish: success',
			array(
				'full'          => (bool) $full,
				'stored_length' => strlen( $sanitized ),
			)
		);

		return array(
			'success' => true,
			'message' => $full ? 'llms-full.txt published' : 'llms.txt published',
		);
	}
}
