<?php
/**
 * Tag entity enrichment: Wikidata lazy fill + optional admin batch.
 *
 * @package Newsroom_AI_Assistant
 */

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

if ( ! function_exists( 'newsai_wikidata_enrich_enabled' ) ) {
	/**
	 * @return bool
	 */
	function newsai_wikidata_enrich_enabled() {
		return get_option( 'newsai_wikidata_enrich_enabled', 'yes' ) === 'yes';
	}
}

if ( ! function_exists( 'newsai_wikidata_sameas_min_score' ) ) {
	/**
	 * Minimum label match score (0–100) before auto Wikidata sameAs is stored or emitted.
	 *
	 * @return int
	 */
	function newsai_wikidata_sameas_min_score() {
		$min = (int) apply_filters( 'nros_wikidata_sameas_min_score', 72 );
		return max( 50, min( 100, $min ) );
	}
}

if ( ! function_exists( 'newsai_wikidata_normalize_label' ) ) {
	/**
	 * @param string $value Tag or Wikidata label.
	 * @return string
	 */
	function newsai_wikidata_normalize_label( $value ) {
		$value = mb_strtolower( trim( (string) $value ), 'UTF-8' );
		if ( $value === '' ) {
			return '';
		}
		if ( function_exists( 'nros_global_unaccent' ) ) {
			$value = nros_global_unaccent( $value );
		}
		$value = preg_replace( '/\s+/u', ' ', $value );
		return trim( $value );
	}
}

if ( ! function_exists( 'newsai_wikidata_match_score' ) ) {
	/**
	 * Compare tag label to a Wikidata search hit.
	 *
	 * @param string               $tag_name Post tag name.
	 * @param array<string, mixed> $match    Search row (label, id, …).
	 * @return int 0–100
	 */
	function newsai_wikidata_match_score( $tag_name, $match ) {
		$tag   = newsai_wikidata_normalize_label( $tag_name );
		$label = newsai_wikidata_normalize_label( isset( $match['label'] ) ? (string) $match['label'] : '' );
		if ( $tag === '' || $label === '' ) {
			return 0;
		}
		if ( $tag === $label ) {
			return 100;
		}
		if ( mb_strpos( $label, $tag ) !== false || mb_strpos( $tag, $label ) !== false ) {
			return 88;
		}
		$pct = 0.0;
		similar_text( $tag, $label, $pct );
		$score = (int) round( $pct );
		$tag_tokens   = array_values( array_filter( explode( ' ', $tag ) ) );
		$label_tokens = array_values( array_filter( explode( ' ', $label ) ) );
		if ( count( $tag_tokens ) > 1 && count( $label_tokens ) > 1 ) {
			$overlap = count( array_intersect( $tag_tokens, $label_tokens ) );
			if ( $overlap > 0 ) {
				$token_score = (int) round( 100 * $overlap / max( count( $tag_tokens ), count( $label_tokens ) ) );
				$score       = max( $score, $token_score );
			}
		}
		return max( 0, min( 100, $score ) );
	}
}

if ( ! function_exists( 'newsai_wikidata_match_passes_gate' ) ) {
	/**
	 * @param string               $tag_name Post tag name.
	 * @param array<string, mixed> $match    Wikidata search hit.
	 * @return bool
	 */
	function newsai_wikidata_match_passes_gate( $tag_name, $match ) {
		return newsai_wikidata_match_score( $tag_name, $match ) >= newsai_wikidata_sameas_min_score();
	}
}

