"""
Random template strategy for the Verbatim RAG system.

Provides random template selection from a pool of diverse templates.
Templates can be generated using LLM or manually curated.
"""

import random
from typing import Any, Dict, List, Optional

from verbatim_core.llm_client import LLMClient

from .base import TemplateStrategy
from .filler import TemplateFiller


class RandomTemplate(TemplateStrategy):
    """
    Random template strategy that selects from a pool of templates.

    This strategy maintains a collection of templates and randomly selects
    one for each use. Templates can be manually added or generated using
    an LLM for diversity.
    """

    DEFAULT_TEMPLATES = [
        """## Key Findings

Based on the documents, here are the relevant facts:

[DISPLAY_SPANS]

*These excerpts are taken verbatim from the source materials.*""",
        """### Response

The following information addresses your question:

[DISPLAY_SPANS]

---
*Source: Verbatim extracts from provided documents*""",
        """## Answer

Here's what I found in the documents:

[DISPLAY_SPANS]

These excerpts are copied exactly from the source materials to ensure accuracy.""",
        """**Summary of Findings:**

[DISPLAY_SPANS]

*Note: All content above is extracted word-for-word from the source documents.*""",
        """### Document Analysis

The relevant information from the documents includes:

[DISPLAY_SPANS]

---
*These are verbatim excerpts to maintain accuracy.*""",
    ]

    def __init__(
        self,
        templates: List[str] = None,
        llm_client: Optional[LLMClient] = None,
        citation_mode: str = "inline",
    ):
        """
        Initialize random template strategy.

        :param templates: Optional list of templates (uses defaults if None)
        :param llm_client: Optional LLM client for generating more templates
        """
        self.templates = templates or self.DEFAULT_TEMPLATES.copy()
        self.llm_client = llm_client
        self.citation_mode = citation_mode
        self.filler = TemplateFiller(citation_mode=citation_mode)

        # Validate all templates
        for template in self.templates:
            self.validate_template(template)

    def set_citation_mode(self, citation_mode: str) -> None:
        self.citation_mode = citation_mode
        self.filler.set_citation_mode(citation_mode)

    def generate(self, question: str, spans: List[str], citation_count: int = 0) -> str:
        """
        Randomly select a template from the pool.

        :param question: User's question (not used for selection)
        :param spans: List of spans (not used for selection)
        :param citation_count: Number of citation spans (not used for selection)
        :return: Randomly selected template
        """
        if not self.templates:
            return self._get_fallback_template()

        return random.choice(self.templates)

    def fill(
        self,
        template: str,
        display_spans: List[Dict[str, Any]],
        citation_spans: List[Dict[str, Any]],
    ) -> str:
        """
        Fill the template with actual span content.

        :param template: Template string with placeholders
        :param display_spans: Spans to display with full text
        :param citation_spans: Spans for citation reference only
        :return: Filled template
        """
        return self.filler.fill(template, display_spans, citation_spans)

    def save_state(self) -> Dict[str, Any]:
        """
        Save the current template pool.

        :return: Dictionary with template pool state
        """
        return {"type": "random", "templates": self.templates}

    def load_state(self, state: Dict[str, Any]) -> None:
        """
        Load template pool from saved state.

        :param state: Dictionary with template pool configuration
        """
        if "templates" in state:
            self.templates = state["templates"]
            # Validate all loaded templates
            for template in self.templates:
                try:
                    self.validate_template(template)
                except ValueError as e:
                    print(f"Warning: Invalid template removed during load: {e}")
                    self.templates.remove(template)

    def add_template(self, template: str) -> None:
        """
        Add a new template to the pool.

        :param template: Template to add
        :raises ValueError: If template is invalid
        """
        self.validate_template(template)
        if template not in self.templates:
            self.templates.append(template)

    def remove_template(self, template: str) -> bool:
        """
        Remove a template from the pool.

        :param template: Template to remove
        :return: True if template was found and removed
        """
        if template in self.templates:
            self.templates.remove(template)
            return True
        return False

    def clear_templates(self) -> None:
        """Clear all templates from the pool."""
        self.templates.clear()

    def get_template_count(self) -> int:
        """
        Get the number of templates in the pool.

        :return: Number of templates
        """
        return len(self.templates)

    def generate_diverse_templates(self, count: int = 10) -> None:
        """
        Generate diverse templates using LLM and add to pool.

        :param count: Number of templates to generate
        :raises ValueError: If no LLM client is available
        """
        if not self.llm_client:
            raise ValueError("LLM client required for template generation")

        prompt = f"""Create {count} diverse answer templates for a Q&A system using **Markdown formatting**. Each should:

1. Include exactly one [DISPLAY_SPANS] placeholder
2. Have different styles (casual, formal, brief, detailed, etc.)
3. Work for any question type
4. Show variety in structure and tone
5. **Use markdown formatting** (headers, bold, italic, lists) for better presentation

Use markdown elements like:
- **Bold text** for emphasis
- *Italic text* for subtle emphasis
- ### Headers for sections
- - Bullet points for lists
- > Blockquotes for highlighting

Return only the templates, one per line. No numbering or explanations."""

        try:
            response = self.llm_client.complete(prompt, temperature=0.8)
            templates = [t.strip() for t in response.split("\n") if t.strip()]

            # Filter and add valid templates
            added_count = 0
            for template in templates:
                try:
                    self.validate_template(template)
                    if template not in self.templates:
                        self.templates.append(template)
                        added_count += 1
                except ValueError:
                    continue  # Skip invalid templates

            print(f"Generated and added {added_count} new templates to the pool")

        except Exception as e:
            print(f"Template generation failed: {e}")
            # Add some fallback templates if generation fails
            fallback_templates = [
                "Here's what the documents reveal:\n\n[DISPLAY_SPANS]",
                "Key findings from the sources:\n\n[DISPLAY_SPANS]",
                "The documents indicate:\n\n[DISPLAY_SPANS]",
            ]

            for template in fallback_templates:
                if template not in self.templates:
                    self.templates.append(template)

    def _get_fallback_template(self) -> str:
        """Get a fallback template when pool is empty."""
        return """## Response

Based on the available documents:

[DISPLAY_SPANS]

---
*These excerpts are taken verbatim from the source documents.*"""
