<?php

namespace AIPT\Api\BulkGenerator\SeoMeta\Core;

class SeoAnalysisService {

	public static function analyze( int $product_id, $focus_keywords, $plugin_config ) {
		$product = \wc_get_product( $product_id );
		if ( ! $product ) {
			return self::get_empty_analysis();
		}

		if ( ! is_array( $plugin_config ) ) {
			$plugin_config = array();
		}
		$meta_keys = $plugin_config['meta_keys'] ?? array();
		$product_title    = $product->get_name();
		$product_content  = $product->get_description();
		$short_desc       = $product->get_short_description();
		$slug             = \get_post_field( 'post_name', $product_id );
		$featured_image   = $product->get_image_id();

		$seo_title = '';
		$seo_desc  = '';
		if ( ! empty( $meta_keys['title_key'] ) ) {
			$seo_title = \get_post_meta( $product_id, $meta_keys['title_key'], true );
		}
		if ( ! empty( $meta_keys['description_key'] ) ) {
			$seo_desc = \get_post_meta( $product_id, $meta_keys['description_key'], true );
		}

		$effective_title = ! empty( $seo_title ) ? $seo_title : $product_title;
		$effective_desc  = ! empty( $seo_desc ) ? $seo_desc : $short_desc;

		$normalized_keywords = array();
		if ( is_string( $focus_keywords ) && ! empty( $focus_keywords ) ) {

			$normalized_keywords = array_values( array_filter( array_map( 'trim', preg_split( '/[,;]+/', $focus_keywords ) ) ) );
		} elseif ( is_array( $focus_keywords ) ) {
			$normalized_keywords = array_values( array_filter( array_map( 'trim', array_map( 'strval', $focus_keywords ) ) ) );
		}
		$primary_keyword = ! empty( $normalized_keywords ) ? $normalized_keywords[0] : '';

		return array(
			'basic_seo'           => self::analyze_basic_seo( $normalized_keywords, $effective_title, $effective_desc, $slug, $product_content ),
			'title_readability'   => self::analyze_title_readability( $effective_title, $primary_keyword ),
			'content_readability' => self::analyze_content_readability( $product_content, $featured_image ),
			'additional'          => self::analyze_additional( $effective_desc, $normalized_keywords ),
		);
	}

	private static function analyze_basic_seo( $keywords, $title, $description, $slug, $content ) {
		$checks = array();

		$checks['keyword_in_title'] = self::check_keyword_presence(
			$keywords,
			$title,
			'Keyword in Title',
			'Focus keyword appears in SEO title',
			'Focus keyword does not appear in SEO title'
		);

		$checks['keyword_in_description'] = self::check_keyword_presence(
			$keywords,
			$description,
			'Keyword in Description',
			'Focus keyword appears in meta description',
			'Focus keyword not found in meta description'
		);

		$checks['keyword_in_url'] = self::check_keyword_presence(
			$keywords,
			$slug,
			'Keyword in URL',
			'Focus keyword used in the URL',
			'Focus keyword not found in URL'
		);

		$clean_content = \wp_strip_all_tags( $content );

		$checks['keyword_in_content'] = self::check_keyword_presence(
			$keywords,
			$clean_content,
			'Keyword in Content',
			'Focus keyword appears in content',
			'Focus keyword does not appear in content'
		);

		$content_length            = self::safe_strlen( $clean_content );
		$checks['content_length']  = self::create_check(
			$content_length >= 300 ? 'pass' : ( $content_length >= 200 ? 'warning' : 'fail' ),
			'Content Length',
			$content_length >= 300
				? "Content is {$content_length} characters"
				: "Content is {$content_length} characters. Consider using at least 300 characters."
		);

		return $checks;
	}

