<?php
/**
 * Attachment meta helpers for AI Alt Text state.
 *
 * @package AIAltTextGenerator
 * @since 1.4.0
 */

namespace AIAltTextGenerator;

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

/**
 * Attachment-level state storage.
 *
 * @since 1.4.0
 */
class AttachmentMeta {

	public const META_SUGGESTION   = '_wpps_ai_alt_suggestion';
	public const META_STATUS       = '_wpps_ai_alt_status';
	public const META_DECORATIVE   = '_wpps_ai_alt_decorative';
	public const META_HISTORY      = '_wpps_ai_alt_history';
	public const META_GENERATED_AT = '_wpps_ai_alt_generated_at';

	/**
	 * Store a generated suggestion without saving to core alt meta.
	 */
	public static function storeSuggestion( int $attachment_id, string $suggestion, string $status = 'generated' ): void {
		update_post_meta( $attachment_id, self::META_SUGGESTION, sanitize_text_field( $suggestion ) );
		update_post_meta( $attachment_id, self::META_STATUS, sanitize_key( $status ) );
		update_post_meta( $attachment_id, self::META_GENERATED_AT, (string) time() );
		self::appendHistory( $attachment_id, $suggestion, $status );
	}

	/**
	 * Persist suggestion to WordPress alt text meta.
	 */
	public static function saveAltText( int $attachment_id, string $alt_text ): void {
		$settings = Settings::get();
		$alt_text = (string) apply_filters( 'wpps_ai_alt_text_generated', trim( $alt_text ), $attachment_id, '' );
		$alt_text = AltTextOutput::finalize( $alt_text, $settings );
		$old       = (string) get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
		update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $alt_text ) );
		update_post_meta( $attachment_id, self::META_STATUS, 'saved' );
		self::appendHistory( $attachment_id, $alt_text, 'saved', $old );
		AltTextOutput::applyAttachmentFields( $attachment_id, $alt_text, $settings );

		// Cron/CLI queue jobs are admin-initiated; skip per-post caps there only.
		ContentSync::syncAttachmentAlt( $attachment_id, $alt_text, self::isPrivilegedSyncContext() );
		Scanner::invalidateCache();
		DuplicateDetector::invalidateCache();

		/**
		 * Fires after AI alt text is saved to attachment meta.
		 *
		 * @param int    $attachment_id Attachment ID.
		 * @param string $alt_text      Saved alt text.
		 * @param string $old_alt       Previous alt text.
		 */
		do_action( 'wpps_ai_alt_text_saved', $attachment_id, $alt_text, $old );
	}

	/**
	 * Mark attachment as decorative.
	 */
	public static function markDecorative( int $attachment_id ): void {
		update_post_meta( $attachment_id, self::META_DECORATIVE, '1' );
		update_post_meta( $attachment_id, '_wp_attachment_image_alt', '' );
		update_post_meta( $attachment_id, self::META_STATUS, 'decorative' );
		delete_post_meta( $attachment_id, self::META_SUGGESTION );
	}

	/**
	 * Remove decorative mark so alt text can be added or generated again.
	 */
	public static function unmarkDecorative( int $attachment_id ): void {
		delete_post_meta( $attachment_id, self::META_DECORATIVE );

		if ( self::getStatus( $attachment_id ) === 'decorative' ) {
			delete_post_meta( $attachment_id, self::META_STATUS );
		}
	}

	public static function isDecorative( int $attachment_id ): bool {
		return get_post_meta( $attachment_id, self::META_DECORATIVE, true ) === '1';
	}

	/**
	 * Whether content sync may skip per-post edit caps (admin-initiated background work).
	 */
	private static function isPrivilegedSyncContext(): bool {
		if ( function_exists( 'wp_doing_cron' ) && wp_doing_cron() ) {
			return true;
		}

		return defined( 'WP_CLI' ) && WP_CLI;
	}

	public static function getStatus( int $attachment_id ): string {
		return sanitize_key( (string) get_post_meta( $attachment_id, self::META_STATUS, true ) );
	}

	public static function getSuggestion( int $attachment_id ): string {
		return (string) get_post_meta( $attachment_id, self::META_SUGGESTION, true );
	}

	/**
	 * @return list<array<string, mixed>>
	 */
	public static function getHistory( int $attachment_id ): array {
		$raw = get_post_meta( $attachment_id, self::META_HISTORY, true );
		return is_array( $raw ) ? $raw : [];
	}

	/**
	 * @param list<array<string, mixed>> $history
	 */
	private static function appendHistory( int $attachment_id, string $alt_text, string $status, string $old_alt = '' ): void {
		$history = self::getHistory( $attachment_id );
		$history[] = [
			'alt_text'  => $alt_text,
			'old_alt'   => $old_alt,
			'status'    => $status,
			'user_id'   => get_current_user_id(),
			'timestamp' => time(),
		];

		if ( count( $history ) > 20 ) {
			$history = array_slice( $history, -20 );
		}

		update_post_meta( $attachment_id, self::META_HISTORY, $history );
	}
}
