"""
Prompt Manager - Centralized prompt management using resumen.md as source of truth
"""

import re
import os
from pathlib import Path
from typing import Optional, Dict, Any
from config import settings


class PromptManager:
    """
    Manages prompts for AI services, loading templates from latex/resumen.md
    This is the SINGLE SOURCE OF TRUTH for academic summary generation.
    """

    _instance = None
    _prompt_cache: Optional[str] = None
    _latex_preamble_cache: Optional[str] = None

    # Path to the prompt template file
    PROMPT_FILE_PATH = Path("latex/resumen.md")

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(PromptManager, cls).__new__(cls)
        return cls._instance

    def _load_prompt_template(self) -> str:
        """Load the complete prompt template from resumen.md"""
        if self._prompt_cache:
            return self._prompt_cache

        try:
            file_path = self.PROMPT_FILE_PATH.resolve()

            if not file_path.exists():
                self._prompt_cache = self._get_fallback_prompt()
                return self._prompt_cache

            content = file_path.read_text(encoding="utf-8")

            # The file has a markdown code block after "## Prompt Template"
            # We need to find the content from "## Prompt Template" to the LAST ```
            # (because there's a ```latex...``` block INSIDE the template)

            # First, find where "## Prompt Template" starts
            template_start = content.find("## Prompt Template")
            if template_start == -1:
                self._prompt_cache = self._get_fallback_prompt()
                return self._prompt_cache

            # Find the opening ``` after the header
            after_header = content[template_start:]
            code_block_start = after_header.find("```")
            if code_block_start == -1:
                self._prompt_cache = self._get_fallback_prompt()
                return self._prompt_cache

            # Skip the opening ``` and any language specifier
            after_code_start = after_header[code_block_start + 3:]
            first_newline = after_code_start.find("\n")
            if first_newline != -1:
                actual_content_start = template_start + code_block_start + 3 + first_newline + 1
            else:
                actual_content_start = template_start + code_block_start + 3

            # Now find the LAST ``` that closes the main block
            # We look for ``` followed by optional space and then newline or end
            remaining = content[actual_content_start:]

            # Find all positions of ``` in the remaining content
            positions = []
            pos = 0
            while True:
                found = remaining.find("```", pos)
                if found == -1:
                    break
                positions.append(found)
                pos = found + 3

            if not positions:
                self._prompt_cache = self._get_fallback_prompt()
                return self._prompt_cache

            # The LAST ``` is the closing of the main block
            # (all previous ``` are the latex block inside the template)
            last_backtick_pos = positions[-1]

            # Extract the content
            template_content = content[actual_content_start:actual_content_start + last_backtick_pos]

            # Remove leading newline if present
            template_content = template_content.lstrip("\n")

            self._prompt_cache = template_content
            return self._prompt_cache

        except Exception as e:
            print(f"Error loading prompt file: {e}")
            self._prompt_cache = self._get_fallback_prompt()
            return self._prompt_cache

    def _get_fallback_prompt(self) -> str:
        """Fallback prompt if resumen.md is not found"""
        return """Sos un asistente académico experto. Creá un resumen extenso en LaTeX basado en la transcripción de clase.

## Transcripción de clase:
[PEGAR TRANSCRIPCIÓN AQUÍ]

## Material bibliográfico:
[PEGAR TEXTO DEL LIBRO/APUNTE O INDICAR QUE LO SUBISTE COMO ARCHIVO]

Generá un archivo LaTeX completo con:
- Estructura académica formal
- Mínimo 10 páginas de contenido
- Fórmulas matemáticas en LaTeX
- Tablas y diagramas cuando corresponda
"""

    def _load_latex_preamble(self) -> str:
        """Extract the LaTeX preamble from resumen.md"""
        if self._latex_preamble_cache:
            return self._latex_preamble_cache

        try:
            file_path = self.PROMPT_FILE_PATH.resolve()

            if not file_path.exists():
                return self._get_default_preamble()

            content = file_path.read_text(encoding="utf-8")

            # Extract LaTeX code block in the template
            match = re.search(
                r"```latex\s*\n([\s\S]*?)\n```",
                content
            )

            if match:
                self._latex_preamble_cache = match.group(1).strip()
            else:
                self._latex_preamble_cache = self._get_default_preamble()

            return self._latex_preamble_cache

        except Exception as e:
            print(f"Error loading LaTeX preamble: {e}")
            return self._get_default_preamble()

    def _get_default_preamble(self) -> str:
        """Default LaTeX preamble"""
        return r"""\documentclass[11pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[spanish,provide=*]{babel}
\usepackage{amsmath,amssymb}
\usepackage{geometry}
\usepackage{graphicx}
\usepackage{tikz}
\usetikzlibrary{arrows.meta,positioning,shapes.geometric,calc}
\usepackage{booktabs}
\usepackage{enumitem}
\usepackage{fancyhdr}
\usepackage{titlesec}
\usepackage{tcolorbox}
\usepackage{array}
\usepackage{multirow}

\geometry{margin=2.5cm}
\pagestyle{fancy}
\fancyhf{}
\fancyhead[L]{[MATERIA] - CBC}
\fancyhead[R]{Clase [N]}
\fancyfoot[C]{\thepage}

% Cajas para destacar contenido
\newtcolorbox{definicion}[1][]{
    colback=blue!5!white,
    colframe=blue!75!black,
    fonttitle=\bfseries,
    title=#1
}

\newtcolorbox{importante}[1][]{
    colback=red!5!white,
    colframe=red!75!black,
    fonttitle=\bfseries,
    title=#1
}

\newtcolorbox{ejemplo}[1][]{
    colback=green!5!white,
    colframe=green!50!black,
    fonttitle=\bfseries,
    title=#1
}
"""

    def get_latex_summary_prompt(
        self,
        transcription: str,
        materia: str = "Economía",
        bibliographic_text: Optional[str] = None,
        class_number: Optional[int] = None
    ) -> str:
        """
        Generate the complete prompt for LaTeX academic summary based on resumen.md template.

        Args:
            transcription: The class transcription text
            materia: Subject name (default: "Economía")
            bibliographic_text: Optional supporting text from books/notes
            class_number: Optional class number for header

        Returns:
            Complete prompt string ready to send to AI
        """
        template = self._load_prompt_template()

        # CRITICAL: Prepend explicit instructions to force direct LaTeX generation
        # (This doesn't modify resumen.md, just adds context before it)
        explicit_instructions = """CRITICAL: Tu respuesta debe ser ÚNICAMENTE código LaTeX.

INSTRUCCIONES OBLIGATORIAS:
1. NO incluyas explicaciones previas
2. NO describas lo que vas a hacer
3. Comienza INMEDIATAMENTE con \\documentclass
4. Tu respuesta debe ser SOLO el código LaTeX fuente
5. Termina con \\end{document}

---

"""

        prompt = explicit_instructions + template

        # Replace placeholders
        prompt = prompt.replace("[MATERIA]", materia)

        # Insert transcription
        if "[PEGAR TRANSCRIPCIÓN AQUÍ]" in prompt:
            prompt = prompt.replace("[PEGAR TRANSCRIPCIÓN AQUÍ]", transcription)
        else:
            prompt += f"\n\n## Transcripción de clase:\n{transcription}"

        # Insert bibliographic material
        bib_text = bibliographic_text or "No se proporcionó material bibliográfico adicional."
        if "[PEGAR TEXTO DEL LIBRO/APUNTE O INDICAR QUE LO SUBISTE COMO ARCHIVO]" in prompt:
            prompt = prompt.replace(
                "[PEGAR TEXTO DEL LIBRO/APUNTE O INDICAR QUE LO SUBISTE COMO ARCHIVO]",
                bib_text
            )
        else:
            prompt += f"\n\n## Material bibliográfico:\n{bib_text}"

        # Add class number if provided
        if class_number is not None:
            prompt = prompt.replace("[N]", str(class_number))

        return prompt

    def get_latex_preamble(
        self,
        materia: str = "Economía",
        class_number: Optional[int] = None
    ) -> str:
        """
        Get the LaTeX preamble with placeholders replaced.

        Args:
            materia: Subject name
            class_number: Optional class number

        Returns:
            Complete LaTeX preamble as string
        """
        preamble = self._load_latex_preamble()

        # Replace placeholders
        preamble = preamble.replace("[MATERIA]", materia)
        if class_number is not None:
            preamble = preamble.replace("[N]", str(class_number))

        return preamble

    def get_latex_fix_prompt(self, latex_code: str, error_log: str) -> str:
        """Get prompt for fixing broken LaTeX code"""
        return f"""I have a LaTeX file that failed to compile. Please fix the code.

COMPILER ERROR LOG:
{error_log[-3000:]}

BROKEN LATEX CODE:
{latex_code}

INSTRUCTIONS:
1. Analyze the error log to find the specific syntax error.
2. Fix the LaTeX code.
3. Return ONLY the full corrected LaTeX code.
4. Do not include markdown blocks or explanations.
5. Start immediately with \\documentclass.
6. Ensure all braces {{}} are properly balanced.
7. Ensure all environments \\begin{{...}} have matching \\end{{...}}.
8. Ensure all packages are properly declared.
"""

    def extract_latex_from_response(self, response: str) -> Optional[str]:
        """
        Extract clean LaTeX code from AI response.

        Handles cases where AI wraps LaTeX in ```latex...``` blocks.
        """
        if not response:
            return None

        # Try to find content inside ```latex ... ``` blocks
        code_block_pattern = r"```(?:latex|tex)?\s*([\s\S]*?)\s*```"
        match = re.search(code_block_pattern, response, re.IGNORECASE)

        if match:
            latex = match.group(1).strip()
        else:
            latex = response.strip()

        # Verify it looks like LaTeX
        if "\\documentclass" not in latex:
            return None

        # Clean up: remove anything before \documentclass
        start_idx = latex.find("\\documentclass")
        latex = latex[start_idx:]

        # Clean up: remove anything after \end{document}
        if "\\end{document}" in latex:
            end_idx = latex.rfind("\\end{document}")
            latex = latex[:end_idx + len("\\end{document}")]

        return latex.strip()


# Singleton instance for easy import
prompt_manager = PromptManager()