	private static function analyze_title_readability( $title, $primary_keyword ) {
		$checks       = array();
		$title_length = self::safe_strlen( $title );

		if ( $title_length >= 50 && $title_length <= 60 ) {
			$status = 'pass';
		} elseif ( ( $title_length >= 30 && $title_length < 50 ) || ( $title_length > 60 && $title_length <= 70 ) ) {
			$status = 'warning';
		} else {
			$status = 'fail';
		}

		$checks['title_length'] = self::create_check(
			$status,
			'Title Length',
			"Title is {$title_length} characters" . ( $status !== 'pass' ? '. Optimal: 50-60 characters.' : '.' )
		);

		if ( ! empty( $primary_keyword ) ) {
			$title_lower   = self::safe_strtolower( $title );
			$keyword_lower = self::safe_strtolower( $primary_keyword );
			$keyword_pos   = self::safe_strpos( $title_lower, $keyword_lower, 0 );
			$half_length   = self::safe_strlen( $title ) / 2;

			$checks['keyword_at_beginning'] = self::create_check(
				$keyword_pos !== false && $keyword_pos < $half_length ? 'pass' : 'warning',
				'Keyword Position',
				$keyword_pos !== false && $keyword_pos < $half_length
					? 'Focus keyword appears at the beginning of title'
					: 'Focus keyword does not appear at the beginning of title'
			);
		}

		return $checks;
	}

	private static function analyze_content_readability( $content, $featured_image_id ) {
		$checks = array();

		$checks['has_images'] = self::create_check(
			! empty( $featured_image_id ) ? 'pass' : 'warning',
			'Featured Image',
			! empty( $featured_image_id )
				? 'Product has a featured image'
				: 'Add a featured image to improve engagement'
		);

		$has_paragraphs          = self::safe_strpos( $content, '</p>', 0 ) !== false || substr_count( $content, "\n\n" ) > 0;
		$checks['has_paragraphs'] = self::create_check(
			$has_paragraphs ? 'pass' : 'warning',
			'Paragraph Structure',
			$has_paragraphs
				? 'Content has proper paragraph structure'
				: 'Consider breaking content into multiple paragraphs'
		);

		return $checks;
	}

	private static function analyze_additional( $description, $keywords ) {
		$checks      = array();
		$desc_length = self::safe_strlen( $description );

		if ( $desc_length >= 140 && $desc_length <= 160 ) {
			$status = 'pass';
		} elseif ( ( $desc_length >= 120 && $desc_length < 140 ) || ( $desc_length > 160 && $desc_length <= 180 ) ) {
			$status = 'warning';
		} else {
			$status = 'fail';
		}

		$checks['meta_description_length'] = self::create_check(
			$status,
			'Description Length',
			$desc_length > 0
				? "Meta description is {$desc_length} characters" . ( $status !== 'pass' ? '. Optimal: 140-160 characters.' : '.' )
				: 'No meta description set'
		);

		$checks['has_focus_keyword'] = self::create_check(
			! empty( $keywords ) ? 'pass' : 'fail',
			'Focus Keyword',
			! empty( $keywords )
				? 'Focus keyword is set'
				: 'No focus keyword set'
		);

		return $checks;
	}

	private static function check_keyword_presence( $keywords, $text, $label, $pass_msg, $fail_msg ) {

		if ( empty( $keywords ) || empty( $text ) ) {
			return self::create_check( 'fail', $label, $fail_msg );
		}

		$text_lower = self::safe_strtolower( $text );
		foreach ( $keywords as $keyword ) {
			if ( ! empty( $keyword ) && self::safe_strpos( $text_lower, self::safe_strtolower( $keyword ), 0 ) !== false ) {
				return self::create_check( 'pass', $label, $pass_msg );
			}
		}

		return self::create_check( 'fail', $label, $fail_msg );
	}

	private static function create_check( $status, $label, $message ) {
		return array(
			'status'  => $status,
			'label'   => $label,
			'message' => $message,
		);
	}

	private static function get_empty_analysis() {
		return array(
			'basic_seo'           => array(),
			'title_readability'   => array(),
			'content_readability' => array(),
			'additional'          => array(),
		);
	}