if ( ! function_exists( 'newsai_term_wikidata_sameas_url' ) ) {
	/**
	 * Wikidata sameAs URL safe for JSON-LD (manual URLs always; auto only above confidence gate).
	 *
	 * @param int    $term_id  Post tag term ID.
	 * @param string $tag_name Optional tag label for legacy re-validation.
	 * @return string Escaped URL or empty.
	 */
	function newsai_term_wikidata_sameas_url( $term_id, $tag_name = '' ) {
		$term_id = (int) $term_id;
		$url     = (string) get_term_meta( $term_id, 'nros_wikidata_url', true );
		if ( $url === '' ) {
			return '';
		}
		$url = esc_url_raw( $url );
		if ( $url === '' || strpos( $url, 'wikidata.org/wiki/Q' ) === false ) {
			return '';
		}
		$source = (string) get_term_meta( $term_id, 'nros_wikidata_source', true );
		if ( $source === 'manual' ) {
			return $url;
		}
		$min        = newsai_wikidata_sameas_min_score();
		$confidence = (int) get_term_meta( $term_id, 'nros_wikidata_confidence', true );
		if ( $source === 'auto' && $confidence >= $min ) {
			return $url;
		}
		if ( $tag_name === '' ) {
			$term = get_term( $term_id, 'post_tag' );
			if ( $term && ! is_wp_error( $term ) ) {
				$tag_name = (string) $term->name;
			}
		}
		$stored_label = (string) get_term_meta( $term_id, 'nros_wikidata_label', true );
		if ( $tag_name !== '' && $stored_label !== '' ) {
			$score = newsai_wikidata_match_score( $tag_name, [ 'label' => $stored_label ] );
			if ( $score >= $min ) {
				return $url;
			}
		}
		return '';
	}
}

if ( ! function_exists( 'newsai_wikidata_search_entities' ) ) {
	/**
	 * @param string $search Tag label.
	 * @param string $lang   Wikidata language code.
	 * @return array<int, array{id:string,label:string,description:string,url:string}>
	 */
	function newsai_wikidata_search_entities( $search, $lang = 'en' ) {
		$search = trim( (string) $search );
		if ( $search === '' ) {
			return [];
		}
		$lang = sanitize_key( (string) $lang );
		if ( $lang === '' ) {
			$lang = 'en';
		}
		$cache_key = 'newsai_wiki_search_' . md5( $lang . '|' . mb_strtolower( $search, 'UTF-8' ) );
		$cached    = get_transient( $cache_key );
		if ( is_array( $cached ) ) {
			return $cached;
		}

		$url = add_query_arg(
			[
				'action'   => 'wbsearchentities',
				'search'   => $search,
				'language' => $lang,
				'format'   => 'json',
				'limit'    => 5,
			],
			'https://www.wikidata.org/w/api.php'
		);

		$response = wp_remote_get(
			$url,
			[
				'timeout'    => 8,
				'user-agent' => 'NewsroomOS/' . ( defined( 'NEWSAI_VERSION' ) ? NEWSAI_VERSION : '1.9' ) . ' (WordPress; tag-enrichment)',
			]
		);
		if ( is_wp_error( $response ) ) {
			return [];
		}
		$code = (int) wp_remote_retrieve_response_code( $response );
		if ( $code < 200 || $code >= 300 ) {
			return [];
		}
		$body = json_decode( (string) wp_remote_retrieve_body( $response ), true );
		if ( ! is_array( $body ) || empty( $body['search'] ) || ! is_array( $body['search'] ) ) {
			set_transient( $cache_key, [], 15 * MINUTE_IN_SECONDS );
			return [];
		}

		$out = [];
		foreach ( $body['search'] as $row ) {
			if ( ! is_array( $row ) || empty( $row['id'] ) ) {
				continue;
			}
			$id = preg_replace( '/[^Q0-9]/', '', (string) $row['id'] );
			if ( $id === '' ) {
				continue;
			}
			$label = '';
			if ( isset( $row['label'] ) ) {
				$label = is_string( $row['label'] ) ? $row['label'] : ( isset( $row['label']['value'] ) ? (string) $row['label']['value'] : '' );
			}
			$desc = isset( $row['description'] ) ? (string) $row['description'] : '';
			$out[] = [
				'id'          => $id,
				'label'       => $label,
				'description' => $desc,
				'url'         => 'https://www.wikidata.org/wiki/' . $id,
			];
		}
		set_transient( $cache_key, $out, DAY_IN_SECONDS );
		return $out;
	}
}

if ( ! function_exists( 'newsai_wikidata_guess_entity_type' ) ) {
	/**
	 * @param string $description Wikidata entity description.
	 * @return string Schema type or empty to keep auto.
	 */
	function newsai_wikidata_guess_entity_type( $description ) {
		$d = mb_strtolower( (string) $description, 'UTF-8' );
		if ( $d === '' ) {
			return '';
		}
		if ( preg_match( '/\b(city|capital|town|village|municipality|island|country|region|prefecture)\b/u', $d ) ) {
			return 'Place';
		}
		if ( preg_match( '/\b(company|organization|organisation|ministry|bank|university|party)\b/u', $d ) ) {
			return 'Organization';
		}
		if ( preg_match( '/\b(politician|actor|singer|writer|journalist|athlete|person)\b/u', $d ) ) {
			return 'Person';
		}
		if ( preg_match( '/\b(event|election|war|match|festival|conference)\b/u', $d ) ) {
			return 'Event';
		}
		return '';
	}
}

