<?php

declare(strict_types=1);

namespace Signocore\Multilanguage\UI;

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

use Signocore\Multilanguage\Application\Constants;
use Signocore\Multilanguage\Features\LanguageManager;
use Signocore\Multilanguage\Infrastructure\Database\TranslationRepository;
use Signocore\Multilanguage\Infrastructure\Traits\Singleton;
use Signocore\Multilanguage\Support\FlagHelper;
use Signocore\Multilanguage\Support\PostTypeHelper;
use Signocore\Multilanguage\Support\TaxonomyHelper;
use Signocore\Multilanguage\Support\TranslationHelper;
use WP_Query;

final class AdminColumns
{
	use Singleton;

	protected function init(): void
	{
		add_action('admin_init', [$this, 'registerColumns']);
		add_action('admin_head', [$this, 'renderColumnStyles']);
		add_action('pre_get_posts', [$this, 'filterAdminByLanguage']);
		add_filter('posts_join', [$this, 'adminJoinTranslation'], 10, 2);
		add_filter('posts_where', [$this, 'adminWhereLanguage'], 10, 2);
	}

	/**
	 * Register translation columns and language views for all translatable post types and taxonomies.
	 */
	public function registerColumns(): void
	{
		if (count(LanguageManager::load()->getActiveLanguages()) <= 1) {
			return;
		}

		foreach (PostTypeHelper::getTranslatablePostTypes() as $postType) {
			if ($postType === 'attachment') {
				continue;
			}

			add_filter("manage_{$postType}_posts_columns", [$this, 'addPostColumn']);
			add_action("manage_{$postType}_posts_custom_column", [$this, 'renderPostColumn'], 10, 2);
			add_filter("views_edit-{$postType}", [$this, 'addLanguageViews']);
		}

		// Media library uses different hooks than standard post type list tables
		if (in_array('attachment', PostTypeHelper::getTranslatablePostTypes(), true)) {
			add_filter('manage_media_columns', [$this, 'addPostColumn']);
			add_action('manage_media_custom_column', [$this, 'renderPostColumn'], 10, 2);
			add_filter('views_upload', [$this, 'addLanguageViews']);
		}

		foreach (TaxonomyHelper::getTranslatableTaxonomies() as $taxonomy) {
			add_filter("manage_edit-{$taxonomy}_columns", [$this, 'addTermColumn']);
			add_filter("manage_{$taxonomy}_custom_column", [$this, 'renderTermColumn'], 10, 3);
		}
	}

	/**
	 * Insert the translations column before seo-health (or append if not present).
	 *
	 * @param array<string, string> $columns
	 * @return array<string, string>
	 */
	public function addPostColumn(array $columns): array
	{
		if (isset($columns['seo-health'])) {
			$newColumns = [];
			foreach ($columns as $key => $label) {
				if ($key === 'seo-health') {
					$newColumns['sml_translations'] = __('Translations', 'signocore-multilanguage');
				}
				$newColumns[$key] = $label;
			}
			return $newColumns;
		}

		$columns['sml_translations'] = __('Translations', 'signocore-multilanguage');

		return $columns;
	}

	/**
	 * Render the translations column content for a post.
	 */
	public function renderPostColumn(string $columnName, int $postId): void
	{
		if ($columnName !== 'sml_translations') {
			return;
		}

		$languages = LanguageManager::load()->getActiveLanguages();
		$elementType = TranslationHelper::resolveElementType($postId);
		$postLanguage = TranslationHelper::getElementLanguage($postId, $elementType);
		$translations = TranslationRepository::getTranslationsForPost($postId);

		echo '<div class="sml-translation-flags">';

		$nonce = wp_create_nonce(Constants::AJAX_NONCE);

		foreach ($languages as $code => $lang) {
			// Skip the post's own language
			if ($code === $postLanguage) {
				continue;
			}

			$translationId = $translations[$code] ?? null;
			$status = 'none';
			$url = '';
			$title = '';

			if ($translationId !== null) {
				$translatedPost = get_post($translationId);
				if ($translatedPost !== null && in_array($translatedPost->post_status, ['publish', 'inherit'], true)) {
					$status = 'published';
				} else {
					$status = 'draft';
				}
				$url = get_edit_post_link($translationId) ?? '';
				/* translators: %s: language name */
				$title = sprintf(__('Edit %s translation', 'signocore-multilanguage'), $lang->name);
			} else {
				$url = admin_url(sprintf(
					'admin-ajax.php?action=sml_create_translation&source_id=%d&lang=%s&_ajax_nonce=%s',
					$postId,
					$code,
					$nonce
				));
				/* translators: %s: language name */
				$title = sprintf(__('Create %s translation', 'signocore-multilanguage'), $lang->name);
			}

			printf(
				'<a href="%s" class="sml-flag-status sml-status-%s" title="%s">%s</a>',
				esc_url($url),
				esc_attr($status),
				esc_attr($title),
				FlagHelper::getFlagImg($code, 16, 12, $lang->name)
			);
		}

		echo '</div>';
	}

