# teacher/utils/ai.py

import time
import json
from functools import wraps
import re

# Gemini key now comes from the dynamic credential store (master admin
# panel → Credentials), resolved lazily on each call.
from core.utils.gemini import model


def generate_questions_with_ai(
    subject: str,
    standard: str,
    difficulty: str,
    topic: str,
    num_questions: int = 5,
    question_type: str = "mixed",
    retries: int = 3,
):
    """
    Generate questions using AI based on subject, standard, difficulty, and topic.

    Args:
        subject: Subject name (e.g., "Mathematics", "Science", "English")
        standard: Class/grade (e.g., "10th", "8th", "12th")
        difficulty: "easy", "medium", "hard"
        topic: Specific topic (e.g., "Algebra", "Photosynthesis", "Tenses")
        num_questions: Number of questions to generate (default: 5)
        question_type: "mcq", "descriptive", "mixed" (default: "mixed")
        retries: Number of retry attempts on failure

    Returns:
        List of question dictionaries with question_text, marks, and optional options for MCQ
    """

    difficulty_map = {
        "easy": "basic understanding and simple recall",
        "medium": "application and moderate problem-solving",
        "hard": "advanced critical thinking and complex problem-solving",
    }

    difficulty_desc = difficulty_map.get(difficulty.lower(), "appropriate level")

    if question_type == "mcq":
        question_format = """
        For each question, provide:
        - question_text: The question with 4 options (A, B, C, D)
        - options: List of 4 options
        - correct_answer: The correct option letter (A, B, C, or D)
        - marks: 1 mark per question
        """
    elif question_type == "descriptive":
        question_format = """
        For each question, provide:
        - question_text: The descriptive question
        - marks: 5-10 marks depending on complexity
        """
    else:  # mixed
        question_format = """
        Mix of question types:
        - 2-3 MCQ questions (1 mark each) with 4 options
        - 2-3 descriptive questions (5-10 marks each)
        - 1-2 short answer questions (2-3 marks each)
        """

    prompt = f"""
    You are an expert teacher creating questions for {standard} standard {subject} students.
    
    Generate {num_questions} questions on the topic: "{topic}"
    Difficulty level: {difficulty_desc}
    
    Requirements:
    - Questions should be age-appropriate for {standard} grade students
    - Align with curriculum standards
    - Cover different aspects of the topic
    - Include a mix of conceptual and application-based questions
    
    {question_format}
    
    Return ONLY a JSON array with the following structure:
    [
        {{
            "question_text": "What is photosynthesis?",
            "question_type": "descriptive",
            "marks": 10,
            "expected_answer": "The process by which plants convert light energy into chemical energy...",
            "bloom_taxonomy_level": "understanding"
        }},
        {{
            "question_text": "Which of the following is a renewable resource?",
            "question_type": "mcq",
            "options": ["Coal", "Natural Gas", "Solar Energy", "Petroleum"],
            "correct_answer": "C",
            "marks": 1,
            "bloom_taxonomy_level": "remembering"
        }}
    ]
    
    For descriptive questions, include an expected_answer.
    For MCQ questions, include options array and correct_answer.
    
    Ensure the JSON is valid and properly formatted.
    """

    for attempt in range(retries):
        try:
            response = model.generate_content(prompt)
            response_text = response.text.strip()

            # Extract JSON from response
            if "```json" in response_text:
                response_text = response_text.split("```json")[1].split("```")[0]
            elif "```" in response_text:
                response_text = response_text.split("```")[1].split("```")[0]

            questions = json.loads(response_text)

            # Validate and clean questions
            validated_questions = []
            for q in questions:
                if "question_text" in q and "question_type" in q:
                    # Ensure marks is set
                    if "marks" not in q:
                        q["marks"] = 5 if q["question_type"] == "descriptive" else 1

                    # For MCQ, ensure options exist
                    if q["question_type"] == "mcq" and "options" not in q:
                        q["options"] = ["Option A", "Option B", "Option C", "Option D"]

                    validated_questions.append(q)

            return validated_questions

        except json.JSONDecodeError as e:
            print(f"JSON decode error (attempt {attempt + 1}): {e}")
            if attempt < retries - 1:
                time.sleep(2)
                continue
            # Return fallback questions
            return _get_fallback_questions(subject, topic, difficulty, num_questions)

        except Exception as e:
            print(f"Error generating questions (attempt {attempt + 1}): {e}")
            if "429" in str(e) and attempt < retries - 1:
                wait_time = 60 * (attempt + 1)
                print(f"Rate limited. Waiting {wait_time}s...")
                time.sleep(wait_time)
            elif attempt < retries - 1:
                time.sleep(2)
            else:
                # Return fallback questions
                return _get_fallback_questions(
                    subject, topic, difficulty, num_questions
                )

    return _get_fallback_questions(subject, topic, difficulty, num_questions)


