<?php
/**
 * Image ALT SEO context resolver.
 *
 * @package SmartyPress_AI_Engine
 */

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

/**
 * Finds article/page context and SEO keywords for image ALT generation.
 */
class SmartyPress_AI_Image_ALT_SEO_Context {

	/**
	 * Resolve generation context for an attachment.
	 *
	 * @param int $attachment_id Attachment ID.
	 * @return array
	 */
	public function resolve( $attachment_id ) {
		$attachment_id = absint( $attachment_id );
		$attachment    = get_post( $attachment_id );
		$context_posts = $this->find_related_posts( $attachment_id );
		$primary_post  = ! empty( $context_posts ) ? $context_posts[0] : null;
		$keywords      = array();

		foreach ( $context_posts as $post ) {
			$keyword = $this->get_focus_keyword( $post->ID );
			if ( '' !== $keyword ) {
				$keywords[] = $keyword;
			}
		}

		$keywords = array_values( array_unique( array_filter( $keywords ) ) );
		$file     = get_attached_file( $attachment_id );

		return array(
			'attachment_id'    => $attachment_id,
			'attachment_title' => $attachment ? $attachment->post_title : '',
			'current_alt'      => get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ),
			'current_caption'  => $attachment ? $attachment->post_excerpt : '',
			'current_description' => $attachment ? $attachment->post_content : '',
			'filename'         => $file ? $this->clean_filename( wp_basename( $file ) ) : '',
			'primary_post'     => $primary_post ? $this->format_post_context( $primary_post ) : null,
			'related_posts'    => array_map( array( $this, 'format_post_context' ), array_slice( $context_posts, 0, 3 ) ),
			'focus_keywords'   => array_slice( $keywords, 0, 3 ),
		);
	}

	/**
	 * Find posts where attachment is likely used.
	 *
	 * @param int $attachment_id Attachment ID.
	 * @return WP_Post[]
	 */
	private function find_related_posts( $attachment_id ) {
		$posts = array();
		$seen  = array();

		$parent_id = absint( get_post_field( 'post_parent', $attachment_id ) );
		if ( $parent_id ) {
			$parent = get_post( $parent_id );
			if ( $this->is_supported_context_post( $parent ) ) {
				$posts[]              = $parent;
				$seen[ $parent->ID ] = true;
			}
		}

		$featured = get_posts(
			array(
				'post_type'      => get_post_types( array( 'public' => true ) ),
				'post_status'    => array( 'publish', 'draft', 'pending', 'future', 'private' ),
				'posts_per_page' => 3,
				'fields'         => 'all',
				'meta_query'     => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
					array(
						'key'   => '_thumbnail_id',
						'value' => $attachment_id,
					),
				),
			)
		);

		foreach ( $featured as $post ) {
			if ( empty( $seen[ $post->ID ] ) ) {
				$posts[]            = $post;
				$seen[ $post->ID ] = true;
			}
		}

		$url       = wp_get_attachment_url( $attachment_id );
		$filename  = $url ? wp_basename( $url ) : '';
		$needle_id = sprintf( '"id":%d', $attachment_id );
		$queries   = array_filter( array( $needle_id, $filename ) );

		foreach ( $queries as $query ) {
			$matches = get_posts(
				array(
					'post_type'      => get_post_types( array( 'public' => true ) ),
					'post_status'    => array( 'publish', 'draft', 'pending', 'future', 'private' ),
					'posts_per_page' => 3,
					's'              => $query,
				)
			);

			foreach ( $matches as $post ) {
				if ( empty( $seen[ $post->ID ] ) && false !== strpos( (string) $post->post_content, $query ) ) {
					$posts[]            = $post;
					$seen[ $post->ID ] = true;
				}
			}
		}

		return array_slice( $posts, 0, 3 );
	}

	/**
	 * Get primary SEO focus keyword from supported SEO plugins and SmartyPress meta.
	 *
	 * @param int $post_id Post ID.
	 * @return string
	 */
	public function get_focus_keyword( $post_id ) {
		$post_id = absint( $post_id );

		if ( class_exists( 'WPSEO_Meta' ) ) {
			$keyword = \WPSEO_Meta::get_value( 'focuskw', $post_id );
			$keyword = $this->sanitize_keyword( $keyword );
			if ( '' !== $keyword ) {
				return $keyword;
			}
		}

		$meta_keys = array(
			'_yoast_wpseo_focuskw',
			'rank_math_focus_keyword',
			'_smartypress_ai_focus_keywords',
			'smartypress_ai_seo_keywords',
		);

		foreach ( $meta_keys as $meta_key ) {
			$keyword = $this->sanitize_keyword( $this->extract_first_keyword( get_post_meta( $post_id, $meta_key, true ) ) );
			if ( '' !== $keyword ) {
				return $keyword;
			}
		}

		return $this->get_aioseo_focus_keyword( $post_id );
	}

	/**
	 * Read AIOSEO keyphrase from its custom table when available.
	 *
	 * @param int $post_id Post ID.
	 * @return string
	 */
	private function get_aioseo_focus_keyword( $post_id ) {
		global $wpdb;

		$table = $wpdb->prefix . 'aioseo_posts';
		if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) !== $table ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			return '';
		}

		$json = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->prepare(
				'SELECT keyphrases FROM %i WHERE post_id = %d',
				$table,
				$post_id
			)
		);
		$data = $json ? json_decode( $json, true ) : null;

		return $this->sanitize_keyword( $data['focus']['keyphrase'] ?? '' );
	}

	/**
	 * Format context post for REST/UI/prompt.
	 *
	 * @param WP_Post $post Post object.
	 * @return array
	 */
	private function format_post_context( $post ) {
		return array(
			'id'            => $post->ID,
			'title'         => get_the_title( $post ),
			'type'          => get_post_type( $post ),
			'url'           => get_permalink( $post->ID ),
			'edit_url'      => get_edit_post_link( $post->ID, 'raw' ),
			'focus_keyword' => $this->get_focus_keyword( $post->ID ),
			'excerpt'       => $this->get_post_excerpt( $post ),
			'taxonomies'    => $this->get_post_taxonomy_context( $post ),
		);
	}

	/**
	 * Get a short excerpt for prompt context.
	 *
	 * @param WP_Post $post Post object.
	 * @return string
	 */
	private function get_post_excerpt( $post ) {
		$excerpt = '' !== trim( (string) $post->post_excerpt )
			? $post->post_excerpt
			: wp_trim_words( wp_strip_all_tags( strip_shortcodes( (string) $post->post_content ) ), 28, '' );

		return sanitize_text_field( $excerpt );
	}

	/**
	 * Get compact public taxonomy context.
	 *
	 * @param WP_Post $post Post object.
	 * @return string
	 */
	private function get_post_taxonomy_context( $post ) {
		$taxonomies = get_object_taxonomies( $post->post_type, 'names' );
		$terms      = array();

		foreach ( $taxonomies as $taxonomy ) {
			$taxonomy_object = get_taxonomy( $taxonomy );
			if ( ! $taxonomy_object || ! $taxonomy_object->public ) {
				continue;
			}

			$post_terms = get_the_terms( $post->ID, $taxonomy );
			if ( empty( $post_terms ) || is_wp_error( $post_terms ) ) {
				continue;
			}

			foreach ( $post_terms as $term ) {
				$terms[] = $term->name;
			}
		}

		$terms = array_slice( array_values( array_unique( array_filter( $terms ) ) ), 0, 5 );

		return implode( ', ', array_map( 'sanitize_text_field', $terms ) );
	}

	/**
	 * Check whether post can provide useful content context.
	 *
	 * @param WP_Post|null $post Post object.
	 * @return bool
	 */
	private function is_supported_context_post( $post ) {
		return $post instanceof WP_Post && 'attachment' !== $post->post_type;
	}

	/**
	 * Extract first keyword from mixed meta value.
	 *
	 * @param mixed $value Meta value.
	 * @return string
	 */
	private function extract_first_keyword( $value ) {
		if ( is_array( $value ) ) {
			foreach ( $value as $item ) {
				$keyword = $this->extract_first_keyword( $item );
				if ( '' !== $keyword ) {
					return $keyword;
				}
			}
			return '';
		}

		if ( ! is_scalar( $value ) ) {
			return '';
		}

		$parts = preg_split( '/\r\n|\r|\n|,/', (string) $value );
		return (string) ( $parts[0] ?? '' );
	}

	/**
	 * Sanitize and reject switch-like false positives.
	 *
	 * @param mixed $keyword Raw keyword.
	 * @return string
	 */
	private function sanitize_keyword( $keyword ) {
		if ( ! is_scalar( $keyword ) ) {
			return '';
		}

		$keyword = preg_replace( '/\s+/u', ' ', sanitize_text_field( trim( (string) $keyword ) ) );
		$invalid = array( '0', '1', 'on', 'off', 'yes', 'no', 'true', 'false', 'enabled', 'disabled', 'checked', 'unchecked', 'null', 'none' );

		if ( '' === $keyword || mb_strlen( $keyword, 'UTF-8' ) < 3 || in_array( strtolower( $keyword ), $invalid, true ) ) {
			return '';
		}

		return $keyword;
	}

	/**
	 * Convert file name into readable context.
	 *
	 * @param string $filename File name.
	 * @return string
	 */
	private function clean_filename( $filename ) {
		$name = pathinfo( $filename, PATHINFO_FILENAME );
		$name = preg_replace( '/-\d+x\d+$/', '', $name );
		$name = preg_replace( '/[-_]+/', ' ', $name );
		return preg_replace( '/\s+/u', ' ', trim( $name ) );
	}
}