	/**
	 * Insert the translations column before seo-health for term tables.
	 *
	 * @param array<string, string> $columns
	 * @return array<string, string>
	 */
	public function addTermColumn(array $columns): array
	{
		if (isset($columns['seo-health'])) {
			$newColumns = [];
			foreach ($columns as $key => $label) {
				if ($key === 'seo-health') {
					$newColumns['sml_translations'] = __('Translations', 'signocore-multilanguage');
				}
				$newColumns[$key] = $label;
			}
			return $newColumns;
		}

		$columns['sml_translations'] = __('Translations', 'signocore-multilanguage');

		return $columns;
	}

	/**
	 * Render the translations column content for a term.
	 */
	public function renderTermColumn(string $content, string $columnName, int $termId): string
	{
		if ($columnName !== 'sml_translations') {
			return $content;
		}

		$screen = get_current_screen();
		$taxonomy = $screen !== null ? $screen->taxonomy : '';

		if ($taxonomy === '') {
			return $content;
		}

		$languages = LanguageManager::load()->getActiveLanguages();
		$elementType = TranslationHelper::resolveTermElementType($termId, $taxonomy);
		$termLanguage = TranslationHelper::getElementLanguage($termId, $elementType);
		$translations = TranslationRepository::getTranslationsForTerm($termId, $taxonomy);

		$output = '<div class="sml-translation-flags">';
		$nonce = wp_create_nonce(Constants::AJAX_NONCE);

		foreach ($languages as $code => $lang) {
			if ($code === $termLanguage) {
				continue;
			}

			$translationId = $translations[$code] ?? null;
			$status = 'none';
			$url = '';
			$title = '';

			if ($translationId !== null) {
				$status = 'published';

				$record = TranslationRepository::findByElementAndLanguage($translationId, $elementType, $code);
				if ($record !== null && $record->status !== Constants::STATUS_PUBLISHED) {
					$status = 'draft';
				}

				$url = get_edit_term_link($translationId, $taxonomy) ?? '';
				/* translators: %s: language name */
				$title = sprintf(__('Edit %s translation', 'signocore-multilanguage'), $lang->name);
			} else {
				$url = admin_url(sprintf(
					'admin-ajax.php?action=sml_create_term_translation&source_id=%d&taxonomy=%s&lang=%s&_ajax_nonce=%s',
					$termId,
					$taxonomy,
					$code,
					$nonce
				));
				/* translators: %s: language name */
				$title = sprintf(__('Create %s translation', 'signocore-multilanguage'), $lang->name);
			}

			$output .= sprintf(
				'<a href="%s" class="sml-flag-status sml-status-%s" title="%s">%s</a>',
				esc_url($url),
				esc_attr($status),
				esc_attr($title),
				FlagHelper::getFlagImg($code, 16, 12, $lang->name)
			);
		}

		$output .= '</div>';

		return $output;
	}