def _get_fallback_questions(subject, topic, difficulty, num_questions):
    """Generate fallback template questions if AI fails"""
    fallback_questions = []

    templates = {
        "easy": [
            f"What is {topic}? Explain in your own words.",
            f"List the main features of {topic}.",
            f"Define {topic} and give one example.",
            f"What are the key components of {topic}?",
            f"Describe the importance of {topic} in {subject}.",
        ],
        "medium": [
            f"Explain the working principle of {topic} with examples.",
            f"Compare and contrast different aspects of {topic}.",
            f"What are the advantages and disadvantages of {topic}?",
            f"Describe the process of {topic} step by step.",
            f"Analyze the role of {topic} in real-world applications.",
        ],
        "hard": [
            f"Critically analyze the concept of {topic} and its implications.",
            f"Evaluate the effectiveness of {topic} in solving complex problems.",
            f"Design a solution using {topic} for a given scenario.",
            f"Discuss the challenges and future scope of {topic}.",
            f"Prove or disprove a hypothesis related to {topic} with reasoning.",
        ],
    }

    selected_templates = templates.get(difficulty, templates["medium"])

    for i in range(min(num_questions, len(selected_templates))):
        fallback_questions.append(
            {
                "question_text": selected_templates[i],
                "question_type": "descriptive",
                "marks": (
                    10 if difficulty == "hard" else (5 if difficulty == "medium" else 3)
                ),
                "expected_answer": f"Student should explain {topic} clearly with relevant examples from {subject}.",
                "bloom_taxonomy_level": (
                    "understanding" if difficulty == "easy" else "analysis"
                ),
            }
        )

    # If we need more questions, repeat with variations
    while len(fallback_questions) < num_questions:
        fallback_questions.append(
            {
                "question_text": f"Explain the concept of {topic} and its application in {subject}.",
                "question_type": "descriptive",
                "marks": 5,
                "expected_answer": f"Comprehensive explanation of {topic} with relevant examples.",
                "bloom_taxonomy_level": "application",
            }
        )

    return fallback_questions


def generate_questions_batch(
    subject: str,
    standard: str,
    difficulty: str,
    topics: list,
    questions_per_topic: int = 3,
    retries: int = 3,
):
    """
    Generate questions for multiple topics in one API call.

    Args:
        subject: Subject name
        standard: Class/grade
        difficulty: "easy", "medium", "hard"
        topics: List of topics
        questions_per_topic: Number of questions per topic
        retries: Number of retry attempts

    Returns:
        Dictionary with topics as keys and list of questions as values
    """

    difficulty_map = {
        "easy": "basic understanding",
        "medium": "application and moderate problem-solving",
        "hard": "advanced critical thinking",
    }

    prompt = f"""
    You are an expert teacher creating questions for {standard} standard {subject} students.
    
    Generate {questions_per_topic} questions for EACH of these topics:
    {json.dumps(topics)}
    
    Overall difficulty level: {difficulty_map.get(difficulty, 'appropriate level')}
    
    Return a JSON object where each key is a topic and value is an array of questions:
    {{
        "topic1": [
            {{
                "question_text": "Question text",
                "question_type": "descriptive",
                "marks": 5,
                "expected_answer": "Expected answer"
            }}
        ],
        "topic2": [...]
    }}
    
    Mix question types where appropriate. For MCQ, include options and correct_answer.
    Ensure the JSON is valid.
    """

    for attempt in range(retries):
        try:
            response = model.generate_content(prompt)
            response_text = response.text.strip()

            # Extract JSON
            if "```json" in response_text:
                response_text = response_text.split("```json")[1].split("```")[0]
            elif "```" in response_text:
                response_text = response_text.split("```")[1].split("```")[0]

            result = json.loads(response_text)
            return result

        except Exception as e:
            print(f"Error generating batch questions (attempt {attempt + 1}): {e}")
            if attempt < retries - 1:
                time.sleep(2)
            else:
                # Return simple structure
                result = {}
                for topic in topics:
                    result[topic] = _get_fallback_questions(
                        subject, topic, difficulty, questions_per_topic
                    )
                return result

    return {}
