"""
H5P Content Generator for Breakpilot Units
==========================================
Generates H5P-compatible content structures from unit definitions.

Supported H5P content types:
- H5P.DragQuestion (Drag and Drop)
- H5P.Blanks (Fill in the Blanks)
- H5P.MultiChoice (Multiple Choice)
- H5P.ImageHotspots (Interactive Images)
"""

import json
import uuid
from dataclasses import dataclass, field
from typing import Any, Optional
from pathlib import Path


@dataclass
class H5PContent:
    """Represents an H5P content package"""
    content_type: str
    title: str
    content: dict
    metadata: dict = field(default_factory=dict)

    def to_json(self) -> str:
        return json.dumps({
            "contentType": self.content_type,
            "title": self.title,
            "content": self.content,
            "metadata": self.metadata
        }, indent=2, ensure_ascii=False)

    def to_h5p_structure(self) -> dict:
        """Generate H5P-compatible structure for export"""
        return {
            "h5p": {
                "mainLibrary": self.content_type,
                "title": self.title,
                "language": "de",
                "embedTypes": ["div"],
                "license": "U",
                "preloadedDependencies": self._get_dependencies()
            },
            "content": self.content
        }

    def _get_dependencies(self) -> list:
        """Get required H5P libraries for content type"""
        deps = {
            "H5P.DragQuestion": [
                {"machineName": "H5P.DragQuestion", "majorVersion": 1, "minorVersion": 14}
            ],
            "H5P.Blanks": [
                {"machineName": "H5P.Blanks", "majorVersion": 1, "minorVersion": 14}
            ],
            "H5P.MultiChoice": [
                {"machineName": "H5P.MultiChoice", "majorVersion": 1, "minorVersion": 16}
            ],
            "H5P.ImageHotspots": [
                {"machineName": "H5P.ImageHotspots", "majorVersion": 1, "minorVersion": 10}
            ]
        }
        return deps.get(self.content_type, [])