	/**
	 * Add language filter views to the post list table.
	 *
	 * @param array<string, string> $views
	 * @return array<string, string>
	 */
	public function addLanguageViews(array $views): array
	{
		$screen = get_current_screen();
		if ($screen === null) {
			return $views;
		}

		$postType = $screen->post_type ?? '';
		if ($postType === '' || !PostTypeHelper::isTranslatable($postType)) {
			return $views;
		}

		$languages = LanguageManager::load()->getActiveLanguages();
		$defaultLangCode = LanguageManager::load()->getDefaultLanguageCode();
		$elementType = 'post_' . $postType;

		// Count posts per language (excluding trash), includes __total key
		$counts = $this->countPostsByLanguageAndType($elementType, $postType, $defaultLangCode);

		// Only show tabs if at least 2 languages have posts
		$languagesWithPosts = array_filter(
			$counts,
			static fn (int $count, string $key) => $key !== '__total' && $count > 0,
			ARRAY_FILTER_USE_BOTH
		);
		if (count($languagesWithPosts) < 2) {
			return $views;
		}

		$currentLang = $_GET['sml_lang'] ?? $defaultLangCode;
		$baseUrl = ($screen->base === 'upload')
			? admin_url('upload.php')
			: admin_url('edit.php?post_type=' . $postType);

		// Build language filter links — "All languages" first
		$langLinks = [];

		$allUrl = add_query_arg('sml_lang', 'all', $baseUrl);
		$allClass = 'sml-lang-filter' . ($currentLang === 'all' ? ' current' : '');
		$totalCount = $counts['__total'] ?? 0;
		$langLinks[] = sprintf(
			'<a href="%s" class="%s">%s <span class="count">(%d)</span></a>',
			esc_url($allUrl),
			esc_attr($allClass),
			esc_html__('All languages', 'signocore-multilanguage'),
			$totalCount
		);

		foreach ($languages as $code => $lang) {
			$count = $counts[$code] ?? 0;
			if ($count === 0) {
				continue;
			}

			$url = add_query_arg('sml_lang', $code, $baseUrl);
			$cssClass = 'sml-lang-filter';
			if ($currentLang === $code) {
				$cssClass .= ' current';
			}

			$langLinks[] = sprintf(
				'<a href="%s" class="%s">%s %s <span class="count">(%d)</span></a>',
				esc_url($url),
				esc_attr($cssClass),
				FlagHelper::getFlagImg($code, 16, 12, $lang->name),
				esc_html($lang->name),
				$count
			);
		}

		// Use span separators (no trailing pipe — WP's implode adds pipe between li items)
		$views = ['sml_languages' => implode(' <span class="sml-lang-sep">|</span> ', $langLinks)] + $views;

		// Inject sml_lang into status link hrefs so status filters preserve language
		$smlLangParam = $currentLang;
		foreach ($views as $key => &$html) {
			if ($key === 'sml_languages') {
				continue;
			}

			$html = preg_replace_callback(
				'/href=["\']([^"\']+)["\']/',
				static function (array $matches) use ($smlLangParam): string {
					$url = html_entity_decode($matches[1]);
					$url = add_query_arg('sml_lang', $smlLangParam, $url);
					return 'href="' . esc_url($url) . '"';
				},
				$html
			);
		}
		unset($html);

		// Replace status counts with language-aware counts (skip for attachments — media views are MIME-type-based)
		if ($currentLang !== 'all' && $postType !== 'attachment') {
			$statusCounts = $this->countPostsByStatusAndLanguage($postType, $currentLang, $defaultLangCode);
			$allStatusCount = ($statusCounts['publish'] ?? 0) + ($statusCounts['draft'] ?? 0) + ($statusCounts['pending'] ?? 0) + ($statusCounts['private'] ?? 0) + ($statusCounts['future'] ?? 0);

			foreach ($views as $key => &$html) {
				if ($key === 'sml_languages') {
					continue;
				}

				// Determine the correct count for this status view
				$newCount = match ($key) {
					'all' => $allStatusCount,
					'publish', 'draft', 'pending', 'private', 'future', 'trash' => $statusCounts[$key] ?? 0,
					default => null,
				};

				if ($newCount !== null) {
					$html = preg_replace(
						'/<span class="count">\((\d+)\)<\/span>/',
						'<span class="count">(' . $newCount . ')</span>',
						$html
					);
				}
			}
			unset($html);

			// Remove status views with 0 count (except "all")
			foreach ($views as $key => $html) {
				if ($key === 'sml_languages' || $key === 'all') {
					continue;
				}

				$count = match ($key) {
					'publish', 'draft', 'pending', 'private', 'future', 'trash' => $statusCounts[$key] ?? 0,
					default => null,
				};

				if ($count === 0) {
					unset($views[$key]);
				}
			}
		}

		return $views;
	}

