"""
Topic generation utilities for news items.
Uses LLM to extract relevant topics/tags from news content.
"""

from loguru import logger
from typing import List

from ...utilities.json_utils import extract_json, get_llm_response_text


def generate_topics(
    query: str,
    findings: str = "",
    category: str = "",
    max_topics: int = 5,
    settings_snapshot=None,
) -> List[str]:
    """
    Generate relevant topics/tags from news content.

    Args:
        query: The search query or research question
        findings: The research findings/content
        category: The news category (if available)
        max_topics: Maximum number of topics to generate
        settings_snapshot: User settings snapshot threaded to get_llm so
            the LLM PEP (evaluate_llm_endpoint) fires under
            llm.require_local_endpoint. Mirrors headline_generator.py.

    Returns:
        List of topic strings
    """
    # Try LLM generation first
    topics = _generate_with_llm(
        query, findings, category, max_topics, settings_snapshot
    )

    # No fallback - if LLM fails, mark as missing
    if not topics:
        topics = ["[Topic generation failed]"]

    # Ensure we have valid topics
    return _validate_topics(topics, max_topics)


def _generate_with_llm(
    query: str,
    findings: str,
    category: str,
    max_topics: int,
    settings_snapshot=None,
) -> List[str]:
    """Generate topics using LLM."""
    try:
        from ...config.llm_config import get_llm

        logger.debug(
            f"Topic generation - findings length: {len(findings) if findings else 0}, category: {category}"
        )

        # Use the configured model for topic generation
        llm = get_llm(temperature=0.5, settings_snapshot=settings_snapshot)

        try:
            # Prepare context
            query_preview = query[:500] if len(query) > 500 else query
            findings_preview = (
                findings[:1000]
                if findings and len(findings) > 1000
                else findings
            )

            prompt = f"""Extract relevant topics/tags from this news content.

Query: {query_preview}
{f"Content: {findings_preview}" if findings_preview else ""}
{f"Category: {category}" if category else ""}

Generate {max_topics} specific, relevant topics that would help categorize and filter this news item.

Requirements:
- Each topic should be 1-3 words
- Topics should be specific and meaningful
- Include geographic regions if mentioned
- Include key entities (countries, organizations, people)
- Include event types (conflict, economy, disaster, etc.)
- Topics should be diverse and cover different aspects

Return ONLY a JSON array of topic strings, like: ["Topic 1", "Topic 2", "Topic 3"]"""

            response = llm.invoke(prompt)
            content = get_llm_response_text(response)

            # Try to parse the JSON response
            topics = extract_json(content, expected_type=list)

            if topics is not None:
                # Clean and validate each topic
                cleaned_topics = []
                for topic in topics:
                    if isinstance(topic, str):
                        cleaned = topic.strip()
                        if cleaned and len(cleaned) <= 30:  # Max topic length
                            cleaned_topics.append(cleaned)

                logger.debug(f"Generated topics: {cleaned_topics}")
                return cleaned_topics[:max_topics]

            # Try to extract topics from plain text response
            logger.debug(f"Failed to parse LLM topics as JSON: {content}")
            if "," in content:
                topics = [t.strip().strip("\"'") for t in content.split(",")]
                return [t for t in topics if t and len(t) <= 30][:max_topics]
        finally:
            from ...utilities.resource_utils import safe_close

            safe_close(llm, "topic LLM")

    except Exception as e:
        logger.debug(f"LLM topic generation failed: {e}")

    return []


def _validate_topics(topics: List[str], max_topics: int) -> List[str]:
    """Validate and clean topics."""
    valid_topics = []
    seen = set()

    for topic in topics:
        if not topic:
            continue

        # Clean the topic
        cleaned = topic.strip()

        # Skip if too short or too long
        if len(cleaned) < 2 or len(cleaned) > 30:
            continue

        # Skip duplicates (case-insensitive)
        normalized = cleaned.lower()
        if normalized in seen:
            continue
        seen.add(normalized)

        # Convert to lowercase as djpetti suggested
        valid_topics.append(normalized)

        if len(valid_topics) >= max_topics:
            break

    # Don't add default topics - show what actually happened
    if not valid_topics:
        valid_topics = ["[No valid topics]"]

    return valid_topics
