import json
import pathlib
from typing import Dict, Any
import logging
from jinja2 import Template, Environment, meta
from .synthia import סינתיה

logger = logging.getLogger(__name__)


class פלמינגו:
    """
    פלמינגו
    --------
    רנדרר צד-שרת בסיוע LLM עם Jinja2.
    """

    def __init__(self, מפתח_אבטחה: str, תיקיית_תבניות: str = "templates", **kwargs):
        if "security_key" in kwargs:
            מפתח_אבטחה = kwargs["security_key"]
        if "templates_dir" in kwargs:
            תיקיית_תבניות = kwargs["templates_dir"]

        self.מודל = סינתיה(מפתח_אבטחה)
        self.llm = self.מודל  # תאימות אנגלית
        self.תיקיית_תבניות = pathlib.Path(תיקיית_תבניות)
        self.templates_dir = self.תיקיית_תבניות  # תאימות אנגלית

    # ---------------------------------------------------------
    # API ציבורי
    # ---------------------------------------------------------

    def רנדר(self, שם_תבנית: str, הקשר: Dict[str, Any], כוונה: str) -> str:
        """
        חילוץ הקשר מובנה מרשומה גולמית ורנדר עם Jinja2.
        """
        תוכן_תבנית = self._טען_תבנית(שם_תבנית)

        if not הקשר or all(v is None for v in הקשר.values()):
            return self._רנדר_גיניה(תוכן_תבנית, {})

        הקשר_מובנה = self._חלץ_הקשר(
            תבנית=תוכן_תבנית,
            הקשר_גולמי=הקשר,
            כוונה=כוונה,
        )

        return self._רנדר_גיניה(תוכן_תבנית, הקשר_מובנה)

    def render(self, template_name: str, context: Dict[str, Any], intent: str) -> str:
        return self.רנדר(template_name, context, intent)

    def רנדר_ישיר(
        self,
        שם_תבנית: str,
        הקשר: Dict[str, Any],
        כוונה: str | None = None,
    ) -> str:
        """
        רנדר ישיר ללא חילוץ LLM.
        """
        תוכן_תבנית = self._טען_תבנית(שם_תבנית)
        return self._רנדר_גיניה(תוכן_תבנית, הקשר)

    def render_direct(
        self,
        template_name: str,
        context: Dict[str, Any],
        intent: str | None = None,
    ) -> str:
        return self.רנדר_ישיר(template_name, context, intent)

    # ---------------------------------------------------------
    # עזר פנימי
    # ---------------------------------------------------------

    def _טען_תבנית(self, שם_תבנית: str) -> str:
        נתיב = self.תיקיית_תבניות / שם_תבנית
        if not נתיב.exists():
            raise FileNotFoundError(f"Template not found: {שם_תבנית}")
        return נתיב.read_text(encoding="utf-8")

    def _חלץ_הקשר(self, תבנית: str, הקשר_גולמי: Dict, כוונה: str) -> Dict[str, Any]:
        הקשר_כמחרוזת = self._המר_הקשר_למחרוזת(הקשר_גולמי)
        משתנים = self._חלץ_משתני_תבנית(תבנית)

        הנחיה = f"""
You are Flamingo, a context extractor for Jinja2 templates.

TASK: Analyze the Jinja2 template variables and extract/format a JSON context object that matches what the template expects.

RULES:
1. Look at the template's Jinja2 variables: {משתנים}
2. Extract corresponding data from the raw context
3. Format data to match template structure exactly
4. Return ONLY valid JSON - no explanations, no markdown
5. If raw context has dict/list data, preserve the structure
6. If raw context has status info, include it

--------------------
INTENT: {כוונה}

--------------------
RAW CONTEXT:
{הקשר_כמחרוזת}

--------------------
Return ONLY the JSON context object:
"""

        try:
            תגובה = self.מודל.השלם(הנחיה)

            תגובה = תגובה.strip()
            if תגובה.startswith("```json"):
                תגובה = תגובה[7:]
            if תגובה.startswith("```"):
                תגובה = תגובה[3:]
            if תגובה.endswith("```"):
                תגובה = תגובה[:-3]
            תגובה = תגובה.strip()

            try:
                הקשר_מובנה = json.loads(תגובה)
                return הקשר_מובנה
            except json.JSONDecodeError:
                logger.exception("[Flamingo] JSON parse error")
                logger.debug("[Flamingo] Response was: %s", תגובה)
                return הקשר_גולמי
        except Exception:
            logger.exception("[Flamingo] LLM call failed")
            logger.warning("[Flamingo] Falling back to raw context")
            return הקשר_גולמי
            תגובה = תגובה[3:]

    def _חלץ_משתני_תבנית(self, תבנית: str) -> str:
        try:
            סביבה = Environment()
            עץ = סביבה.parse(תבנית)
            משתנים = meta.find_undeclared_variables(עץ)
            return ", ".join(sorted(משתנים))
        except Exception:
            logger.exception("[Flamingo] Error extracting variables")
            return "Unable to extract variables"

    def _המר_הקשר_למחרוזת(self, הקשר: Dict[str, Any]) -> str:
        שורות = []
        for מפתח, ערך in הקשר.items():
            if ערך is None:
                שורות.append(f"{מפתח}: None")
            elif isinstance(ערך, (str, int, float, bool)):
                שורות.append(f"{מפתח}: {ערך}")
            elif isinstance(ערך, (list, dict)):
                שורות.append(f"{מפתח}: {json.dumps(ערך, indent=2)}")
            else:
                שורות.append(f"{מפתח}: {repr(ערך)}")
        return "\n".join(שורות)

    def _רנדר_גיניה(self, תוכן_תבנית: str, הקשר: Dict[str, Any]) -> str:
        try:
            תבנית = Template(תוכן_תבנית)
            מרונדר = תבנית.render(**הקשר)

            if not מרונדר.strip().lower().startswith("<!doctype"):
                return "<!DOCTYPE html>\n" + מרונדר

            return מרונדר
        except Exception:
            logger.exception("[Flamingo] Jinja2 render error")
            return תוכן_תבנית


# תאימות שמות
Flamingo = פלמינגו