	/**
	 * Filter admin post list by language.
	 */
	public function filterAdminByLanguage(WP_Query $query): void
	{
		if (!is_admin() || !$query->is_main_query()) {
			return;
		}

		global $pagenow;
		if (!in_array($pagenow, ['edit.php', 'upload.php'], true)) {
			return;
		}

		$postType = $query->get('post_type') ?: 'post';
		if (!PostTypeHelper::isTranslatable($postType)) {
			return;
		}

		$smlLang = $_GET['sml_lang'] ?? null;

		// "All languages" = no filtering
		if ($smlLang === 'all') {
			return;
		}

		// Default to default language if no param
		if ($smlLang === null) {
			$smlLang = LanguageManager::load()->getDefaultLanguageCode();
		}

		$langManager = LanguageManager::load();
		if (!$langManager->isActiveLanguage($smlLang)) {
			return;
		}

		$query->set('sml_admin_filter_lang', $smlLang);

		// Track whether we're filtering by the default language
		$defaultLangCode = $langManager->getDefaultLanguageCode();
		if ($smlLang === $defaultLangCode) {
			$query->set('sml_admin_filter_default', true);
		}
	}

	/**
	 * Add JOIN clause for admin language filtering.
	 */
	public function adminJoinTranslation(string $join, WP_Query $query): string
	{
		$lang = $query->get('sml_admin_filter_lang');
		if (empty($lang)) {
			return $join;
		}

		global $wpdb;

		$table = $wpdb->prefix . Constants::TABLE_TRANSLATIONS;
		$postType = $query->get('post_type') ?: 'post';
		$elementType = 'post_' . $postType;
		$isDefault = (bool) $query->get('sml_admin_filter_default');

		// LEFT JOIN for default language (includes posts without translation records)
		// INNER JOIN for other languages (only posts with explicit translation records)
		$joinType = $isDefault ? 'LEFT JOIN' : 'INNER JOIN';
		$join .= " {$joinType} `{$table}` AS sml_admin_t ON ({$wpdb->posts}.ID = sml_admin_t.element_id AND sml_admin_t.element_type = '" . esc_sql($elementType) . "')";

		return $join;
	}

	/**
	 * Add WHERE clause for admin language filtering.
	 */
	public function adminWhereLanguage(string $where, WP_Query $query): string
	{
		$lang = (string) $query->get('sml_admin_filter_lang');
		if ($lang === '') {
			return $where;
		}

		$isDefault = (bool) $query->get('sml_admin_filter_default');

		if ($isDefault) {
			// Default language: include posts with matching language OR no translation record at all
			$where .= " AND (sml_admin_t.language_code = '" . esc_sql($lang) . "' OR sml_admin_t.id IS NULL)";
		} else {
			$where .= " AND sml_admin_t.language_code = '" . esc_sql($lang) . "'";
		}

		return $where;
	}

	/**
	 * Count posts per language for a given element type, excluding trashed posts.
	 * Includes unregistered posts in the default language count and a __total key.
	 *
	 * @return array<string, int>
	 */
	private function countPostsByLanguageAndType(string $elementType, string $postType, string $defaultLangCode): array
	{
		global $wpdb;

		$table = $wpdb->prefix . Constants::TABLE_TRANSLATIONS;

		// Count posts with translation records, grouped by language
		$results = $wpdb->get_results($wpdb->prepare(
			"SELECT t.language_code, COUNT(*) as count
			FROM `{$table}` AS t
			INNER JOIN {$wpdb->posts} AS p ON t.element_id = p.ID
			WHERE t.element_type = %s
			AND p.post_status != 'trash'
			GROUP BY t.language_code",
			$elementType
		));

		$counts = [];
		foreach ($results as $row) {
			$counts[$row->language_code] = (int) $row->count;
		}

		// Count posts without any translation record (unregistered posts = default language)
		$unregisteredCount = (int) $wpdb->get_var($wpdb->prepare(
			"SELECT COUNT(*)
			FROM {$wpdb->posts} AS p
			WHERE p.post_type = %s
			AND p.post_status != 'trash'
			AND p.ID NOT IN (
				SELECT t.element_id FROM `{$table}` AS t WHERE t.element_type = %s
			)",
			$postType,
			$elementType
		));

		if ($unregisteredCount > 0) {
			$counts[$defaultLangCode] = ($counts[$defaultLangCode] ?? 0) + $unregisteredCount;
		}

		// Total = actual post count (not sum of language counts)
		$counts['__total'] = (int) $wpdb->get_var($wpdb->prepare(
			"SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = %s AND post_status != 'trash'",
			$postType
		));

		return $counts;
	}

