<?php
/**
 * SEO fix context service.
 *
 * @package SmartyPress_AI_Engine
 * @since 1.0.0
 */

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

/**
 * Handles SEO fix payload sanitizing, stats, and transient context storage.
 */
class SmartyPress_AI_SEO_Context_Service extends SmartyPress_AI_SEO_Controller_Service_Base {

	/**
	 * Pipeline version.
	 *
	 * @var string
	 */
	private $pipeline_version;

	/**
	 * Context TTL in seconds.
	 *
	 * @var int
	 */
	private $context_ttl;

	/**
	 * Constructor.
	 *
	 * @param string $pipeline_version Pipeline version.
	 * @param int    $context_ttl      Context TTL.
	 */
	public function __construct( $pipeline_version, $context_ttl ) {
		$this->pipeline_version = (string) $pipeline_version;
		$this->context_ttl      = absint( $context_ttl );
	}

	/**
	 * Sanitize incoming payload.
	 *
	 * @param array $params Raw request params.
	 * @return array
	 */
	public function sanitize_payload( $params ) {
		return array(
			'post_id'      => absint( $params['post_id'] ?? 0 ),
			'post_type'    => sanitize_key( $params['post_type'] ?? '' ),
			'language'     => sanitize_text_field( $params['language'] ?? '' ),
			'provider'     => sanitize_key( $params['provider'] ?? '' ),
			'seo'          => $this->sanitize_recursive( $params['seo'] ?? array() ),
			'post'         => $this->sanitize_recursive( $params['post'] ?? array(), true ),
			'failed_tests' => is_array( $params['failed_tests'] ?? null ) ? $this->sanitize_recursive( $params['failed_tests'] ) : array(),
		);
	}

	/**
	 * Build and store a context.
	 *
	 * @param int   $post_id      Post ID.
	 * @param array $payload      Payload.
	 * @param array $local_checks Local pre-check result.
	 * @return array Context response data.
	 */
	public function store_context( $post_id, $payload, $local_checks ) {
		$payload['pipeline_version'] = $this->pipeline_version;
		$payload['context_hash']     = $this->build_context_hash( $post_id, $payload );
		$payload['local_pre_checks'] = $local_checks;

		$context_id = $this->build_context_id( $post_id, $payload['context_hash'] );
		set_transient( $context_id, $payload, $this->context_ttl );

		return array(
			'context_id' => $context_id,
			'payload'    => $payload,
		);
	}

	/**
	 * Load and validate a context.
	 *
	 * @param int    $post_id     Post ID.
	 * @param string $context_id  Context transient key.
	 * @return array|WP_Error
	 */
	public function load_context( $post_id, $context_id ) {
		$context = $context_id ? get_transient( $context_id ) : false;

		if ( ! is_array( $context ) || ( $context['pipeline_version'] ?? '' ) !== $this->pipeline_version ) {
			return new WP_Error(
				'smartypress_ai_seo_context_expired',
				__( 'SEO context expired. Please regenerate SEO fixes.', 'smartypress-ai-engine' ),
				array( 'status' => 410 )
			);
		}

		if ( absint( $context['post_id'] ?? 0 ) !== absint( $post_id ) ) {
			return new WP_Error(
				'smartypress_ai_seo_context_mismatch',
				__( 'SEO context does not match the current post.', 'smartypress-ai-engine' ),
				array( 'status' => 400 )
			);
		}

		return $context;
	}

	/**
	 * Build a stable transient key for a context.
	 *
	 * @param int    $post_id      Post ID.
	 * @param string $context_hash Context hash.
	 * @return string
	 */
	public function build_context_id( $post_id, $context_hash ) {
		return 'spai_seo_fix_' . absint( $post_id ) . '_' . get_current_user_id() . '_' . substr( sanitize_key( $context_hash ), 0, 16 );
	}

	/**
	 * Build a context hash.
	 *
	 * @param int   $post_id Post ID.
	 * @param array $payload Payload.
	 * @return string
	 */
	public function build_context_hash( $post_id, $payload ) {
		$post = get_post( $post_id );
		$seed = array(
			'post_id'       => absint( $post_id ),
			'post_modified' => $post ? $post->post_modified_gmt : '',
			'content'       => $payload['post']['content_plain_text'] ?? '',
			'blocks'        => $payload['post']['blocks'] ?? array(),
			'failed_tests'  => $payload['failed_tests'] ?? array(),
		);

		return md5( wp_json_encode( $seed ) );
	}

	/**
	 * Get lightweight stats for a cached context.
	 *
	 * @param array $payload Payload.
	 * @return array
	 */
	public function get_context_stats( $payload ) {
		$text  = wp_strip_all_tags( (string) ( $payload['post']['content_plain_text'] ?? '' ) );
		$words = preg_split( '/\s+/u', trim( $text ) );

		return array(
			'words'        => '' === trim( $text ) ? 0 : count( array_filter( $words ) ),
			'blocks'       => isset( $payload['post']['blocks'] ) && is_array( $payload['post']['blocks'] ) ? count( $payload['post']['blocks'] ) : 0,
			'failed_tests' => isset( $payload['failed_tests'] ) && is_array( $payload['failed_tests'] ) ? count( $payload['failed_tests'] ) : 0,
		);
	}
}
