<?php
namespace AIOSEO\Plugin\Common\Llms;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Handles the LLMS.txt generation.
 *
 * @since 4.8.4
 */
class Llms {
	/**
	 * Site title
	 *
	 * since 4.8.4
	 *
	 * @var string
	 */
	private $title;

	/**
	 * Site description
	 *
	 * since 4.8.4
	 *
	 * @var string
	 */
	private $description;

	/**
	 * Site link
	 *
	 * since 4.8.4
	 *
	 * @var string
	 */
	private $link;

	/**
	 * Plugin version
	 *
	 * since 4.8.4
	 *
	 * @var string
	 */
	private $version;

	public function __construct() {
		if ( is_admin() || ! aioseo()->options->advanced->llmsTxt ) {
			return;
		}

		add_action( 'parse_request', [ $this, 'checkRequest' ] );
	}

	/**
	 * Checks if the request is for the LLMS.txt file.
	 *
	 * @since 4.8.4
	 *
	 * @param \WP   $wp The WordPress request object.
	 * @return void
	 */
	public function checkRequest( $wp ) {
		$slug = $wp->request ?? aioseo()->helpers->cleanSlug( $wp->request );
		if ( ! $slug && isset( $_SERVER['REQUEST_URI'] ) ) {
			// We must fallback to the REQUEST URI in case the site uses plain permalinks.
			$slug = aioseo()->helpers->cleanSlug( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
		}

		if ( 'llms.txt' !== $slug ) {
			return;
		}

		$this->setSiteInfo();
		$this->generate();
	}

	/**
	 * Sets the site info.
	 *
	 * @since 4.8.4
	 *
	 * @return void
	 */
	private function setSiteInfo() {
		$isMultisite = is_multisite();
		$this->title = $isMultisite
			? get_blog_option( get_current_blog_id(), 'blogname' )
			: get_bloginfo( 'name' );
		$this->title = $this->title ?? aioseo()->meta->title->getHomePageTitle();

		$this->description = $isMultisite
			? get_blog_option( get_current_blog_id(), 'blogdescription' )
			: get_bloginfo( 'description' );
		$this->description = $this->description ?? aioseo()->meta->description->getHomePageDescription();

		$this->link = $isMultisite
			? get_blog_option( get_current_blog_id(), 'siteurl' )
			: home_url();

		$this->version = aioseo()->helpers->getAioseoVersion();
	}

	/**
	 * Generates the LLMS.txt file.
	 *
	 * @since 4.8.4
	 *
	 * @return void
	 */
	private function generate() {
		$this->headers();

		$content  = $this->getHeader();
		$content .= $this->getSiteDescription();
		$content .= $this->getSitemapUrl();
		$content .= $this->getRecentContent();

		echo $content; #phpcs:ignore
		exit;
	}

	/**
	 * Gets the header section of the llms.txt file.
	 *
	 * @since 4.8.4
	 *
	 * @return string
	 */
	private function getHeader() {
		$introText = sprintf(
			/* translators: 1 - The plugin name ("All in One SEO"), 2 - The version number */
			esc_html__( 'Generated by %1$s v%2$s, this is an llms.txt file, used by LLMs to index the site.', 'all-in-one-seo-pack' ),
			esc_html( AIOSEO_PLUGIN_NAME ),
			esc_html( aioseo()->version )
		);

		if ( $this->title ) {
			$introText .= esc_html( "\n\n# {$this->title}\n\n" );
		}

		return $introText;
	}

	/**
	 * Gets the site description section of the llms.txt file.
	 *
	 * @since 4.8.4
	 *
	 * @return string
	 */
	private function getSiteDescription() {
		if ( $this->description ) {
			return "{$this->description}\n\n";
		}

		return '';
	}

	/**
	 * Gets the sitemap link section of the llms.txt file.
	 *
	 * @since 4.8.4
	 *
	 * @return string
	 */
	private function getSitemapUrl() {
		if ( ! aioseo()->options->sitemap->general->enable ) {
			return '';
		}

		$sitemapUrl = aioseo()->sitemap->helpers->getUrl( 'general' );

		return "## Sitemaps\n\n- [XML Sitemap]({$sitemapUrl}): Contains all public/indexable URLs for this website.\n\n";
	}

	/**
	 * Gets the recent content section of the llms.txt file.
	 *
	 * @since 4.8.4
	 *
	 * @return string
	 */
	private function getRecentContent() {
		$content = '';

		$postTypes                       = array_filter( aioseo()->helpers->getPublicPostTypes( true ), function( $type ) {
			return 'attachment' !== $type;
		} );
		$originalSitemapType             = aioseo()->sitemap->type;
		$originalLinksPerIndex           = aioseo()->sitemap->linksPerIndex;
		$originalIndexes                 = aioseo()->sitemap->indexes;

		aioseo()->sitemap->type          = 'llms';
		aioseo()->sitemap->linksPerIndex = 20;
		aioseo()->sitemap->indexes       = true;

		foreach ( $postTypes as $postType ) {
			$postTypeObject = get_post_type_object( $postType );
			if ( ! $postTypeObject ) {
				continue;
			}

			$recentPosts = aioseo()->sitemap->query->posts( $postType );

			if ( ! empty( $recentPosts ) ) {
				$content .= '## ' . $postTypeObject->labels->name . "\n\n";
				foreach ( $recentPosts as $post ) {
					$content .= '- [' . aioseo()->helpers->decodeHtmlEntities( $post->post_title ) . '](' . aioseo()->helpers->decodeUrl( get_permalink( $post->ID ) ) . ")\n";
				}
				$content .= "\n";
			}
		}

		$taxonomies = aioseo()->helpers->getPublicTaxonomies( true );

		// Get recent terms for each taxonomy using sitemap query
		foreach ( $taxonomies as $taxonomy ) {
			$taxonomyObject = get_taxonomy( $taxonomy );
			if ( ! $taxonomyObject ) {
				continue;
			}

			$terms = aioseo()->sitemap->query->terms( $taxonomy );

			if ( ! empty( $terms ) ) {
				$content .= '## ' . $taxonomyObject->labels->name . "\n\n";
				foreach ( $terms as $term ) {
					if ( is_object( $term ) && ! empty( $term->term_id ) && ! empty( $term->name ) ) {
						$content .= '- [' . aioseo()->helpers->decodeHtmlEntities( $term->name ) . '](' . aioseo()->helpers->decodeUrl( get_term_link( $term->term_id, $taxonomy ) ) . ")\n";
					}
				}
				$content .= "\n";
			}
		}

		// Restore original sitemap settings
		aioseo()->sitemap->type          = $originalSitemapType;
		aioseo()->sitemap->linksPerIndex = $originalLinksPerIndex;
		aioseo()->sitemap->indexes       = $originalIndexes;

		return $content;
	}

	/**
	 * Sets the HTTP headers for the LLMS.txt.
	 *
	 * @since 4.8.4
	 *
	 * @return void
	 */
	public function headers() {
		$charset = aioseo()->helpers->getCharset();
		header( "Content-Type: text/plain; charset=$charset", true );
		header( 'X-Robots-Tag: noindex, follow', true );
	}

	/**
	 * Gets the LLMs.txt URL if accessible.
	 *
	 * @since 4.8.4
	 *
	 * @return array The LLMs.txt URL if accessible, null otherwise.
	 */
	public function getUrl() {
		$url          = home_url( '/llms.txt' );
		$isAccessible = false;

		if ( aioseo()->options->advanced->llmsTxt ) {
			$response     = wp_remote_head( $url );
			$isAccessible = ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response );
		}

		return [
			'url'          => $url,
			'isAccessible' => $isAccessible
		];
	}
}