	/**
	 * Count posts per status for a specific language, excluding trash.
	 *
	 * @return array<string, int>
	 */
	private function countPostsByStatusAndLanguage(string $postType, string $langCode, string $defaultLangCode): array
	{
		global $wpdb;

		$table = $wpdb->prefix . Constants::TABLE_TRANSLATIONS;
		$elementType = 'post_' . $postType;
		$isDefault = ($langCode === $defaultLangCode);

		if ($isDefault) {
			// LEFT JOIN to include unregistered posts
			$results = $wpdb->get_results($wpdb->prepare(
				"SELECT p.post_status, COUNT(*) as count
				FROM {$wpdb->posts} AS p
				LEFT JOIN `{$table}` AS t ON (p.ID = t.element_id AND t.element_type = %s)
				WHERE p.post_type = %s
				AND p.post_status != 'auto-draft'
				AND (t.language_code = %s OR t.id IS NULL)
				GROUP BY p.post_status",
				$elementType,
				$postType,
				$langCode
			));
		} else {
			// INNER JOIN for non-default languages
			$results = $wpdb->get_results($wpdb->prepare(
				"SELECT p.post_status, COUNT(*) as count
				FROM {$wpdb->posts} AS p
				INNER JOIN `{$table}` AS t ON (p.ID = t.element_id AND t.element_type = %s)
				WHERE p.post_type = %s
				AND p.post_status != 'auto-draft'
				AND t.language_code = %s
				GROUP BY p.post_status",
				$elementType,
				$postType,
				$langCode
			));
		}

		$counts = [];
		foreach ($results as $row) {
			$counts[$row->post_status] = (int) $row->count;
		}

		return $counts;
	}

	/**
	 * Render inline CSS for translation status columns.
	 */
	public function renderColumnStyles(): void
	{
		$screen = get_current_screen();
		if ($screen === null) {
			return;
		}

		$isRelevant = false;

		if ($screen->base === 'edit' || $screen->base === 'upload') {
			$postType = $screen->post_type ?? '';
			$isRelevant = PostTypeHelper::isTranslatable($postType);
		} elseif ($screen->base === 'edit-tags' || $screen->base === 'term') {
			$taxonomy = $screen->taxonomy ?? '';
			$isRelevant = TaxonomyHelper::isTranslatable($taxonomy);
		}

		if (!$isRelevant) {
			return;
		}

		?>
		<style>
			.column-sml_translations { width: 120px; }
			.sml-translation-flags { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; }
			.sml-flag-status { display: inline-flex; padding: 2px; border-radius: 2px; text-decoration: none; opacity: 0.9; transition: opacity 0.15s; }
			.sml-flag-status:hover { opacity: 1; }
			.sml-status-published { background: #d4edda; border: 1px solid #b1dfbb; }
			.sml-status-draft { background: #fff3cd; border: 1px solid #ffc107; }
			.sml-status-none { background: #e9ecef; border: 1px solid #ced4da; filter: grayscale(100%); opacity: 0.5; }
			.sml-status-none:hover { filter: grayscale(0%); opacity: 1; }
			.subsubsub li.sml_languages { display: block; width: 100%; margin-bottom: 4px; font-size: 0; }
			.sml-lang-filter { font-size: 13px; text-decoration: none; display: inline-flex; align-items: center; gap: 4px; }
			.sml-lang-filter.current { font-weight: 600; }
			.sml-lang-filter img { vertical-align: middle; }
			.sml-lang-sep { font-size: 13px; margin: 0 4px; color: #999; }
		</style>
		<?php
	}
}
