<?php

declare(strict_types=1);

namespace Signocore\Multilanguage\Features;

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

use Signocore\Multilanguage\Infrastructure\Database\TranslationRepository;
use Signocore\Multilanguage\Infrastructure\Traits\Singleton;
use Signocore\Multilanguage\Support\LocaleHelper;
use Signocore\Multilanguage\Support\UrlHelper;

/**
 * Outputs hreflang tags in the document head for SEO.
 */
final class HreflangTags
{
	use Singleton;

	protected function init(): void
	{
		add_action('wp_head', [$this, 'outputTags'], 1);
	}

	/**
	 * Output hreflang link tags.
	 */
	public function outputTags(): void
	{
		/** @var bool $enabled */
		$enabled = apply_filters('signocore_ml_hreflang_enabled', true);
		if (!$enabled) {
			return;
		}

		$tags = $this->buildTags();

		/** @var array<int, array{hreflang: string, href: string}> $tags */
		$tags = apply_filters('signocore_ml_hreflang_tags', $tags);

		if (empty($tags)) {
			return;
		}

		echo "\n<!-- Signocore Multilanguage hreflang tags -->\n";
		foreach ($tags as $tag) {
			echo '<link rel="alternate" hreflang="' . esc_attr($tag['hreflang']) . '" href="' . esc_url($tag['href']) . '" />' . "\n";
		}
		echo "<!-- /Signocore Multilanguage hreflang tags -->\n\n";
	}

	/**
	 * Build hreflang tag data for the current page.
	 *
	 * @return array<int, array{hreflang: string, href: string}>
	 */
	private function buildTags(): array
	{
		$langManager = LanguageManager::load();
		$languages = $langManager->getActiveLanguages();
		$defaultCode = $langManager->getDefaultLanguageCode();

		if (count($languages) < 2) {
			return [];
		}

		$archivePageId = UrlHelper::getPageBackedArchiveId();
		if ($archivePageId !== null) {
			return $this->buildSingularTags($languages, $defaultCode, $archivePageId);
		}

		if (is_singular()) {
			return $this->buildSingularTags($languages, $defaultCode);
		}

		if (is_category() || is_tag() || is_tax()) {
			return $this->buildTaxonomyArchiveTags($languages, $defaultCode);
		}

		return $this->buildArchiveTags($languages, $defaultCode);
	}

	/**
	 * Build hreflang tags for singular pages (posts, pages, CPTs).
	 *
	 * @param array<string, object> $languages
	 * @return array<int, array{hreflang: string, href: string}>
	 */
	private function buildSingularTags(array $languages, string $defaultCode, ?int $postId = null): array
	{
		$postId = $postId ?? get_queried_object_id();
		if ($postId <= 0) {
			return [];
		}

		$translations = TranslationRepository::getTranslationsForPost($postId, publishedOnly: true);

		if (empty($translations)) {
			return [];
		}

		$tags = [];
		$defaultHref = '';

		foreach ($languages as $lang) {
			if (!UrlHelper::isLanguageReachable($lang->code)) {
				continue;
			}

			if (!isset($translations[$lang->code])) {
				continue;
			}

			$translatedPostId = $translations[$lang->code];
			$permalink = get_permalink($translatedPostId);

			if ($permalink === false) {
				continue;
			}

			$hreflang = LocaleHelper::getHreflangCode($lang->code);
			$href = (string) $permalink;

			$tags[] = [
				'hreflang' => $hreflang,
				'href' => $href,
			];

			if ($lang->code === $defaultCode) {
				$defaultHref = $href;
			}
		}

		// Add x-default pointing to the default language version
		if ($defaultHref !== '') {
			$tags[] = [
				'hreflang' => 'x-default',
				'href' => $defaultHref,
			];
		}

		return $tags;
	}

	/**
	 * Build hreflang tags for taxonomy archive pages.
	 *
	 * Uses get_term_link() for each translated term to ensure
	 * translated base slugs and term slugs are included.
	 *
	 * @param array<string, object> $languages
	 * @return array<int, array{hreflang: string, href: string}>
	 */
	private function buildTaxonomyArchiveTags(array $languages, string $defaultCode): array
	{
		$term = get_queried_object();
		if (!$term instanceof \WP_Term) {
			return [];
		}

		$translations = TranslationRepository::getTranslationsForTerm(
			$term->term_id,
			$term->taxonomy
		);

		if (empty($translations)) {
			return [];
		}

		$tags = [];
		$defaultHref = '';

		foreach ($languages as $lang) {
			if (!UrlHelper::isLanguageReachable($lang->code)) {
				continue;
			}

			if (!isset($translations[$lang->code])) {
				continue;
			}

			$termLink = get_term_link($translations[$lang->code], $term->taxonomy);
			if (is_wp_error($termLink)) {
				continue;
			}

			$hreflang = LocaleHelper::getHreflangCode($lang->code);
			$tags[] = ['hreflang' => $hreflang, 'href' => $termLink];

			if ($lang->code === $defaultCode) {
				$defaultHref = $termLink;
			}
		}

		if ($defaultHref !== '') {
			$tags[] = ['hreflang' => 'x-default', 'href' => $defaultHref];
		}

		return $tags;
	}

	/**
	 * Build hreflang tags for archives, home, and other non-singular pages.
	 *
	 * @param array<string, object> $languages
	 * @return array<int, array{hreflang: string, href: string}>
	 */
	private function buildArchiveTags(array $languages, string $defaultCode): array
	{
		$tags = [];
		$defaultHref = '';

		foreach ($languages as $lang) {
			if (!UrlHelper::isLanguageReachable($lang->code)) {
				continue;
			}

			$hreflang = LocaleHelper::getHreflangCode($lang->code);
			$href = UrlHelper::getUrlForLanguage($lang->code);

			$tags[] = [
				'hreflang' => $hreflang,
				'href' => $href,
			];

			if ($lang->code === $defaultCode) {
				$defaultHref = $href;
			}
		}

		if ($defaultHref !== '') {
			$tags[] = [
				'hreflang' => 'x-default',
				'href' => $defaultHref,
			];
		}

		return $tags;
	}
}