if ( ! function_exists( 'newsai_enrich_tag_from_wikidata' ) ) {
	/**
	 * Fill empty tag termmeta from Wikidata (idempotent; skips when URL already set).
	 *
	 * @param int  $term_id Post tag term ID.
	 * @param bool $force   Overwrite existing Wikidata URL when true.
	 * @return bool True when meta was updated.
	 */
	function newsai_enrich_tag_from_wikidata( $term_id, $force = false ) {
		$term_id = (int) $term_id;
		if ( $term_id < 1 || ! newsai_wikidata_enrich_enabled() ) {
			return false;
		}
		$term = get_term( $term_id, 'post_tag' );
		if ( ! $term || is_wp_error( $term ) ) {
			return false;
		}

		$existing = (string) get_term_meta( $term_id, 'nros_wikidata_url', true );
		if ( $existing !== '' && ! $force ) {
			return false;
		}
		if ( get_transient( 'newsai_wiki_reject_' . $term_id ) && ! $force ) {
			return false;
		}

		$lock_key = 'newsai_wiki_enrich_lock_' . $term_id;
		if ( get_transient( $lock_key ) ) {
			return false;
		}
		set_transient( $lock_key, 1, 2 * MINUTE_IN_SECONDS );

		$lang = function_exists( 'newsai_get_ui_lang' ) ? newsai_get_ui_lang() : 'en';
		$wiki_lang = ( strpos( $lang, 'el' ) === 0 ) ? 'el' : 'en';
		$matches   = newsai_wikidata_search_entities( (string) $term->name, $wiki_lang );
		if ( empty( $matches ) && $wiki_lang !== 'en' ) {
			$matches = newsai_wikidata_search_entities( (string) $term->name, 'en' );
		}
		if ( empty( $matches ) ) {
			delete_transient( $lock_key );
			return false;
		}

		$best = null;
		$best_score = 0;
		foreach ( $matches as $candidate ) {
			$candidate_score = newsai_wikidata_match_score( (string) $term->name, $candidate );
			if ( $candidate_score > $best_score ) {
				$best_score = $candidate_score;
				$best       = $candidate;
			}
		}
		if ( ! is_array( $best ) || ! newsai_wikidata_match_passes_gate( (string) $term->name, $best ) ) {
			set_transient( 'newsai_wiki_reject_' . $term_id, 1, DAY_IN_SECONDS );
			delete_transient( $lock_key );
			return false;
		}

		$updated = false;

		if ( $force || $existing === '' ) {
			update_term_meta( $term_id, 'nros_wikidata_url', esc_url_raw( $best['url'] ) );
			update_term_meta( $term_id, 'nros_wikidata_label', sanitize_text_field( (string) $best['label'] ) );
			update_term_meta( $term_id, 'nros_wikidata_confidence', (string) $best_score );
			update_term_meta( $term_id, 'nros_wikidata_source', 'auto' );
			$updated = true;
		}

		$saved_type = (string) get_term_meta( $term_id, 'nros_entity_type', true );
		if ( ( $saved_type === '' || $saved_type === 'auto' ) && ! empty( $best['description'] ) ) {
			$guessed = newsai_wikidata_guess_entity_type( $best['description'] );
			if ( $guessed !== '' ) {
				update_term_meta( $term_id, 'nros_entity_type', $guessed );
				$updated = true;
			}
		}

		$lat = (string) get_term_meta( $term_id, 'nros_lat', true );
		$lng = (string) get_term_meta( $term_id, 'nros_lng', true );
		if ( ( $lat === '' || $lng === '' ) && function_exists( 'nros_get_global_cities_graph' ) && function_exists( 'nros_global_unaccent' ) ) {
			$city_map  = nros_get_global_cities_graph();
			$search_key = nros_global_unaccent( (string) $term->name );
			if ( isset( $city_map[ $search_key ] ) ) {
				if ( $lat === '' && isset( $city_map[ $search_key ]['lat'] ) ) {
					update_term_meta( $term_id, 'nros_lat', (string) $city_map[ $search_key ]['lat'] );
					$updated = true;
				}
				if ( $lng === '' && isset( $city_map[ $search_key ]['lng'] ) ) {
					update_term_meta( $term_id, 'nros_lng', (string) $city_map[ $search_key ]['lng'] );
					$updated = true;
				}
				if ( $saved_type === '' || $saved_type === 'auto' ) {
					update_term_meta( $term_id, 'nros_entity_type', 'Place' );
					$updated = true;
				}
			}
		}

		delete_transient( $lock_key );
		return $updated;
	}
}

