<?php
/**
 * Per-revision dismissal store for content-to-block suggestions.
 *
 * @package SEOvaultSEO\Schema\Content
 */

namespace SEOvaultSEO\Schema\Content;

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

/**
 * Remembers dismissed suggestions keyed by content hash so nags do not repeat
 * for the same revision, but reappear when content changes.
 */
class SchemaContentSuggestionStore {

	const META_KEY = '_seovault_content_suggestion_dismissals';

	/**
	 * Load dismissal map.
	 *
	 * @param int $post_id Post ID.
	 * @return array<string,array{content_hash:string,dismissed_at:int,suggestion_id:string}>
	 */
	public static function get_dismissals( $post_id ) {
		$raw = get_post_meta( (int) $post_id, self::META_KEY, true );
		if ( ! is_array( $raw ) ) {
			return array();
		}
		$out = array();
		foreach ( $raw as $kind => $row ) {
			$kind = sanitize_key( (string) $kind );
			if ( '' === $kind || ! is_array( $row ) ) {
				continue;
			}
			$out[ $kind ] = array(
				'content_hash'   => isset( $row['content_hash'] ) ? sanitize_text_field( (string) $row['content_hash'] ) : '',
				'dismissed_at'   => isset( $row['dismissed_at'] ) ? (int) $row['dismissed_at'] : 0,
				'suggestion_id'  => isset( $row['suggestion_id'] ) ? sanitize_text_field( (string) $row['suggestion_id'] ) : '',
			);
		}
		return $out;
	}

	/**
	 * Whether a suggestion kind is dismissed for the given content hash.
	 *
	 * @param int    $post_id      Post ID.
	 * @param string $kind         faq|howto.
	 * @param string $content_hash Content hash.
	 * @return bool
	 */
	public static function is_dismissed( $post_id, $kind, $content_hash ) {
		$kind = sanitize_key( (string) $kind );
		$hash = (string) $content_hash;
		if ( '' === $kind || '' === $hash ) {
			return false;
		}
		$map = self::get_dismissals( $post_id );
		if ( empty( $map[ $kind ]['content_hash'] ) ) {
			return false;
		}
		return hash_equals( (string) $map[ $kind ]['content_hash'], $hash );
	}

	/**
	 * Dismiss a suggestion for the current content revision.
	 *
	 * @param int    $post_id        Post ID.
	 * @param string $kind           faq|howto.
	 * @param string $content_hash   Content hash.
	 * @param string $suggestion_id  Optional suggestion id.
	 * @return bool
	 */
	public static function dismiss( $post_id, $kind, $content_hash, $suggestion_id = '' ) {
		$post_id = (int) $post_id;
		$kind    = sanitize_key( (string) $kind );
		$hash    = sanitize_text_field( (string) $content_hash );
		if ( $post_id <= 0 || ! in_array( $kind, array( 'faq', 'howto' ), true ) || '' === $hash ) {
			return false;
		}
		$map          = self::get_dismissals( $post_id );
		$map[ $kind ] = array(
			'content_hash'  => $hash,
			'dismissed_at'  => time(),
			'suggestion_id' => sanitize_text_field( (string) $suggestion_id ),
		);
		update_post_meta( $post_id, self::META_KEY, $map );
		return true;
	}

	/**
	 * Clear dismissal for a kind (e.g. after confirm creates a block).
	 *
	 * @param int    $post_id Post ID.
	 * @param string $kind    faq|howto.
	 * @return void
	 */
	public static function clear( $post_id, $kind = '' ) {
		$post_id = (int) $post_id;
		$kind    = sanitize_key( (string) $kind );
		if ( $post_id <= 0 ) {
			return;
		}
		if ( '' === $kind ) {
			delete_post_meta( $post_id, self::META_KEY );
			return;
		}
		$map = self::get_dismissals( $post_id );
		unset( $map[ $kind ] );
		if ( empty( $map ) ) {
			delete_post_meta( $post_id, self::META_KEY );
			return;
		}
		update_post_meta( $post_id, self::META_KEY, $map );
	}

	/**
	 * Fingerprint for validation cache keys.
	 *
	 * @param int $post_id Post ID.
	 * @return string
	 */
	public static function fingerprint( $post_id ) {
		$map = self::get_dismissals( $post_id );
		if ( empty( $map ) ) {
			return '';
		}
		return 'sha256:' . hash( 'sha256', (string) wp_json_encode( $map ) );
	}
}