	/**
	 * Safe strlen with mbstring fallback.
	 *
	 * @param string $string The string to measure.
	 * @return int String length.
	 */
	private static function safe_strlen( $string ) {
		if ( function_exists( 'mb_strlen' ) ) {
			return mb_strlen( $string, 'UTF-8' );
		}
		return strlen( $string );
	}

	/**
	 * Safe strtolower with mbstring fallback.
	 *
	 * @param string $string The string to convert.
	 * @return string Lowercase string.
	 */
	private static function safe_strtolower( $string ) {
		if ( function_exists( 'mb_strtolower' ) ) {
			return mb_strtolower( $string, 'UTF-8' );
		}
		return strtolower( $string );
	}

	/**
	 * Safe strpos with mbstring fallback.
	 *
	 * @param string $haystack The string to search in.
	 * @param string $needle   The string to search for.
	 * @param int    $offset   Optional offset.
	 * @return int|false Position or false if not found.
	 */
	private static function safe_strpos( $haystack, $needle, $offset = 0 ) {
		if ( function_exists( 'mb_strpos' ) ) {
			return mb_strpos( $haystack, $needle, $offset, 'UTF-8' );
		}
		return strpos( $haystack, $needle, $offset );
	}

	/**
	 * Calculate SEO score from analysis results.
	 *
	 * Category weights:
	 * - basic_seo: 50% (keyword checks + content length)
	 * - title_readability: 20% (title length + keyword position)
	 * - content_readability: 15% (images + paragraphs)
	 * - additional: 15% (meta description length + focus keyword)
	 *
	 * Status scoring: pass = 100%, warning = 50%, fail = 0%
	 *
	 * @param array $analysis_details The analysis results from analyze().
	 *
	 * @return int|null Score 0-100 or null if no checks available.
	 */
	public static function calculate_score( $analysis_details ) {
		if ( empty( $analysis_details ) ) {
			return null;
		}

		$category_weights = array(
			'basic_seo'           => 50,
			'title_readability'   => 20,
			'content_readability' => 15,
			'additional'          => 15,
		);

		$total_weighted_score = 0;
		$total_weight_used    = 0;

		foreach ( $category_weights as $category => $weight ) {
			if ( empty( $analysis_details[ $category ] ) || ! is_array( $analysis_details[ $category ] ) ) {
				continue;
			}

			$category_checks = $analysis_details[ $category ];
			

			$valid_checks = array_filter( $category_checks, function ( $check ) {
				return isset( $check['status'] );
			} );
			$check_count  = count( $valid_checks );

			if ( 0 === $check_count ) {
				continue;
			}

			$category_score = 0;
			foreach ( $valid_checks as $check ) {
				switch ( $check['status'] ) {
					case 'pass':
						$category_score += 100;
						break;
					case 'warning':
						$category_score += 50;
						break;
					case 'fail':
					default:
						$category_score += 0;
						break;
				}
			}

			$normalized_category_score = $category_score / $check_count;

			$total_weighted_score += ( $normalized_category_score * $weight ) / 100;
			$total_weight_used    += $weight;
		}

		if ( 0 === $total_weight_used ) {
			return null;
		}

		$final_score = ( $total_weighted_score / $total_weight_used ) * 100;

		return (int) round( $final_score );
	}

	/**
	 * Get score label based on score value.
	 *
	 * Thresholds match RankMath:
	 * - 81-100: good
	 * - 51-80: ok
	 * - 1-50: needs_work
	 * - 0: needs_work
	 * - null: no_data
	 *
	 * @param int|null $score The score value (0-100) or null.
	 *
	 * @return string Score label: 'good', 'ok', 'needs_work', or 'no_data'.
	 */
	public static function get_score_label( $score ) {
		if ( null === $score ) {
			return 'no_data';
		}
		if ( $score >= 81 ) {
			return 'good';
		}
		if ( $score >= 51 ) {
			return 'ok';
		}
		return 'needs_work';
	}
}
