<?php
/**
 * Duplicate alt text detection.
 *
 * @package AIAltTextGenerator
 * @since 1.6.0
 */

namespace AIAltTextGenerator;

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

/**
 * @since 1.6.0
 */
class DuplicateDetector {

	private const CACHE_KEY = 'wpps_ai_alt_duplicates_v1';
	private const CACHE_TTL = HOUR_IN_SECONDS;

	/**
	 * Count alt strings used on 2+ images.
	 */
	public static function countDuplicates(): int {
		$groups = self::getDuplicateGroups();
		return count( $groups );
	}

	/**
	 * @return array<string, list<int>> alt_text => attachment IDs
	 */
	public static function getDuplicateGroups( bool $force_refresh = false ): array {
		if ( ! $force_refresh ) {
			$cached = get_transient( self::CACHE_KEY );
			if ( is_array( $cached ) ) {
				return $cached;
			}
		}

		global $wpdb;

		$mimes      = AltTextGenerator::getSupportedMimes();
		$mime_place = implode( ',', array_fill( 0, count( $mimes ), '%s' ) );
		$args       = array_merge( [ 'attachment', 'inherit', AttachmentMeta::META_DECORATIVE ], $mimes );

		$rows = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT LOWER(TRIM(am.meta_value)) AS alt_key, GROUP_CONCAT(p.ID) AS ids, COUNT(*) AS cnt
				FROM {$wpdb->posts} p
				INNER JOIN {$wpdb->postmeta} am ON am.post_id = p.ID
					AND am.meta_key = '_wp_attachment_image_alt'
					AND am.meta_value != ''
				LEFT JOIN {$wpdb->postmeta} dm ON dm.post_id = p.ID
					AND dm.meta_key = %s AND dm.meta_value = '1'
				WHERE p.post_type = %s AND p.post_status = %s
				AND p.post_mime_type IN ($mime_place)
				AND dm.post_id IS NULL
				AND CHAR_LENGTH(TRIM(am.meta_value)) >= 5
				GROUP BY alt_key
				HAVING cnt > 1
				ORDER BY cnt DESC
				LIMIT 500",
				...$args
			),
			ARRAY_A
		);

		$groups = [];
		if ( is_array( $rows ) ) {
			foreach ( $rows as $row ) {
				$key = (string) ( $row['alt_key'] ?? '' );
				if ( $key === '' ) {
					continue;
				}
				$ids = array_map( 'intval', array_filter( explode( ',', (string) ( $row['ids'] ?? '' ) ) ) );
				if ( count( $ids ) > 1 ) {
					$groups[ $key ] = $ids;
				}
			}
		}

		set_transient( self::CACHE_KEY, $groups, self::CACHE_TTL );

		return $groups;
	}

	public static function invalidateCache(): void {
		delete_transient( self::CACHE_KEY );
	}

	/**
	 * @return list<int>
	 */
	public static function getDuplicateAttachmentIds(): array {
		$ids = [];
		foreach ( self::getDuplicateGroups() as $group ) {
			foreach ( $group as $id ) {
				$ids[] = (int) $id;
			}
		}

		return array_values( array_unique( $ids ) );
	}

	/**
	 * Context for regenerating a more specific alt when duplicates exist.
	 *
	 * @return array{shared_alt: string, count: int}|null
	 */
	public static function getContextForAttachment( int $attachment_id ): ?array {
		foreach ( self::getDuplicateGroups() as $alt_key => $ids ) {
			if ( in_array( $attachment_id, $ids, true ) ) {
				return [
					'shared_alt' => $alt_key,
					'count'      => count( $ids ),
				];
			}
		}

		return null;
	}
}