if ( ! function_exists( 'newsai_enrich_tags_for_post' ) ) {
	/**
	 * @param int $post_id Post ID.
	 */
	function newsai_enrich_tags_for_post( $post_id ) {
		$post_id = (int) $post_id;
		if ( $post_id < 1 ) {
			return;
		}
		$tags = wp_get_post_tags( $post_id, [ 'fields' => 'ids' ] );
		if ( empty( $tags ) ) {
			return;
		}
		foreach ( $tags as $term_id ) {
			newsai_enrich_tag_from_wikidata( (int) $term_id, false );
		}
	}
}

if ( ! function_exists( 'newsai_wikidata_on_set_object_terms' ) ) {
	/**
	 * Lazy Wikidata enrichment when tags are assigned to a post.
	 *
	 * @param int    $object_id Object ID.
	 * @param array  $terms     Term IDs or slugs.
	 * @param array  $tt_ids    Term taxonomy IDs.
	 * @param string $taxonomy  Taxonomy slug.
	 */
	function newsai_wikidata_on_set_object_terms( $object_id, $terms, $tt_ids, $taxonomy ) {
		if ( $taxonomy !== 'post_tag' || ! newsai_wikidata_enrich_enabled() ) {
			return;
		}
		$post_id = (int) $object_id;
		if ( $post_id < 1 || get_post_type( $post_id ) !== 'post' ) {
			return;
		}
		if ( ! empty( $tt_ids ) && is_array( $tt_ids ) ) {
			foreach ( $tt_ids as $tt_id ) {
				$term = get_term_by( 'term_taxonomy_id', (int) $tt_id, 'post_tag' );
				if ( $term && ! is_wp_error( $term ) ) {
					newsai_enrich_tag_from_wikidata( (int) $term->term_id, false );
				}
			}
			return;
		}
		newsai_enrich_tags_for_post( $post_id );
	}
}
add_action( 'set_object_terms', 'newsai_wikidata_on_set_object_terms', 30, 4 );

if ( ! function_exists( 'newsai_wikidata_on_created_term' ) ) {
	/**
	 * @param int    $term_id  Term ID.
	 * @param int    $tt_id    Term taxonomy ID.
	 * @param string $taxonomy Taxonomy slug.
	 */
	function newsai_wikidata_on_created_term( $term_id, $tt_id, $taxonomy ) {
		unset( $tt_id );
		if ( $taxonomy === 'post_tag' ) {
			newsai_enrich_tag_from_wikidata( (int) $term_id, false );
		}
	}
}
add_action( 'created_term', 'newsai_wikidata_on_created_term', 20, 3 );

if ( ! function_exists( 'newsai_ajax_enrich_tag_wikidata' ) ) {
	function newsai_ajax_enrich_tag_wikidata() {
		check_ajax_referer( 'newsai_ajax_nonce', 'nonce' );
		if ( ! is_user_logged_in() || ! current_user_can( 'edit_posts' ) ) {
			wp_send_json_error( [ 'message' => 'unauthorized' ], 403 );
		}
		$term_id = isset( $_POST['term_id'] ) ? (int) $_POST['term_id'] : 0;
		if ( $term_id < 1 ) {
			wp_send_json_error( [ 'message' => 'invalid_term' ], 400 );
		}
		$ok = newsai_enrich_tag_from_wikidata( $term_id, false );
		if ( ! $ok ) {
			wp_send_json_error( [ 'message' => 'no_match' ], 404 );
		}
		wp_send_json_success(
			[
				'wikidata_url' => (string) get_term_meta( $term_id, 'nros_wikidata_url', true ),
				'entity_type'  => (string) get_term_meta( $term_id, 'nros_entity_type', true ),
			]
		);
	}
}
add_action( 'wp_ajax_newsai_enrich_tag_wikidata', 'newsai_ajax_enrich_tag_wikidata' );