class H5PGenerator:
    """Generates H5P content from unit definitions"""

    def __init__(self, locale: str = "de-DE"):
        self.locale = locale

    def generate_from_unit(self, unit: dict) -> list[H5PContent]:
        """
        Generate all H5P content items from a unit definition.

        Args:
            unit: Unit definition dictionary

        Returns:
            List of H5PContent objects
        """
        contents = []

        # Generate drag and drop from stops/vocab
        drag_drop = self._generate_drag_drop(unit)
        if drag_drop:
            contents.append(drag_drop)

        # Generate fill in blanks from concepts
        blanks = self._generate_fill_blanks(unit)
        if blanks:
            contents.append(blanks)

        # Generate multiple choice from pre/post check questions
        mc_items = self._generate_multiple_choice(unit)
        contents.extend(mc_items)

        return contents

    def _get_localized(self, obj: Optional[dict], key: str, default: str = "") -> str:
        """Get localized string from object"""
        if not obj:
            return default
        if isinstance(obj, str):
            return obj
        if isinstance(obj, dict):
            # Try locale-specific key
            if self.locale in obj:
                return obj[self.locale]
            # Try without hyphen (de_DE vs de-DE)
            alt_locale = self.locale.replace("-", "_")
            if alt_locale in obj:
                return obj[alt_locale]
            # Fallback to first available
            if obj:
                return next(iter(obj.values()))
        return default

    def _generate_drag_drop(self, unit: dict) -> Optional[H5PContent]:
        """
        Generate Drag and Drop content from unit vocabulary.
        Students drag terms to their definitions.
        """
        stops = unit.get("stops", [])
        if not stops:
            return None

        # Collect all vocabulary items
        vocab_items = []
        for stop in stops:
            label = self._get_localized(stop.get("label"), self.locale)
            vocab = stop.get("vocab", [])
            for v in vocab:
                term = self._get_localized(v.get("term"), self.locale)
                hint = self._get_localized(v.get("hint"), self.locale)
                if term and hint:
                    vocab_items.append({
                        "term": term,
                        "definition": hint,
                        "stop": label
                    })

        if len(vocab_items) < 2:
            return None

        # Build H5P.DragQuestion content
        drop_zones = []
        draggables = []

        for i, item in enumerate(vocab_items[:8]):  # Limit to 8 items
            # Drop zone for definition
            drop_zones.append({
                "x": 10,
                "y": 10 + i * 12,
                "width": 35,
                "height": 10,
                "correctElements": [str(i)],
                "showLabel": True,
                "backgroundOpacity": 100,
                "tipsAndFeedback": {
                    "tip": f"Ziehe den passenden Begriff hierher"
                },
                "label": f"<p>{item['definition']}</p>"
            })

            # Draggable term
            draggables.append({
                "x": 60,
                "y": 10 + i * 12,
                "width": 30,
                "height": 8,
                "dropZones": [str(i)],
                "type": {
                    "library": "H5P.AdvancedText 1.1",
                    "params": {
                        "text": f"<p>{item['term']}</p>"
                    }
                },
                "multiple": False
            })

        unit_title = self._get_localized(unit.get("title"), self.locale, unit.get("unit_id", "Unit"))

        content = {
            "scoreShow": "Ergebnis anzeigen",
            "tryAgain": "Nochmal versuchen",
            "checkAnswer": "Antworten pruefen",
            "submitAnswers": "Abgeben",
            "behaviour": {
                "enableRetry": True,
                "enableCheckButton": True,
                "showSolutionsRequiresInput": True,
                "singlePoint": False,
                "applyPenalties": False,
                "enableScoreExplanation": True,
                "dropZoneHighlighting": "dragging",
                "autoAlignSpacing": 2,
                "enableFullScreen": False
            },
            "question": {
                "settings": {
                    "size": {
                        "width": 620,
                        "height": 400
                    }
                },
                "task": {
                    "elements": draggables,
                    "dropZones": drop_zones
                }
            },
            "overallFeedback": [
                {"from": 0, "to": 50, "feedback": "Versuche es nochmal!"},
                {"from": 51, "to": 80, "feedback": "Gut gemacht!"},
                {"from": 81, "to": 100, "feedback": "Ausgezeichnet!"}
            ]
        }

        return H5PContent(
            content_type="H5P.DragQuestion",
            title=f"{unit_title} - Begriffe zuordnen",
            content=content,
            metadata={
                "unit_id": unit.get("unit_id"),
                "generated_from": "vocabulary"
            }
        )

    def _generate_fill_blanks(self, unit: dict) -> Optional[H5PContent]:
        """
        Generate Fill in the Blanks from concept "why" explanations.
        Key terms become blanks.
        """
        stops = unit.get("stops", [])
        if not stops:
            return None

        sentences = []
        for stop in stops:
            concept = stop.get("concept", {})
            why = self._get_localized(concept.get("why"), self.locale)
            vocab = stop.get("vocab", [])

            if not why or not vocab:
                continue

            # Find terms to blank out
            sentence = why
            for v in vocab:
                term = self._get_localized(v.get("term"), self.locale)
                if term and term.lower() in sentence.lower():
                    # Replace term with blank (H5P format: *term*)
                    import re
                    pattern = re.compile(re.escape(term), re.IGNORECASE)
                    sentence = pattern.sub(f"*{term}*", sentence, count=1)
                    break

            if "*" in sentence:
                sentences.append(sentence)

        if not sentences:
            return None

        unit_title = self._get_localized(unit.get("title"), self.locale, unit.get("unit_id", "Unit"))

        content = {
            "text": "<p>" + "</p><p>".join(sentences) + "</p>",
            "overallFeedback": [
                {"from": 0, "to": 50, "feedback": "Versuche es nochmal!"},
                {"from": 51, "to": 80, "feedback": "Gut gemacht!"},
                {"from": 81, "to": 100, "feedback": "Ausgezeichnet!"}
            ],
            "showSolutions": "Loesung anzeigen",
            "tryAgain": "Nochmal versuchen",
            "checkAnswer": "Pruefen",
            "submitAnswer": "Abgeben",
            "notFilledOut": "Bitte fuellen Sie alle Luecken aus.",
            "answerIsCorrect": "':ans' ist richtig!",
            "answerIsWrong": "':ans' ist falsch.",
            "answeredCorrectly": "Richtig!",
            "answeredIncorrectly": "Falsch.",
            "behaviour": {
                "enableRetry": True,
                "enableSolutionsButton": True,
                "enableCheckButton": True,
                "caseSensitive": False,
                "autoCheck": False,
                "separateLines": False
            }
        }

        return H5PContent(
            content_type="H5P.Blanks",
            title=f"{unit_title} - Lueckentext",
            content=content,
            metadata={
                "unit_id": unit.get("unit_id"),
                "generated_from": "concepts"
            }
        )

    def _generate_multiple_choice(self, unit: dict) -> list[H5PContent]:
        """
        Generate Multiple Choice questions from precheck/postcheck.
        """
        contents = []

        # Load precheck questions if referenced
        precheck = unit.get("precheck", {})
        postcheck = unit.get("postcheck", {})

        # For now, generate from stops' concepts as misconception-targeted questions
        stops = unit.get("stops", [])
        unit_title = self._get_localized(unit.get("title"), self.locale, unit.get("unit_id", "Unit"))

        for i, stop in enumerate(stops):
            concept = stop.get("concept", {})
            misconception = self._get_localized(concept.get("common_misconception"), self.locale)
            why = self._get_localized(concept.get("why"), self.locale)
            label = self._get_localized(stop.get("label"), self.locale)

            if not misconception or not why:
                continue

            # Create a question about the concept
            content = {
                "question": f"<p>Was ist richtig ueber {label}?</p>",
                "answers": [
                    {
                        "correct": True,
                        "text": f"<p>{why}</p>",
                        "tpiAndFeedback": {
                            "chosenFeedback": "<p>Richtig!</p>",
                            "notChosenFeedback": ""
                        }
                    },
                    {
                        "correct": False,
                        "text": f"<p>{misconception}</p>",
                        "tipsAndFeedback": {
                            "chosenFeedback": f"<p>Das ist ein haeufiger Irrtum!</p>",
                            "notChosenFeedback": ""
                        }
                    }
                ],
                "overallFeedback": [
                    {"from": 0, "to": 50, "feedback": "Versuche es nochmal!"},
                    {"from": 51, "to": 100, "feedback": "Sehr gut!"}
                ],
                "behaviour": {
                    "enableRetry": True,
                    "enableSolutionsButton": True,
                    "enableCheckButton": True,
                    "type": "auto",
                    "singlePoint": True,
                    "randomAnswers": True,
                    "showSolutionsRequiresInput": True,
                    "confirmCheckDialog": False,
                    "confirmRetryDialog": False,
                    "autoCheck": False,
                    "passPercentage": 100
                },
                "UI": {
                    "checkAnswerButton": "Pruefen",
                    "submitAnswerButton": "Abgeben",
                    "showSolutionButton": "Loesung zeigen",
                    "tryAgainButton": "Nochmal",
                    "tipsLabel": "Tipp anzeigen",
                    "scoreBarLabel": "Du hast :num von :total Punkten",
                    "tipAvailable": "Tipp verfuegbar",
                    "feedbackAvailable": "Feedback verfuegbar",
                    "readFeedback": "Feedback lesen",
                    "wrongAnswer": "Falsche Antwort",
                    "correctAnswer": "Richtige Antwort"
                }
            }

            contents.append(H5PContent(
                content_type="H5P.MultiChoice",
                title=f"{unit_title} - {label} Quiz",
                content=content,
                metadata={
                    "unit_id": unit.get("unit_id"),
                    "stop_id": stop.get("stop_id"),
                    "generated_from": "misconception"
                }
            ))

        return contents


def generate_h5p_for_unit(unit_definition: dict, locale: str = "de-DE") -> list[dict]:
    """
    Main function to generate H5P content for a unit.

    Args:
        unit_definition: The unit JSON definition
        locale: Target locale for content

    Returns:
        List of H5P content structures ready for export
    """
    generator = H5PGenerator(locale=locale)
    contents = generator.generate_from_unit(unit_definition)

    return [c.to_h5p_structure() for c in contents]


def generate_h5p_manifest(contents: list[H5PContent], unit_id: str) -> dict:
    """
    Generate a manifest listing all H5P content for a unit.
    """
    return {
        "unit_id": unit_id,
        "generated_at": __import__("datetime").datetime.utcnow().isoformat(),
        "content_count": len(contents),
        "items": [
            {
                "id": str(uuid.uuid4()),
                "type": c.content_type,
                "title": c.title,
                "metadata": c.metadata
            }
            for c in contents
        ]
    }
