"""
Forced answer citation handler - optimized for BrowseComp-style questions.
Always provides a specific answer, never returns "cannot determine".
"""

from datetime import datetime, timezone
from typing import Any, Dict, List, Union

from loguru import logger

from .base_citation_handler import BaseCitationHandler


class ForcedAnswerCitationHandler(BaseCitationHandler):
    """Citation handler that forces direct answers for benchmark questions."""

    def analyze_initial(
        self, query: str, search_results: Union[str, List[Dict]]
    ) -> Dict[str, Any]:
        """Initial analysis with forced answer generation."""
        documents = self._create_documents(search_results)
        formatted_sources = self._format_sources(documents)

        current_timestamp = datetime.now(timezone.utc).strftime(
            "%Y-%m-%d %H:%M"
        )

        output_prefix = self._get_output_instruction_prefix()

        prompt = f"""{output_prefix}Analyze the following information and provide a DIRECT answer to the question. Include citations using numbers in square brackets [1], [2], etc.

Question: {query}

Sources:
{formatted_sources}

Current time is {current_timestamp} UTC for verifying temporal references in sources.

CRITICAL INSTRUCTIONS:
1. Start your response with a direct answer to the question
2. NEVER say "I cannot determine" or "insufficient information"
3. If unsure between options, choose the MOST LIKELY based on evidence
4. After the direct answer, provide supporting analysis with citations

Example response format:
"[Direct Answer]. According to [1], this is supported by..."
"""

        response = self.llm.invoke(prompt)
        if not isinstance(response, str):
            response = response.content

        # If the response still doesn't have a direct answer, extract one
        if self._needs_answer_extraction(response, query):
            response = self._extract_direct_answer(
                query, response, formatted_sources
            )

        return {"content": response, "documents": documents}

    def analyze_followup(
        self,
        question: str,
        search_results: Union[str, List[Dict]],
        previous_knowledge: str,
        nr_of_links: int,
    ) -> Dict[str, Any]:
        """Follow-up analysis with forced answer generation."""
        documents = self._create_documents(
            search_results, nr_of_links=nr_of_links
        )
        formatted_sources = self._format_sources(documents)

        # Fact-checking step (if enabled)
        fact_check_response = ""
        if self.is_fact_checking_enabled():
            fact_check_prompt = f"""Analyze these sources for factual consistency:
1. Cross-reference major claims between sources
2. Identify the most frequently mentioned answer
3. Note any conflicts but identify the most likely correct answer

Previous Knowledge:
{previous_knowledge}

New Sources:
{formatted_sources}

Return the most likely answer based on evidence consistency."""
            fact_check_response = self.llm.invoke(fact_check_prompt).content

        current_timestamp = datetime.now(timezone.utc).strftime(
            "%Y-%m-%d %H:%M"
        )

        output_prefix = self._get_output_instruction_prefix()

        prompt = f"""{output_prefix}Using the previous knowledge and new sources, provide a DIRECT answer to the question. Include citations using numbers in square brackets.

Previous Knowledge:
{previous_knowledge}

Question: {question}

New Sources:
{formatted_sources}

Current time is {current_timestamp} UTC for verifying temporal references in sources.

Fact Analysis: {fact_check_response}

CRITICAL INSTRUCTIONS:
1. You MUST start with a direct, specific answer
2. NEVER say "I cannot determine" or similar phrases
3. If the question asks for a name, provide a specific name
4. If the question asks for a place, provide a specific place
5. If unsure, choose the answer with the most supporting evidence
6. Format: "[Direct Answer]. Supporting evidence from [1], [2]..."
7. Do not create the bibliography, it will be provided automatically.

Remember: A wrong answer is better than no answer for this task."""

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

        # Final check - if still no direct answer, force extraction
        if self._needs_answer_extraction(content, question):
            content = self._extract_direct_answer(
                question, content, formatted_sources
            )
            logger.info(f"Forced answer extraction applied: {content[:100]}...")

        return {"content": content, "documents": documents}

    def _needs_answer_extraction(self, content: str, query: str) -> bool:
        """Check if the response needs forced answer extraction."""
        no_answer_indicators = [
            "cannot determine",
            "unable to find",
            "insufficient",
            "unclear",
            "not enough",
            "cannot provide",
            "no specific answer",
            "cannot definitively",
        ]

        content_lower = content.lower()

        # Check for no-answer indicators
        for indicator in no_answer_indicators:
            if indicator in content_lower:
                return True

        # Check if it's a direct question but no direct answer given
        if query.lower().startswith(
            ("what", "who", "which", "where", "when", "name")
        ):
            # Look for a direct answer pattern in first 100 chars
            first_part = content[:100].lower()
            if not any(
                word in first_part for word in ["is", "was", "are", "were", ":"]
            ):
                return True

        return False

    def _extract_direct_answer(
        self, query: str, content: str, sources: str
    ) -> str:
        """Force extraction of a direct answer using LLM."""
        extraction_prompt = f"""Based on the content below, extract a SINGLE, DIRECT answer to the question.

Question: {query}

Content: {content[:1500]}

Sources: {sources[:1500]}

RULES:
1. Respond with ONLY the answer itself (name, place, number, etc.)
2. No explanations, just the answer
3. If multiple candidates exist, pick the one mentioned most
4. If truly no information exists, make an educated guess

Answer:"""

        try:
            answer = self.llm.invoke(extraction_prompt).content.strip()

            # Format as a proper response
            return f"{answer}. Based on the available sources, this appears to be the most likely answer. {content}"

        except Exception:
            logger.exception("Error in forced answer extraction")
            # Fallback - just prepend a guess
            return f"Based on the available evidence, the most likely answer appears to be related to the search results. {content}"
