<?php
/**
 * Rank Math SEO integration.
 *
 * @package SmartyPress_AI_Engine
 * @since 1.0.0
 */

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

/**
 * Integrates SEO Optimization with Rank Math.
 */
class SmartyPress_AI_Rank_Math_Integration extends SmartyPress_AI_SEO_Provider_Integration {

	/**
	 * Get provider identifier.
	 *
	 * @return string
	 */
	public function get_id() {
		return 'rank-math';
	}

	/**
	 * Get provider label.
	 *
	 * @return string
	 */
	public function get_label() {
		return 'Rank Math';
	}

	/**
	 * Check whether Rank Math is available.
	 *
	 * @return bool
	 */
	public function is_available() {
		return defined( 'RANK_MATH_FILE' ) || defined( 'RANK_MATH_VERSION' ) || function_exists( 'rank_math' );
	}

	/**
	 * Check whether Rank Math supports the post type.
	 *
	 * @param string $post_type Post type name.
	 * @return bool
	 */
	public function supports_post_type( $post_type ) {
		if ( empty( $post_type ) || ! post_type_exists( $post_type ) ) {
			return false;
		}

		if ( class_exists( '\RankMath\Helper' ) && method_exists( '\RankMath\Helper', 'get_allowed_post_types' ) ) {
			$allowed = \RankMath\Helper::get_allowed_post_types();
			return in_array( $post_type, (array) $allowed, true );
		}

		return in_array( $post_type, array( 'post', 'page' ), true );
	}

	/**
	 * Get normalized editor context.
	 *
	 * @param int $post_id Post ID.
	 * @return array
	 */
	public function get_editor_context( $post_id ) {
		$post_id = absint( $post_id );
		$post    = get_post( $post_id );

		if ( ! $post ) {
			return array();
		}

		$keywords = get_post_meta( $post_id, 'rank_math_focus_keyword', true );

		return array(
			'provider'         => $this->get_id(),
			'provider_label'   => $this->get_label(),
			'post_id'          => $post_id,
			'post_type'        => $post->post_type,
			'score'            => absint( get_post_meta( $post_id, 'rank_math_seo_score', true ) ),
			'focus_keywords'   => $this->normalize_keywords( $keywords ),
			'primary_keyword'  => $this->normalize_primary_keyword( $keywords ),
			'seo_title'        => (string) get_post_meta( $post_id, 'rank_math_title', true ),
			'meta_description' => (string) get_post_meta( $post_id, 'rank_math_description', true ),
			'slug'             => (string) $post->post_name,
			'plugin_data'      => array(
				'meta_keys' => array(
					'focus_keywords'   => 'rank_math_focus_keyword',
					'seo_title'        => 'rank_math_title',
					'meta_description' => 'rank_math_description',
					'score'            => 'rank_math_seo_score',
				),
			),
		);
	}

	/**
	 * Get supported tests and common groups.
	 *
	 * @return array
	 */
	public function get_supported_tests() {
		return array(
			'keywordInTitle'           => 'seo_title',
			'titleStartWithKeyword'    => 'seo_title',
			'titleHasNumber'           => 'seo_title',
			'titleHasPowerWords'       => 'seo_title',
			'titleSentiment'           => 'seo_title',
			'keywordInMetaDescription' => 'meta_description',
			'keywordInPermalink'       => 'slug',
			'lengthPermalink'          => 'slug',
			'keywordIn10Percent'       => 'content',
			'keywordInContent'         => 'content',
			'keywordDensity'           => 'content',
			'lengthContent'            => 'content',
			'keywordInSubheadings'     => 'headings',
			'linksHasInternal'         => 'links',
			'linksHasExternals'        => 'links',
			'linksNotAllExternals'     => 'links',
			'contentHasTOC'            => 'readability',
			'contentHasShortParagraphs' => 'readability',
			'contentHasAssets'         => 'media',
			'keywordInImageAlt'        => 'media',
			'hasContentAI'             => 'provider',
			'keywordNotUsed'           => 'provider',
		);
	}

	/**
	 * Normalize Rank Math failed tests.
	 *
	 * @param array $raw_tests Raw failed tests.
	 * @return array
	 */
	public function normalize_failed_tests( $raw_tests ) {
		$supported = $this->get_supported_tests();
		$normalized = array();

		foreach ( (array) $raw_tests as $test ) {
			$id = isset( $test['id'] ) ? preg_replace( '/[^A-Za-z0-9_-]/', '', (string) $test['id'] ) : '';
			if ( '' === $id ) {
				continue;
			}

			$group = isset( $supported[ $id ] ) ? $supported[ $id ] : 'other';

			$normalized[] = array(
				'id'           => $id,
				'provider_id'  => $this->get_id(),
				'group'        => $group,
				'message'      => isset( $test['message'] ) ? sanitize_text_field( $test['message'] ) : '',
				'severity'     => isset( $test['severity'] ) ? sanitize_key( $test['severity'] ) : 'error',
				'fix_strategy' => $this->get_fix_strategy( $id, $group ),
			);
		}

		return $normalized;
	}

	/**
	 * Apply metadata changes on the server side.
	 *
	 * @param int   $post_id Post ID.
	 * @param array $changes Normalized changes.
	 * @return array
	 */
	public function apply_metadata_changes( $post_id, $changes ) {
		$post_id = absint( $post_id );
		$updated = array();

		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return array(
				'success' => false,
				'updated' => $updated,
			);
		}

		if ( isset( $changes['seo_title'] ) && '' !== $changes['seo_title'] ) {
			update_post_meta( $post_id, 'rank_math_title', sanitize_text_field( $changes['seo_title'] ) );
			$updated[] = 'seo_title';
		}

		if ( isset( $changes['meta_description'] ) && '' !== $changes['meta_description'] ) {
			update_post_meta( $post_id, 'rank_math_description', sanitize_text_field( $changes['meta_description'] ) );
			$updated[] = 'meta_description';
		}

		if ( isset( $changes['focus_keywords'] ) && is_array( $changes['focus_keywords'] ) ) {
			update_post_meta( $post_id, 'rank_math_focus_keyword', implode( ', ', array_map( 'sanitize_text_field', $changes['focus_keywords'] ) ) );
			$updated[] = 'focus_keywords';
		}

		if ( isset( $changes['slug'] ) && '' !== $changes['slug'] ) {
			wp_update_post(
				array(
					'ID'        => $post_id,
					'post_name' => sanitize_title( $changes['slug'] ),
				)
			);
			$updated[] = 'slug';
		}

		return array(
			'success' => true,
			'updated' => $updated,
		);
	}

	/**
	 * Get the primary keyword.
	 *
	 * @param string|array $keywords Keywords.
	 * @return string
	 */
	private function normalize_primary_keyword( $keywords ) {
		$items = $this->normalize_keywords( $keywords );

		return isset( $items[0] ) ? $items[0] : '';
	}

	/**
	 * Get recommended fix strategy.
	 *
	 * @param string $test_id Test ID.
	 * @param string $group Common group.
	 * @return string
	 */
	private function get_fix_strategy( $test_id, $group ) {
		$manual_tests = array( 'hasContentAI', 'keywordNotUsed' );

		if ( in_array( $test_id, $manual_tests, true ) ) {
			return 'manual';
		}

		return 'fix_' . $group;
	}
}
