from django.shortcuts import render, redirect, get_object_or_404
from django.core.files.storage import FileSystemStorage
from django.contrib import messages
import pandas as pd
from .models import QuestionBank,InputSuggestion,InputSuggestionImage, InputSuggestionDocument, Area, PartName, ChapterName,TopicName, QuoteIdiomPhrase
from django.db.models import Max, Count, Value, Q
from .forms import UploadFileForm, InputSuggestionForm, QuestionFilterForm
import os
from datetime import datetime
from docx import Document
from docx.shared import Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
from PIL import Image as PILImage
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from django.http import FileResponse, HttpResponse
from PIL import Image as PILImage
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required
import json
from django.utils import timezone
from datetime import timedelta
from django.db import transaction
from accounts.models import User
import csv
from io import BytesIO
from django.http import HttpResponse
from .models import Report
from django.template.loader import render_to_string
from django.db.models.functions import Concat
from django.contrib.auth import get_user_model
from django.conf import settings
from .document_generator import generate_filtered_questions_document  # Assuming you have a separate file for document generation
User = get_user_model()
import logging
logger = logging.getLogger(__name__)
import sys
sys.stdout.reconfigure(encoding='utf-8')

from django.http import JsonResponse
# ************************* Generate Test Word file End *********************************************

# Clean text utility
def clean_text(text):
    """Utility function to clean and format text by removing extra newlines and spaces."""
    if not text:
        return ''
    # Strip leading and trailing spaces
    text = text.strip()
    # Replace multiple newlines or newline + spaces with a single space
    text = re.sub(r'\s*\n\s*', ' ', text)
    # Ensure no multiple spaces remain after replacements
    text = re.sub(r'\s+', ' ', text)
    return text

# Generate Word file
def generate_questions(request):
    try:
        buffer = BytesIO()  # In-memory buffer to store the document
        today = datetime.today().strftime('%Y-%m-%d')
        file_name = f'all_questions_{today}.docx'
        document = Document()

        for question in QuestionBank.objects.all():
            if question.question_sub_type == 'simple_type':
                add_simple_type(question, document)
            elif question.question_sub_type == 'r_and_a_type':
                add_r_and_a_type(question, document)
            elif question.question_sub_type == 'list_type_1':
                add_list_type_1(question, document)
            elif question.question_sub_type == 'list_type_2':
                add_list_type_2(question, document)
            
            # Add a space between questions
            document.add_paragraph()

        # Save the document to the in-memory file object
        document.save(buffer)
        buffer.seek(0)

        # Return the generated file as a downloadable response
        response = FileResponse(buffer, as_attachment=True, filename=file_name)
        response['Content-Disposition'] = f'attachment; filename={file_name}'
        return response

    except Exception as e:
        return HttpResponse(f"An error occurred: {str(e)}", status=500)

# Add question types
def add_simple_type(question, document):
    """Add simple type question to the document."""
    table = document.add_table(rows=1, cols=2)
    table.style = 'Table Grid'
    
    # Left column: Question and options
    left_col = table.cell(0, 0)
    left_col.text = f"({question.question_number}). {clean_text(question.question_part)}"
    add_options(left_col, question)

    # Right column: Solution, marks, etc.
    right_col = table.cell(0, 1)
    add_question_details(right_col, question)

def add_r_and_a_type(question, document):
    """Add reason and assertion type question to the document."""
    table = document.add_table(rows=1, cols=2)
    table.style = 'Table Grid'

    # Left column: Assertion and reason
    left_col = table.cell(0, 0)
    left_col.text = f"({question.question_number}). {clean_text(question.question_part_first)}"
    left_col.text += f"\n{clean_text(question.assertion)}"
    left_col.text += f"\n{clean_text(question.reason)}"
    left_col.text += f"\n{clean_text(question.question_part_third)}"
    add_options(left_col, question)

    # Right column: Solution, marks, etc.
    right_col = table.cell(0, 1)
    add_question_details(right_col, question)

def add_list_type_1(question, document):
    """Add list type 1 question to the document."""
    table = document.add_table(rows=1, cols=2)
    table.style = 'Table Grid'

    # Left column: Question and list options
    left_col = table.cell(0, 0)
    left_col.text = f"({question.question_number}). {clean_text(question.question_part_first)}"
    
    for i in range(1, 9):  # 8 list rows
        list_row = getattr(question, f'list_1_row{i}', None)
        if list_row:
            left_col.text += f"\n{i}. {clean_text(list_row)}"
    
    if question.question_part_third:
        left_col.text += f"\n\n{clean_text(question.question_part_third)}"
    add_options(left_col, question)

    # Right column: Solution, marks, etc.
    right_col = table.cell(0, 1)
    add_question_details(right_col, question)

def add_list_type_2(question, document):
    """Add list type 2 question to the document."""
    table = document.add_table(rows=1, cols=2)
    table.style = 'Table Grid'

    # Left column: Question and list options (2 lists)
    left_col = table.cell(0, 0)
    left_col.text = f"({question.question_number}). {clean_text(question.question_part_first)}"

    # Create another table within the left column for LIST-I and LIST-II
    inner_table = left_col.add_table(rows=1, cols=2)
    inner_table.style = 'Table Grid'
    inner_table.cell(0, 0).text = f"LIST - I ({clean_text(question.list_1_name)})"
    inner_table.cell(0, 1).text = f"LIST - II ({clean_text(question.list_2_name)})"
    
    for i in range(1, 9):
        list_1_item = getattr(question, f'list_1_row{i}', '')
        list_2_item = getattr(question, f'list_2_row{i}', '')
        row = inner_table.add_row().cells
        row[0].text = f"{chr(64+i)}. {clean_text(list_1_item)}"
        row[1].text = f"{i}. {clean_text(list_2_item)}"

    # Right column: Solution, marks, etc.
    right_col = table.cell(0, 1)
    add_question_details(right_col, question)

# Add options to the question
def add_options(cell, question):
    """Add options (A, B, C, D) to a table cell."""
    for opt in ['a', 'b', 'c', 'd']:
        option_text = getattr(question, f'answer_option_{opt}', None)
        if option_text:
            cell.text += f"\n({opt.upper()}) {clean_text(option_text)}"

# Add details like solution, marks, and metadata
def add_question_details(cell, question):
    """Add details like the solution, marks, and metadata with bold headings."""
    # Get a paragraph object to start adding runs with formatting
    paragraph = cell.add_paragraph()

    # Correct Answer
    run = paragraph.add_run('Correct Answer: ')
    run.bold = True
    paragraph.add_run(f"{clean_text(question.correct_answer_choice)}")

    # Solution
    paragraph = cell.add_paragraph()  # Create a new paragraph for each item
    run = paragraph.add_run('Solution: ')
    run.bold = True
    paragraph.add_run(f"{clean_text(question.correct_answer_description)}")

    # Marks
    paragraph = cell.add_paragraph()
    run = paragraph.add_run('Marks: ')
    run.bold = True
    paragraph.add_run(f"{question.marks}")
    
    run = paragraph.add_run('\nNegative Marks: ')
    run.bold = True
    paragraph.add_run(f"{question.negative_marks}")

    # Degree of Difficulty
    paragraph = cell.add_paragraph()
    run = paragraph.add_run('Degree of Difficulty: ')
    run.bold = True
    paragraph.add_run(f"{clean_text(question.degree_of_difficulty)}")

    # Evergreen Index
    paragraph = cell.add_paragraph()
    run = paragraph.add_run('Evergreen Index: ')
    run.bold = True
    paragraph.add_run(f"{question.evergreen_index}")

    # Created At
    created_at_str = question.created_at.strftime('%Y-%m-%d %H:%M:%S')
    paragraph = cell.add_paragraph()
    run = paragraph.add_run('Created At: ')
    run.bold = True
    paragraph.add_run(f"{created_at_str}")

    # Created By
    if question.created_by:
        created_by_str = question.created_by.get_full_name() or question.created_by.username
        paragraph = cell.add_paragraph()
        run = paragraph.add_run('Created By: ')
        run.bold = True
        paragraph.add_run(f"{clean_text(created_by_str)}")


# # ************************* Generate Test Word file End *********************************************


# ************************* Generate Clas Plus Word file Start *********************************************
from django.shortcuts import render, redirect
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required
from django.template.loader import render_to_string
from django.contrib import messages
from .models import Area, Section, PartName, ChapterName, TopicName, SubTopicName, QuestionBank


# *********************** Dynamic Data Fetching Views *********************** #

# Function to dynamically fetch areas based on selected subjects
def get_areas_list(request):
    subject_ids = request.GET.getlist('subject_ids[]')
    if not subject_ids:
        return JsonResponse({'areas': []})  # Return an empty list if no subject IDs are provided
    areas = Area.objects.filter(subject_name__id__in=subject_ids).values('id', 'name')
    return JsonResponse({'areas': list(areas)})

# Function to dynamically fetch sections based on selected areas
def get_sections_list(request):
    area_ids = request.GET.getlist('area_ids[]')
    if not area_ids:
        return JsonResponse({'sections': []})  # Return an empty list if no area IDs are provided
    sections = Section.objects.filter(area__id__in=area_ids).values('id', 'name')
    return JsonResponse({'sections': list(sections)})

# Function to dynamically fetch parts based on selected sections
def get_parts_list(request):
    section_ids = request.GET.getlist('section_ids[]')
    if not section_ids:
        return JsonResponse({'parts': []})  # Return an empty list if no section IDs are provided
    parts = PartName.objects.filter(section__id__in=section_ids).values('id', 'name')
    return JsonResponse({'parts': list(parts)})

# Function to dynamically fetch chapters based on selected parts
def get_chapters_list(request):
    part_ids = request.GET.getlist('part_ids[]')
    if not part_ids:
        return JsonResponse({'chapters': []})  # Return an empty list if no part IDs are provided
    chapters = ChapterName.objects.filter(part__id__in=part_ids).values('id', 'name')
    return JsonResponse({'chapters': list(chapters)})

# Function to dynamically fetch topics based on selected chapters
def get_topics_list(request):
    chapter_ids = request.GET.getlist('chapter_ids[]')
    if not chapter_ids:
        return JsonResponse({'topics': []})  # Return an empty list if no chapter IDs are provided
    topics = TopicName.objects.filter(chapter__id__in=chapter_ids).values('id', 'name')
    return JsonResponse({'topics': list(topics)})

# Function to dynamically fetch subtopics based on selected topics
def get_subtopics_list(request):
    topic_ids = request.GET.getlist('topic_ids[]')
    if not topic_ids:
        return JsonResponse({'subtopics': []})  # Return an empty list if no topic IDs are provided
    subtopics = SubTopicName.objects.filter(topic__id__in=topic_ids).values('id', 'name')
    return JsonResponse({'subtopics': list(subtopics)})


# ************************** Question Filtering ************************** #


# ************************** Question Filtering ************************** #

from django.shortcuts import render, get_object_or_404
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.template.loader import render_to_string
from django.contrib.auth.decorators import login_required
from decouple import config
from openai import OpenAI

from .models import QuestionBank, Area, Section, PartName, ChapterName, TopicName, SubTopicName

# ✅ Initialize OpenAI client
client = OpenAI(api_key=config("OPENAI_API_KEY"))


# views.py

from collections import defaultdict
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from .models import (
    QuestionBank, Area, Section, PartName,
    ChapterName, TopicName, SubTopicName
)

@login_required
def question_filter_view(request):
    """
    Filter questions by hierarchy (Area | Section | Part | Chapter | Topic | Subtopic)
    and group them by base_question_id into English/Hindi pairs.
    """

    # ---------- Dropdown data ----------
    areas = Area.objects.all().order_by("area_SI_Code")
    sections = Section.objects.all().order_by("section_Unit_SI")
    parts = PartName.objects.all().order_by("part_serial")
    chapters = ChapterName.objects.all().order_by("chapter_number")
    topics = TopicName.objects.all().order_by("topic_SI_number")
    subtopics = SubTopicName.objects.all().order_by("sub_topic_SI_Number")

    # ---------- Apply filters ----------
    filters = {
        "area_name__area_SI_Code": request.GET.get("area"),
        "section_name__section_Unit_SI": request.GET.get("section"),
        "part_name__part_serial": request.GET.get("part"),
        "chapter_name__chapter_number": request.GET.get("chapter"),
        "topic_name__topic_SI_number": request.GET.get("topic"),
        "subtopic_name__sub_topic_SI_Number": request.GET.get("subtopic"),
        "created_at__date": request.GET.get("created_at"),
        "question_sub_type": request.GET.get("question_sub_type"),
    }

    # Keep only non-empty values
    filters = {k: v for k, v in filters.items() if v}

    questions = QuestionBank.objects.all().select_related("created_by").prefetch_related(
        "area_name", "section_name", "part_name", "chapter_name", "topic_name", "subtopic_name" 
    )
    if filters:
        questions = questions.filter(**filters) 

    # ---------- Group by base_question_id ----------
    grouped_questions = defaultdict(lambda: {"english": None, "hindi": None})

    for q in questions:
        if not q.base_question_id:
            continue
        if q.language == "e":
            grouped_questions[q.base_question_id]["english"] = q
        elif q.language == "h":
            grouped_questions[q.base_question_id]["hindi"] = q

    # ---------- Context ----------
    context = {
        "grouped_questions": dict(grouped_questions),  # force JSON-serializable
        "areas": areas,
        "sections": sections,
        "parts": parts,
        "chapters": chapters,
        "topics": topics,
        "subtopics": subtopics,
        "question_types": QuestionBank.QUESTION_TYPES,  # ✅ pass all types (incl. statement_type)
    }

    return render(request, "question_bank/question_filter.html", context)


from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import csrf_exempt
from django.template.loader import render_to_string
import traceback

@csrf_exempt
def generate_alternate_question(request):
    if request.method != 'POST':
        return JsonResponse({'status': 'error', 'message': 'Invalid request method'}, status=400)

    question_id = request.POST.get('question_id')
    if not question_id:
        return JsonResponse({'status': 'error', 'message': 'Missing question ID'}, status=400)

    try:
        question = get_object_or_404(QuestionBank, id=question_id)
        subtype = question.question_sub_type

        # ========== Build SOURCE QUESTION STRING ==========
        if subtype == "list_type_2":
            list1 = "\n".join([f"{chr(65+i)}. {item}" for i, item in enumerate(question.list_1_items)])
            list2 = "\n".join([f"{i+1}. {item}" for i, item in enumerate(question.list_2_items)])
            source_text = f"""
List-I:
{list1}

List-II:
{list2}

Options:
a. {question.answer_option_a}
b. {question.answer_option_b}
c. {question.answer_option_c}
d. {question.answer_option_d}

Correct Answer: {question.correct_answer_choice}
Correct Answer Description: {question.correct_answer_description}
"""
        elif subtype == "list_type_1":
            list_items = "\n".join([f"{i+1}. {item}" for i, item in enumerate(question.list_1_items)])
            source_text = f"""
First Part: {question.question_part_first}

List:
{list_items}

Third Part: {question.question_part_third}

Options:
a. {question.answer_option_a}
b. {question.answer_option_b}
c. {question.answer_option_c}
d. {question.answer_option_d}

Correct Answer: {question.correct_answer_choice}
Correct Answer Description: {question.correct_answer_description}
"""
        elif subtype == "r_and_a_type":
            source_text = f"""
Assertion: {question.assertion}
Reason: {question.reason}

Options:
a. {question.answer_option_a}
b. {question.answer_option_b}
c. {question.answer_option_c}
d. {question.answer_option_d}

Correct Answer: {question.correct_answer_choice}
Correct Answer Description: {question.correct_answer_description}
"""
        elif subtype in ["simple_type", "true_and_false_type", "fill_in_the_blank_type"]:
            source_text = f"""
Question: {question.question_part_first}

Options:
a. {question.answer_option_a}
b. {question.answer_option_b}
c. {question.answer_option_c}
d. {question.answer_option_d}

Correct Answer: {question.correct_answer_choice}
Correct Answer Description: {question.correct_answer_description}
"""
        elif subtype == "statement_type":
            stmts = "\n".join([f"Statement {i+1}: {s}" for i, s in enumerate(question.stmt_lines)])
            source_text = f"""
First Part: {question.question_part_first}

{stmts}

Third Part: {question.question_part_third}

Options:
a. {question.answer_option_a}
b. {question.answer_option_b}
c. {question.answer_option_c}
d. {question.answer_option_d}

Correct Answer: {question.correct_answer_choice}
Correct Answer Description: {question.correct_answer_description}
"""
        else:
            return JsonResponse({'status': 'error', 'message': f'Unsupported subtype {subtype}'}, status=400)

        # ========== Instruction ==========
        instruction = {
            "list_type_2": """Create a List Match (List-II) question.
STRICT RULES:
1. Always format List-I as A., B., C., D. items.
2. Always format List-II as 1., 2., 3., 4. items.
3. Options must ONLY contain mapping patterns like:
   a. A-3; B-2; C-5; D-1
   b. A-1; B-4; C-2; D-3
   c. A-2; B-1; C-3; D-5
   d. A-4; B-5; C-1; D-2
4. DO NOT mix mapping patterns inside List-I or List-II.
5. Always include “Correct Answer” and “Correct Answer Description” separately.""",
            "list_type_1": "Generate similar List-I type questions following the same structure...",
            "r_and_a_type": "Generate similar Assertion-Reason type questions...",
            "simple_type": "Generate similar MCQ questions with same structure...",
            "true_and_false_type": "Generate similar True/False type questions...",
            "fill_in_the_blank_type": "Generate similar Fill in the Blank type questions...",
            "statement_type": "Generate similar Statement type questions..."
        }.get(subtype, "")

        # ========== Final Prompt ==========
        bilingual_prompt = f"""
You are an expert UPSC/MPPSC bilingual question creator.

SOURCE QUESTION:
{source_text}

TASK:
1. Generate 4 alternate questions in ENGLISH.
   - Start with:
     ### ENGLISH
   - Each question must strictly follow the format.
   - At the end of each question, also include:
     Keywords: <comma-separated keywords>
   - Separate each question with:
     ---

2. Then generate the SAME 4 alternate questions in HINDI.
   - Start with:
     ### HINDI
   - Each question must strictly follow the format.
   - At the end of each question, also include:
     Keywords: <comma-separated keywords>
   - Separate each question with:
     ---

{instruction}
"""

        # ========== CALL OPENAI ==========
        completion = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "Always follow the format strictly. No extra text."},
                {"role": "user", "content": bilingual_prompt}
            ],
            temperature=0.7,
            max_tokens=2200,
        )

        ai_text = completion.choices[0].message.content.strip()
        if not ai_text:
            return JsonResponse({'status': 'error', 'message': 'OpenAI returned empty response'}, status=500)

        # ========== PARSE MULTIPLE QUESTIONS ==========
        english_blocks, hindi_blocks = [], []
        for block in ai_text.split("###"):
            block = block.strip()
            if block.startswith("ENGLISH"):
                english_blocks = [b.strip() for b in block.replace("ENGLISH", "").split("---") if b.strip()]
            elif block.startswith("HINDI"):
                hindi_blocks = [b.strip() for b in block.replace("HINDI", "").split("---") if b.strip()]

        paired_blocks = []
        for i in range(max(len(english_blocks), len(hindi_blocks))):
            paired_blocks.append({
                "english": english_blocks[i] if i < len(english_blocks) else "",
                "hindi": hindi_blocks[i] if i < len(hindi_blocks) else "",
            })

        # ========== Render ==========
        html = render_to_string('partials/ai_alt_ques_result_card.html', {
            'paired_blocks': paired_blocks,
            'question_id': question.id
        })
        return JsonResponse({'status': 'success', 'html': html})

    except Exception as e:
        print(" Traceback:", traceback.format_exc())
        return JsonResponse({'status': 'error', 'message': str(e)}, status=500)



import re
import json
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import QuestionBank, SubTopicName


@login_required
def save_alternate_question(request):

    if request.method != "POST":
        return JsonResponse({"status": "error", "message": "Invalid request method"}, status=400)

    try:
        # ===============================
        # Handle JSON / Form POST
        # ===============================
        if request.content_type == "application/json":
            data = json.loads(request.body)
            original_question_id = data.get("source_id")
            content_payload = data.get("content")
        else:
            original_question_id = request.POST.get("source_id")
            content_payload = request.POST.get("content")

        if not original_question_id or not content_payload:
            return JsonResponse({"status": "error", "message": "Missing data"}, status=400)

        english_blocks, hindi_blocks = [], []

        if isinstance(content_payload, dict):
            english_blocks = content_payload.get("english_blocks", [])
            hindi_blocks = content_payload.get("hindi_blocks", [])
        else:
            ai_text = content_payload.strip()
            for chunk in ai_text.split("###"):
                c = chunk.strip()
                if c.startswith("ENGLISH"):
                    english_blocks = [
                        b.strip() for b in c.replace("ENGLISH", "").split("---") if b.strip()
                    ]
                elif c.startswith("HINDI"):
                    hindi_blocks = [
                        b.strip() for b in c.replace("HINDI", "").split("---") if b.strip()
                    ]

    except Exception as e:
        return JsonResponse({"status": "error", "message": f"JSON Error: {str(e)}"}, status=400)

    try:
        source_question = get_object_or_404(QuestionBank, id=original_question_id)

        # ======================================
        # Helpers
        # ======================================

        def match_subtopic(keywords_text):
            if not keywords_text:
                return None
            for kw in keywords_text.split(","):
                kw = kw.strip()
                if kw:
                    sub = SubTopicName.objects.filter(name__icontains=kw).first()
                    if sub:
                        return sub
            return None

        def parse_block(text, language="e"):
            """
            Parses an AI block of text into question, options, answer, description, keywords.
            language = "e" for English, "h" for Hindi
            """
            if not text:
                return {
                    "question": "",
                    "a": "",
                    "b": "",
                    "c": "",
                    "d": "",
                    "answer": "",
                    "description": "",
                    "keywords": "",
                }

            # Normalize line breaks
            text = text.replace("\r", "").strip()

            # ------------------------------
            # Remove ALL Question, Options, Keywords labels
            # ------------------------------
            if language == "e":
                text = re.sub(r"(?im)\bQuestion\s*[:：]", "", text)
                text = re.sub(r"(?im)\bOptions\s*[:：]?", "", text)
                text = re.sub(r"(?im)\bKeywords\s*[:：]?", "", text)
            else:
                text = re.sub(r"(?im)\bQuestion\s*[:：]", "", text)
                text = re.sub(r"(?im)\bOptions\s*[:：]?", "", text)
                text = re.sub(r"(?im)\bKeywords\s*[:：]?", "", text)
                text = re.sub(r"(?im)\bप्रश्न\s*[:：]", "", text)
                text = re.sub(r"(?im)\bविकल्प\s*[:：]?", "", text)
                text = re.sub(r"(?im)\bसही\s*उत्तर\s*[:：]?", "", text)
                text = re.sub(r"(?im)\bव्याख्या\s*[:：]?", "", text)

            # Extract Keywords (if present at end)
            keywords_match = re.search(r"(?i)Keywords\s*[:：]\s*(.+)", text)
            keywords = keywords_match.group(1).strip() if keywords_match else ""
            if keywords_match:
                text = text.replace(keywords_match.group(0), "")

            # Extract Correct Answer Choice
            answer_match = re.search(
                r"(?i)Correct\s*Answer\s*[:：]?\s*\(?([a-d])\)?",
                text
            )
            answer = answer_match.group(1).lower() if answer_match else ""
            if answer_match:
                text = text.replace(answer_match.group(0), "")

            # Extract Explanation / Description
            desc_match = re.search(
                r"(?i)(Correct\s*Answer\s*Description|Explanation|Solution)\s*[:：]\s*(.+)",
                text,
                re.DOTALL
            )
            description = desc_match.group(2).strip() if desc_match else ""
            if desc_match:
                text = text.replace(desc_match.group(0), "")

            # Extract Options (STRICT FORMAT)
            option_pattern = r"(?im)^[\(\[]?([a-d])[\)\]\.\-:]?\s*(.+)"
            option_matches = re.findall(option_pattern, text)

            options = {"a": "", "b": "", "c": "", "d": ""}
            for key, val in option_matches:
                options[key.lower()] = val.strip()

            # Remove option lines from text to get clean question
            text = re.sub(option_pattern, "", text)

            question_text = text.strip()

            return {
                "question": question_text,
                "a": options["a"],
                "b": options["b"],
                "c": options["c"],
                "d": options["d"],
                "answer": answer,
                "description": description,
                "keywords": keywords,
            }

        # ======================================
        # SAVE AI QUESTIONS
        # ======================================

        created_ids = []

        with transaction.atomic():

            for i in range(min(len(english_blocks), len(hindi_blocks))):

                en = parse_block(english_blocks[i], language="e")
                hi = parse_block(hindi_blocks[i], language="h")

                subtopic = match_subtopic(en["keywords"]) or match_subtopic(hi["keywords"])

                # -------------------------
                # ENGLISH AI QUESTION
                # -------------------------
                q_en = QuestionBank.objects.create(
                    base_question_id=source_question.base_question_id,
                    question_number=source_question.question_number,
                    question_sub_type=source_question.question_sub_type,
                    language="e",
                    type_of_question=source_question.type_of_question,
                    ai_version=source_question.ai_version + 1 if source_question.ai_version else 1,
                    created_by=request.user,
                    ai_matched_subtopic=subtopic,

                    question_part=en["question"],
                    answer_option_a=en["a"],
                    answer_option_b=en["b"],
                    answer_option_c=en["c"],
                    answer_option_d=en["d"],
                    correct_answer_choice=en["answer"],
                    correct_answer_description=en["description"],

                    key_words=en["keywords"],
                    key_words_en=en["keywords"],
                )

                # -------------------------
                # HINDI AI QUESTION
                # -------------------------
                q_hi = QuestionBank.objects.create(
                    base_question_id=source_question.base_question_id,
                    question_number=source_question.question_number,
                    question_sub_type=source_question.question_sub_type,
                    language="h",
                    type_of_question=source_question.type_of_question,
                    ai_version=q_en.ai_version,
                    created_by=request.user,
                    ai_matched_subtopic=subtopic,

                    question_part_hi=hi["question"],
                    answer_option_a_hi=hi["a"],
                    answer_option_b_hi=hi["b"],
                    answer_option_c_hi=hi["c"],
                    answer_option_d_hi=hi["d"],
                    correct_answer_choice=hi["answer"],
                    correct_answer_description_hi=hi["description"],

                    key_words=hi["keywords"],
                    key_words_hi=hi["keywords"],
                )

                created_ids.extend([q_en.id, q_hi.id])

        return JsonResponse({
            "status": "success",
            "new_ids": created_ids
        })

    except Exception as e:
        return JsonResponse({
            "status": "error",
            "message": str(e)
        }, status=500)


from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import csrf_exempt
from django.template.loader import render_to_string
from openai import OpenAI
import traceback, json, re

from .models import (
    QuestionBank, KeywordName, SubTopicName,
    Area, Section, PartName, ChapterName, TopicName
)

# ✅ Initialize OpenAI Client
client = OpenAI(api_key="YOUR_OPENAI_API_KEY")

# 🧹 Ignore junk/common words
IGNORED_KEYWORDS = {
    "india", "indian", "delhi", "bihar", "up", "mp", "maharashtra",
    "country", "state", "district", "world", "nation",
    "january", "february", "march", "april", "may", "june",
    "july", "august", "september", "october", "november", "december",
    "none", "all", "both", "each", "year", "century", "data", "time"
}


# ============================================================
# 🔹 Safe Keyword Creation Helper
# ============================================================
def safe_get_or_create_keyword(name, lang="EN", source="ai", score=0.9, subtopics=None):
    """
    Ensures uniqueness (case-insensitive) and safely links to one or more subtopics.
    Supports multiple subtopics per keyword.
    """
    try:
        clean_name = (name or "").strip()
        if not clean_name:
            return None

        obj = KeywordName.objects.filter(name__iexact=clean_name, language__iexact=lang).first()
        if not obj:
            obj = KeywordName.objects.create(
                name=clean_name,
                language=lang,
                source=source,
                relevance_score=score
            )

        # ✅ Link multiple subtopics if provided
        if subtopics:
            if isinstance(subtopics, (list, tuple, set)):
                for st in subtopics:
                    if st:
                        obj.subtopics.add(st)
            else:
                obj.subtopics.add(subtopics)

        obj.save(update_fields=[])
        return obj

    except Exception as e:
        print(" Keyword Creation Error:", e)
        return None


# ============================================================
# 🔹 Generate AI-based Subtopics & Keywords
# ============================================================
@csrf_exempt
def generate_pyq_keywords(request):
    """
    🔹 AI-based Subtopic & Keyword Mapping
    - Maps Question | SubTopics (many-to-many)
    - Generates bilingual keywords
    - Merges with existing DB keywords
    - Returns rendered HTML block for frontend
    """
    if request.method != "POST":
        return JsonResponse({"status": "error", "message": "Invalid request"}, status=400)

    qid = request.POST.get("question_id")
    if not qid:
        return JsonResponse({"status": "error", "message": "Missing question ID"}, status=400)

    try:
        # 1️⃣ Fetch Question
        question = get_object_or_404(QuestionBank, id=qid)

        q_text = f"""
Question: {question.question_part_first or question.question_part or ''}
Options:
A. {question.answer_option_a}
B. {question.answer_option_b}
C. {question.answer_option_c}
D. {question.answer_option_d}
Correct Answer: {question.correct_answer_choice}
Explanation: {question.correct_answer_description or ''}
"""

        # 2️⃣ Load available Subtopics for mapping
        subtopics = list(
            SubTopicName.objects.select_related("topic__chapter__part__section__area").values(
                "name", "sub_topic_short_Code", "topic__chapter__part__section__area__name",
            )
        )
        subtopic_list = [
            f"{s['topic__chapter__part__section__area__name']} | {s['name']} ({s['sub_topic_short_Code']})"
            for s in subtopics
        ]

        # 3️⃣ Prompt AI for Subtopic Mapping
        mapping_prompt = f"""
You are a UPSC/MPPSC content mapping expert at Hajela’s IAS Academy.

Analyse this question (options + explanation).
Map it to 2–5 conceptually relevant subtopics from the provided list.

Rules:
- Match by conceptual link, not word overlap.
- Include "confidence" (0–1) and "reason" in JSON.
- Output valid JSON only.

Question:
{q_text}

Available Subtopics:
{subtopic_list[:500]}
"""

        completion = client.chat.completions.create(
            model="gpt-4o",
            messages=[
                {"role": "system", "content": "Output valid JSON only — no commentary or markdown."},
                {"role": "user", "content": mapping_prompt},
            ],
            temperature=0.3,
            max_tokens=1200,
        )

        raw_output = completion.choices[0].message.content.strip()
        print("\nRAW AI OUTPUT:\n", raw_output.encode("utf-8","ignore").decode("utf-8"), "\n")

        cleaned = re.sub(r"```(?:json)?", "", raw_output).replace("```", "").strip()

        try:
            parsed_json = json.loads(cleaned)
            if isinstance(parsed_json, dict):
                matched_subtopics = (
                    parsed_json.get("matches")
                    or parsed_json.get("relevant_subtopics")
                    or parsed_json.get("mapped_subtopics")
                    or parsed_json.get("high_confidence_mappings")
                    or []
                )
            else:
                matched_subtopics = parsed_json
        except Exception:
            matched_subtopics = []

        # 4️⃣ Verify & Link Subtopics
        verified_matches, linked_subtopics, seen = [], [], set()
        question.subtopic_name.clear()

        for st in matched_subtopics:
            name_ai, conf, reason = "", 0.9, "AI thematic mapping"
            if isinstance(st, dict):
                name_ai = st.get("subtopic", "").strip().lower()
                conf = float(st.get("confidence", 0.9))
                reason = st.get("reason", reason)
            elif isinstance(st, str):
                name_ai = st.strip().lower()

            # Clean patterns
            name_ai = name_ai.replace("|", " ")
            name_ai = re.sub(r"\(.*?\)", "", name_ai)
            name_ai = re.sub(
                r"\b(history|geography|economy|polity|environment|science|gs|general studies|other)\b",
                "",
                name_ai,
                flags=re.IGNORECASE,
            ).strip()

            if not name_ai or name_ai in seen:
                continue
            seen.add(name_ai)

            sub_obj = SubTopicName.objects.filter(name__icontains=name_ai).select_related(
                "topic__chapter__part__section__area"
            ).first()
            if not sub_obj:
                continue

            topic = sub_obj.topic
            chapter = topic.chapter if topic else None
            part = chapter.part if chapter else None
            section = part.section if part else None
            area = section.area if section else None

            if area: question.area_name.add(area)
            if section: question.section_name.add(section)
            if part: question.part_name.add(part)
            if chapter: question.chapter_name.add(chapter)
            if topic: question.topic_name.add(topic)

            question.subtopic_name.add(sub_obj)
            linked_subtopics.append(sub_obj)

            verified_matches.append({
                "area": getattr(area, "name", "—"),
                "section": getattr(section, "name", "—"),
                "part": getattr(part, "name", "—"),
                "chapter": getattr(chapter, "name", "—"),
                "topic": getattr(topic, "name", "—"),
                "subtopic": sub_obj.name,
                "code": sub_obj.sub_topic_short_Code,
                "reason": reason,
                "confidence": round(conf, 2),
            })

        # ✅ Link all found subtopics to their keywords
        for sub in linked_subtopics:
            safe_get_or_create_keyword(sub.name, "EN", "ai", 0.9, [sub])

        if linked_subtopics:
            question.ai_matched_subtopic = linked_subtopics[0]
            question.save(update_fields=["ai_matched_subtopic"])

        # 5️⃣ Generate Keywords (Bilingual)
        all_existing_keywords = set(KeywordName.objects.values_list("name", flat=True))
        existing_keywords_lower = {k.lower().strip() for k in all_existing_keywords}

        keyword_prompt = f"""
You are an expert UPSC/MPPSC keyword curator following Hajela’s IAS Keyword Rulebook v1.1.

Generate 8–12 precise, examinable keywords in English and Hindi.

Skip generic/country/state words and duplicates from this list:
{', '.join(list(existing_keywords_lower)[:200])}

Format strictly:
### ENGLISH
keyword1, keyword2, keyword3
---
### HINDI
कीवर्ड1, कीवर्ड2, कीवर्ड3

Question Context:
{q_text}
"""
        kw_completion = client.chat.completions.create(
            model="gpt-4o",
            messages=[
                {"role": "system", "content": "Return bilingual keywords only — no commentary."},
                {"role": "user", "content": keyword_prompt},
            ],
            temperature=0.4,
            max_tokens=900,
        )

        ai_text = kw_completion.choices[0].message.content.strip()
        print("\nRAW KEYWORDS OUTPUT:\n", ai_text.encode("utf-8","ignore").decode("utf-8"), "\n")

        # ✅ Extract bilingual keywords
        en_keywords, hi_keywords = "", ""
        for block in ai_text.split("###"):
            block = block.strip().replace("---", "").strip()
            if block.lower().startswith("english"):
                en_keywords = re.sub(r"(?i)english", "", block).strip()
            elif block.lower().startswith("hindi") or "कीवर्ड" in block:
                hi_keywords = re.sub(r"(?i)hindi", "", block).strip()

        # ✅ Clean keywords
        def clean_keywords(text):
            words = [k.strip() for k in text.split(",") if k.strip()]
            return [
                w for w in words
                if w.lower() not in IGNORED_KEYWORDS and w.lower() not in existing_keywords_lower
            ]

        en_clean = clean_keywords(en_keywords)
        hi_clean = clean_keywords(hi_keywords)

        # ✅ Collect existing DB keywords for linked subtopics
        existing_subtopic_keywords = KeywordName.objects.filter(
            subtopics__in=linked_subtopics
        ).distinct().values("name", "language")

        db_en = [k["name"] for k in existing_subtopic_keywords if k["language"] == "EN"]
        db_hi = [k["name"] for k in existing_subtopic_keywords if k["language"] == "HI"]

        merged_en = sorted(set(db_en) | {k.lower().strip() for k in en_clean})
        merged_hi = sorted(set(db_hi) | {k.lower().strip() for k in hi_clean})

        # ✅ Save to question
        question.key_words = f"EN: {', '.join(merged_en)} | HI: {', '.join(merged_hi)}"
        question.key_words_en = ", ".join(merged_en)
        question.key_words_hi = ", ".join(merged_hi)
        question.save(update_fields=["key_words", "key_words_en", "key_words_hi"])

        # ✅ Create & link all keywords
        for kw in merged_en:
            safe_get_or_create_keyword(kw, "EN", "merged", 0.9, linked_subtopics)
        for kw in merged_hi:
            safe_get_or_create_keyword(kw, "HI", "merged", 0.9, linked_subtopics)

        # ✅ Render HTML for frontend
        html = render_to_string(
            "partials/ai_result_card.html",
            {
                "paired_blocks": [{
                    "english": question.question_part_first or "",
                    "hindi": question.question_part_first_hi or "",
                    "en_keywords": ", ".join(merged_en),
                    "hi_keywords": ", ".join(merged_hi),
                    "db_en_keywords": db_en,
                    "db_hi_keywords": db_hi,
                    "source": "AI + DB Keywords Merged",
                    "matched_subtopics": verified_matches or [],
                }],
                "question_id": question.id,
                "existing_keywords": set(KeywordName.objects.filter(language="EN").values_list("name", flat=True)),
                "existing_keywords_hi": set(KeywordName.objects.filter(language="HI").values_list("name", flat=True)),
            },
            request=request,
        )

        return JsonResponse({
            "status": "success",
            "html": html,
            "matched_count": len(verified_matches),
            "linked_subtopics": [s.sub_topic_short_Code for s in linked_subtopics],
            "hierarchy_tagged": True,
        })


    except Exception as e:
        import traceback

        safe_trace = traceback.format_exc().encode("utf-8","ignore").decode("utf-8")
        safe_error = str(e).encode("utf-8","ignore").decode("utf-8")

        print("Keyword Generation Error:\n", safe_trace)

        return JsonResponse(
            {"status": "error", "message": safe_error},
            status=500,
            json_dumps_params={"ensure_ascii": False}
        )
    

    
from django.views.decorators.http import require_POST
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import csrf_exempt
import json
from .models import QuestionBank, KeywordName, SubTopicName

@csrf_exempt
@require_POST
def update_question_keywords(request):
    """
    ✅ Handles manual save from frontend:
       - Updates English/Hindi keywords
       - Saves Subtopic relations (ManyToMany)
       - Syncs with KeywordName table (creates if missing)
    """
    try:
        data = json.loads(request.body.decode("utf-8"))
        qid = data.get("question_id")
        en_keywords = data.get("english_keywords", "").strip()
        hi_keywords = data.get("hindi_keywords", "").strip()
        subtopic_codes = data.get("subtopics", [])  # new

        if not qid:
            return JsonResponse({"status": "error", "message": "Missing question_id"}, status=400)

        question = get_object_or_404(QuestionBank, id=qid)

        # 🧹 Normalize lists
        en_list = sorted(set([k.strip() for k in en_keywords.split(",") if k.strip()]))
        hi_list = sorted(set([k.strip() for k in hi_keywords.split(",") if k.strip()]))

        # ✅ Update question keywords fields
        question.key_words_en = ", ".join(en_list)
        question.key_words_hi = ", ".join(hi_list)
        question.key_words = f"EN: {', '.join(en_list)} | HI: {', '.join(hi_list)}"
        question.save(update_fields=["key_words", "key_words_en", "key_words_hi"])

        # ✅ Update subtopics relations (ManyToMany)
        if subtopic_codes:
            question.subtopic_name.clear()
            for code in subtopic_codes:
                sub_obj = SubTopicName.objects.filter(sub_topic_short_Code=code).select_related(
                    "topic__chapter__part__section__area"
                ).first()
                if sub_obj:
                    # link the subtopic
                    question.subtopic_name.add(sub_obj)

                    # link the hierarchy automatically
                    topic = sub_obj.topic
                    chapter = topic.chapter if topic else None
                    part = chapter.part if chapter else None
                    section = part.section if part else None
                    area = section.area if section else None

                    if area: question.area_name.add(area)
                    if section: question.section_name.add(section)
                    if part: question.part_name.add(part)
                    if chapter: question.chapter_name.add(chapter)
                    if topic: question.topic_name.add(topic)

        # ✅ Sync keywords to KeywordName table
        existing_all = set(KeywordName.objects.values_list("name", flat=True))
        existing_lower = {e.lower().strip() for e in existing_all}

        merged_en = []
        merged_hi = []

        for kw in en_list:
            kw_clean = kw.strip()
            if kw_clean.lower() not in existing_lower:
                KeywordName.objects.create(name=kw_clean, language="EN", source="manual/merged")
            merged_en.append(kw_clean)

        for kw in hi_list:
            kw_clean = kw.strip()
            if kw_clean.lower() not in existing_lower:
                KeywordName.objects.create(name=kw_clean, language="HI", source="manual/merged")
            merged_hi.append(kw_clean)

        # ✅ Final confirmation response
        return JsonResponse({
            "status": "success",
            "message": "✅ Keywords & Subtopics saved successfully.",
            "english_keywords": merged_en,
            "hindi_keywords": merged_hi,
            "subtopics": subtopic_codes,
            "question_id": question.id
        })

    except Exception as e:
        print("update_question_keywords Error:", e)
        return JsonResponse({
            "status": "error",
            "message": f"Server Error: {str(e)}"
        }, status=500)


from django.shortcuts import render, get_object_or_404
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from openai import OpenAI
from .models import SubTopicName, MicroSubTopicName

# client = OpenAI(api_key=settings.OPENAI_API_KEY)

def subtopic_list_view(request):
    """Show all SubTopics with button to generate keywords"""
    subtopics = SubTopicName.objects.select_related('topic').all()

    # Convert MicroSubTopicName objects into {subtopic_id: [list of keywords]}
    existing_keywords = {}
    for ms in MicroSubTopicName.objects.select_related('subtopics'):
        kw_list = [kw.strip() for kw in ms.name.split(',') if kw.strip()]
        existing_keywords[ms.subtopics.sub_topic_SI_Number] = kw_list

    return render(
        request,
        'question_bank/subtopics_list.html',
        {
            'subtopics': subtopics,
            'existing_keywords': existing_keywords
        }
    )


@csrf_exempt
def generate_keywords_view(request, subtopic_id):
    """Generate conceptual or PYQ-based keywords for a SubTopic."""
    subtopic = get_object_or_404(SubTopicName, pk=subtopic_id)
    mode = request.GET.get('mode', 'conceptual').lower()

    if mode == "pyq":
        # 📘 PYQ-based prompt (exam trend-aware)
        prompt = f"""
You are an expert UPSC and State PSC exam analyst.

TASK:
Generate 15–20 exam-relevant keywords for the following Sub-Topic,
based on previous year questions (PYQs) asked in UPSC, MPPSC and other State PSC exams.

Sub-Topic: {subtopic.name}
Topic: {subtopic.topic.name if subtopic.topic else 'N/A'}
Short Code: {subtopic.sub_topic_short_Code}

Guidelines:
- Base your output on PYQ trends.
- Focus on frequently tested entities, acts, articles, committees, reports, and institutions.
- Return only comma-separated keywords (no numbering or explanation).
"""
    else:
        # 🧠 CONCEPTUAL PROMPT (Full Hajela’s IAS Rulebook v1.7)
        prompt = f"""
You are an expert UPSC/MPPSC keyword curator.

TASK: 
1. Generate 20–30 high-signal keywords in English. The rules (Rulebook for Sub Topics MCQ Keywording (v1.7 – 2025-10-04 IST)) to be followed while creating keywords are:
   a. Scope & Philosophy
      i. Hajela's IAS (HIA) is a Bhopal-based coaching institution for various Civil Services examinations (UPSC, MPPSC, etc.). Its database contains:
         1. Topics (basic unit: "Sub_topic")
         2. Questions (PYQs, Model Questions)
         3. Content (lecture videos, PDFs, notes)
      ii. The database is divided into Areas | Parts | Chapters | Topics | Sub-topics.
      iii. Areas:
         1. History
         2. Geography
         3. Polity
         4. Economy
         5. Environment
         6. Science
         7. General Knowledge (GK)
         8. Current Affairs
         9. International Relations
         10. Ethics
         11. HIA Special
         12. Art & Culture
         13. Hindi
         14. English
         15. Internal Security & Disaster Management
         16. Humanities & Management
         17. MP History
         18. MP Geography
         19. Information and Communication Technology (ICT)
         20. MP Tribes
         21. MP Polity
         22. MP Economy
         23. GS2 (General Studies 2) consisting of Comprehension, Logical Reasoning etc.
      iv. Parts (≈140):
         1. Ancient India
         2. Medieval India
         3. The 18th Century India
         4. The 19th Century India
         5. Indian National Movement
         6. Modern Indian History
         7. World History
         8. Physical Geography Astronomy
         9. World Area Geography
         10. Physical Geography Earth
         11. Physical Geography Lithosphere
         12. Physical Geography Atmosphere
         13. Physical Geography Climatology
         14. Physical Geography Hydrosphere
         15. World Human Geography
         16. World Economic Geography
         17. India Area Geography
         18. Indian Human Geography
         19. Indian Physical Geography
         20. Indian Economic Geography
         21. Geographical Terms
         22. Geo-informatics
         23. Introduction to Polity
         24. System of Governance
         25. Constitutional Framework
         26. Constitutional Details
         27. Details of Governance
         28. Welfare State
         29. Constitutional Bodies
         30. Working of the Constitution
         31. Bodies other than Constitutional Bodies
         32. Other Constitutional Dimensions
         33. Elections
         34. Other Political Dynamics
         35. Comparison of the Constitution
         36. Polity-Others
         37. Introduction & Basic Concepts
         38. Macroeconomics
         39. Microeconomics
         40. General Economics
         41. Health
         42. Education
         43. Sociology & Economy
         44. Government Policies and Interventions
         45. Economy Current Issues
         46. General Environment
         47. Biodiversity
         48. Biodiversity Chemistry
         49. Climate Change
         50. Science Tech
         51. Space Tech
         52. Defence Tech
         53. Nuclear Tech
         54. Nano Tech
         55. Intellectual Property
         56. Biotechnology
         57. Biosciences
         58. Physics
         59. Chemistry
         60. Geometry & Mensuration
         61. Arithmetic
         62. Statistics & Mathematics
         63. Permutation, Combination & Probability
         64. GK
         65. International Current Affairs
         66. National Current Affairs
         67. Madhya Pradesh Current Affairs
         68. Current Affairs - General
         69. Indian Foreign Relations
         70. Groupings & International Institutions
         71. International Relations Current Issues
         72. Ethics
         73. Psychology
         74. Ethics & Philosophy
         75. Ethics in Public Administration
         76. Ethics, Life Style and Counter Force MP
         77. Art Forms
         78. Painting
         79. Literature
         80. Architecture
         81. Music
         82. World Art & Culture
         83. MP Art & Culture
         84. General Hindi GS UPSC
         85. Hindi General MP Mains
         86. Hindi Essay MP Mains
         87. English UPSC
         88. Internal Security
         89. Disaster Management
         90. Sociology
         91. Entrepreneurship & Management MP
         92. MP History
         93. MP Geography
         94. Information Technology
         95. M P Tribes
         96. MP Polity
         97. MP Education
         98. MP Economy
         99. MP Health
         100. Comprehension
         101. Interpersonal & Communication Skills
         102. Logical Reasoning and Analytical Ability
         103. Decision Making
         104. Mental Ability
         105. Numeracy
         106. Data Interpretation
         107. Comprehension MP
         108. Communication Skills MP
         109. Logical Reasoning and Analytical Ability MP
         110. Decision Making MP
         111. Mental Ability MP
         112. Numeracy MP
         113. Data Interpretation MP
         114. Essay UPSC
         115. Test
         116. Mock Interview
      v. Next levels:
         1. ≈450 Chapters
         2. ≈1200 Topics
         3. ≈1700 Sub-topics
         4. The details are available at the database ...............
      vi. Keywords are the bridge between Sub-topics and Questions:
         1. Keywords must be generated for both Questions and Sub-topics.
         2. Matching keywords enable tagging Questions ↔ Sub-topics.
         3. Target: 15–20 high-signal, examinable, precise phrases per Sub Topic.
         4. General properties:
            a. Case-insensitive
            b. Sequence-sensitive
            c. Keywords (backend) vs. Hashtags (frontend) | system relies on keywords.
      vii. Presently, keywords need to be generated only for Sub-topics:
         1. For generation of Keywords, the Area, Part, Chapter, Topic and Sub Topic need to be considered together.
   b. Hard Deletions (do not create such keywords unless exempted)
      i. Axis tails (generic): polity, economy, society, religion, culture, art & architecture, literature, chronology, sources.
      ii. Era mislabels: standalone "Ancient India", "Medieval India", "Modern India".
      iii. Noisy stand-alones:
         1. Generic nouns: development, reforms, rule, law, events, contribution, emergence, knowledge, mapping, field, records, rise, factors, responsible.
         2. Unqualified geographies: Asia, Europe, Africa, America, World.
         3. Bare science terms: geomagnetic field, rocks, theory, effect, eruption.
         4. Filler adjectives: important, major, various, different, key.
         5. Meta-words: overview, background, miscellaneous, types.
         6. Roman numerals (if alone).
         7. Initials/honorifics: Dr., Pt., Sri, Netaji, Mahatma, Lokmanya, Begum, Rao, etc.
         8. Duplicate forms (case/punctuation variants).
         9. Standalone years (normalize or drop).
         10. Example deletions: stone, india, post, indo, dynasties, salient events, empires, across, world, century, wars, scenario, india 1.
   c. Using High-signal Terms (examples)
      i. Era anchoring:
         1. "Ancient India (Pre-Mauryan)", "Medieval India (Delhi Sultanate)""Medieval India (1000-1700 AD)".
      ii. Geographic anchoring:
         1. Tie "India" with period (e.g., Modern India).
         2. Foreign example: "European Renaissance (15th–16th c.)".
      iii. Dynasty/Era/Text expansion:
         1. Maurya | Mauryan Empire
         2. Gupta | Gupta Empire
         3. Rigveda | Rigveda (Vedic Text)
      iv. Conceptual enrichment:
         1. Architecture | Nagara temple style / Stupa–Chaitya–Vihara
         2. Literature | Sangam corpus / Arthashastra (text)
      v. Year normalization:
         1. 1200 | 1200 AD; 600 BCE
         2. Use en dash: 1775–82
      vi. Relation expansion:
         1. US USSR relations | US–USSR relations (Cold War)
         2. America formation | Formation of the USA (1776–1789)
   d. Facet Templates
      i. Persons/Leaders: role, tenure, key battles, treaties, allies/enemies.
      ii. Wars/Battles: battle name, year, commanders, outcomes, treaties.
      iii. Constitutional Acts/Missions: provisions, criticisms, institutions formed.
      iv. Mass movements: aims, slogans, sessions, withdrawals, spread.
      v. Civilisations/Cultural: polity, economy, society/religion, art, literature, sources.
      vi. Foreign relations: bind to era + geography.
   e. Question Keyword Rules (APQO/RQK)
      i. Base context: Area + Part (+ Chapter/Topic if available).
      ii. Stem: key entities/ideas.
      iii. Options: include all 4 answer options.
      iv. Correct answer description: enrich for concept precision.
   f. QA Checklist
      i. Era alignment with Area/Part/Chapter/Topic.
      ii. ≥70% high-signal entities/events/ideas.
      iii. De-duplicate by case/punctuation.
      iv. Typography: en dash, proper names, full forms.
   g. Other Rules (evolving)
      i. Core matching semantics: case-insensitive, order-sensitive, lowercase internal, Title Case display.
      ii. Noise deletion: drop generic singletons, unqualified labels, naked years, filler tokens, exam-instruction artifacts.
      iii. Concept enrichment & canonicalization:
         1. Acts/Sessions/Movements with year (e.g., Government of India Act 1919 – Dyarchy).
         2. Person


2.  Output: comma-separated, Title Case where needed.

3. Translate the keywords generated also into Hindi (keywords only, no sentences).

Now, generate keywords for the following:

Sub-Topic: {subtopic.name}  
Topic: {subtopic.topic.name if subtopic.topic else 'N/A'}  
Short Code: {subtopic.sub_topic_short_Code}

Output Format:
English Keywords (comma-separated)
Hindi Keywords (comma-separated)
"""

    try:
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "You are a civil services keyword tagging expert following Hajela’s IAS Keyword Rulebook v1.7."},
                {"role": "user", "content": prompt},
            ],
            max_tokens=500,
            temperature=0.7,
        )

        keywords = response.choices[0].message.content.strip()

        # Save separately for conceptual / pyq
        MicroSubTopicName.objects.update_or_create(
            micro_sub_topic_SI_number=f"{subtopic.sub_topic_SI_Number}_{mode.upper()}",
            defaults={"name": keywords, "subtopics": subtopic}
        )

        return JsonResponse({"success": True, "keywords": keywords, "mode": mode})
    except Exception as e:
        return JsonResponse({"success": False, "error": str(e)})



from django.contrib.auth.decorators import login_required
from .models import QuestionBank

@login_required
def view_ai_generated_questions(request):
    questions = QuestionBank.objects.filter(
        correct_answer_description__isnull=False,
        question_sub_type='simple_type'  # You can remove this filter if you want all types
    ).order_by('-created_at')  # Shows newest first
    return render(request, 'question_bank/ai_questions.html', {'questions': questions})



import os
import re
from datetime import datetime
from io import BytesIO

from PIL import Image as PILImage
from django.conf import settings
from django.http import FileResponse, HttpResponse
from docx import Document
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.shared import Inches

from .models import QuestionBank

def clean_text(text):
    """Utility function to clean and format text by removing extra newlines and spaces."""
    if not text:
        return ''
    text = text.strip()
    text = re.sub(r'\s*\n\s*', ' ', text)
    text = re.sub(r'\s+', ' ', text)
    return text

def set_no_border(cell):
    tc = cell._element
    tcPr = tc.get_or_add_tcPr()
    tcBorders = OxmlElement('w:tcBorders')
    for border_name in ['top', 'left', 'bottom', 'right']:
        border = OxmlElement(f'w:{border_name}')
        border.set(qn('w:val'), 'nil')
        tcBorders.append(border)
    tcPr.append(tcBorders)

def generate_questions_document(request):
    try:
        # ✅ Get selected IDs from POST
        selected_ids = request.POST.getlist('selected_questions')  # ✅ correct
  # JavaScript sends this list via AJAX
        if not selected_ids:
            return HttpResponse("No questions selected!", status=400)

        questions = QuestionBank.objects.filter(id__in=selected_ids)

        # Setup document
        base_dir = os.path.join(settings.MEDIA_ROOT, 'word_file')
        os.makedirs(base_dir, exist_ok=True)
        today = datetime.today().strftime('%Y-%m-%d')
        file_name = f'class_plus_questions_{today}.docx'
        file_path = os.path.join(base_dir, file_name)
        document = Document()

        for question in questions:
            table = document.add_table(rows=0, cols=3)
            table.style = 'Table Grid'

            if question.question_sub_type == "r_and_a_type":
                question_text = (
                    clean_text(question.question_part_first or '') + "\n" +
                    (clean_text(question.assertion) if question.assertion else '') + "\n" +
                    (clean_text(question.reason) if question.reason else '') + "\n" +
                    clean_text(question.question_part_third or '')
                )
            else:
                if question.question_part and question.question_part.strip():
                    question_text = clean_text(question.question_part)
                else:
                    question_text = (
                        clean_text(question.question_part_first or '') + "\n" +
                        ("Assertion (A): " + clean_text(question.assertion) if question.assertion else '') + "\n" +
                        ("Reason (R): " + clean_text(question.reason) if question.reason else '') + "\n" +
                        clean_text(question.question_part_third or '')
                    )

            q_row = table.add_row().cells
            q_row[0].text = 'Question'

            if question.question_sub_type == 'list_type_1':
                q_row[1].text = f"{clean_text(question.question_part_first or '')}\n"
                q_row[1].text += "\n".join([
                    f"{i}. {getattr(question, f'list_1_row{i}', '')}"
                    for i in range(1, 9) if getattr(question, f'list_1_row{i}', '')
                ]) + "\n" + clean_text(question.question_part_third or '')
            elif question.list_1_name and question.list_2_name:
                sub_table = document.add_table(rows=1, cols=2)
                sub_table.style = 'Table Grid'
                sub_hdr_cells = sub_table.rows[0].cells
                sub_hdr_cells[0].text = f"LIST - I\n({clean_text(question.list_1_name)})"
                sub_hdr_cells[1].text = f"LIST - II\n({clean_text(question.list_2_name)})"

                for i in range(1, 9):
                    list_1_option = getattr(question, f'list_1_row{i}', '')
                    list_2_option = getattr(question, f'list_2_row{i}', '')
                    if not list_2_option:
                        break
                    row_cells = sub_table.add_row().cells
                    row_cells[0].text = f"{chr(64+i)}. {list_1_option}"
                    row_cells[1].text = f"{i}. {list_2_option}"

                q_row[1]._element.clear_content()
                p = q_row[1].add_paragraph()
                p.add_run(clean_text(question.question_part_first or '') + "\n")
                q_row[1]._element.append(sub_table._element)
                q_row[1].add_paragraph("\nCodes:\t A\t B\t C\t D")
            else:
                q_row[1].text = question_text

            q_row[1].merge(q_row[2])

            # Insert Image
            if question.image:
                image_path = question.image.path
                pil_img = PILImage.open(image_path)
                if pil_img.mode == 'RGBA':
                    pil_img = pil_img.convert('RGB')
                img_io = BytesIO()
                pil_img.save(img_io, format='JPEG')
                img_io.seek(0)
                q_row[1].add_paragraph().add_run().add_picture(img_io, width=Inches(1.5))

            # Handle table options (A-D)
            valid_options = ['a', 'b', 'c', 'd']
            correct_answer = question.correct_answer_choice.lower() if question.correct_answer_choice else None
            for opt in valid_options:
                option_text = getattr(question, f"answer_option_{opt}", None)
                if option_text:
                    opt_row = table.add_row().cells
                    opt_row[0].text = 'Option'
                    opt_row[1].text = f"{opt.upper()}. {option_text}"
                    opt_row[2].text = 'correct' if opt == correct_answer else 'incorrect'

            if question.question_sub_type == 'fill_in_the_blank_type':
                option_row = table.add_row().cells
                option_row[0].text = 'Option'
                option_row[1].text = question.correct_answer_choice or '___'

            if question.question_sub_type == 'true_and_false_type':
                answer_row = table.add_row().cells
                answer_row[0].text = 'Answer'
                correct_answer_letter = question.correct_answer_choice.lower()
                correct_answer_text = getattr(question, f"answer_option_{correct_answer_letter}", None)
                answer_row[1].text = correct_answer_text or "Answer not available"
                answer_row[1].merge(answer_row[2])

            # Additional Info
            table.add_row().cells[0].text = 'Type'
            type_row = table.rows[-1].cells
            type_row[1].text = (
                'true_false' if question.question_sub_type == 'true_and_false_type'
                else 'fill_ups' if question.question_sub_type == 'fill_in_the_blank_type'
                else 'multiple_choice'
            )
            type_row[1].merge(type_row[2])

            sol_row = table.add_row().cells
            sol_row[0].text = 'Solution'
            sol_row[1].text = clean_text(question.correct_answer_description)
            sol_row[1].merge(sol_row[2])

            marks_row = table.add_row().cells
            marks_row[0].text = 'Marks'
            marks_row[1].text = str(question.marks)
            marks_row[2].text = str(question.negative_marks)

            diff_row = table.add_row().cells
            diff_row[0].text = 'Degree of Difficulty'
            diff_row[1].text = clean_text(question.degree_of_difficulty or '')
            diff_row[1].merge(diff_row[2])

            document.add_paragraph()  # space between questions

        document.save(file_path)
        return FileResponse(open(file_path, 'rb'), as_attachment=True, filename=file_name)

    except Exception as e:
        return HttpResponse(f"An error occurred: {str(e)}", status=500)


# views.py
from django.shortcuts import render
from .models import QuestionBank

def generate_classplus_doc_view(request):
    questions = QuestionBank.objects.all()
    return render(request, 'question_bank/generate_classplus_doc.html', {'questions': questions})


# ************************* Generate Clas Plus Word file Start *********************************************


# ************************* Upload Excel file Start *********************************************

# Function to safely convert exam years to integers
def safe_int(value, default=0):
    try:
        return int(value)
    except (ValueError, TypeError):
        return default  # Return a default value if conversion fails

# Function to safely convert numeric values to float
def safe_float(value, default=0.0):
    try:
        return float(value) if value not in [None, '', ' '] else default
    except (ValueError, TypeError):
        return default  # Return default if conversion fails

import random
from django.db import transaction

import re
import pandas as pd
from django.shortcuts import render, redirect
from django.contrib import messages
from django.core.files.storage import FileSystemStorage
from django.db.models import Max

from .models import QuestionBank, Area, PartName
from .forms import UploadFileForm


def safe_int(value, default=0):
    try:
        return int(value)
    except (ValueError, TypeError):
        return default


def safe_float(value, default=0.0):
    try:
        return float(value)
    except (ValueError, TypeError):
        return default


def _pick(row, *keys):
    """Return the first non-empty value from the given candidate keys (strings)."""
    for k in keys:
        v = row.get(k, '')
        if v is None:
            continue
        # pandas can give floats for empty cells; coerce to str safely
        s = str(v).strip()
        if s != '' and s.lower() != 'nan':
            return s
    return ''


# ************************* Upload Excel file Start *********************************************
# ************************* Upload Excel file (updated) *********************************************

import re
import pandas as pd
import random
from django.db import transaction
from django.shortcuts import render, redirect
from django.contrib import messages
from django.core.files.storage import FileSystemStorage
from django.db.models import Max
from django.contrib.auth import get_user_model

from .forms import UploadFileForm
from .models import (
    QuestionBank,
    Area, Section, PartName, ChapterName, TopicName, SubTopicName,
    ExamName, EvergreenIndexName
)

User = get_user_model()

# ---------- tiny helpers ----------

def safe_int(value, default=0):
    try:
        return int(value)
    except (ValueError, TypeError):
        return default

def safe_float(value, default=0.0):
    try:
        if value in (None, '', ' '):
            return default
        return float(value)
    except (ValueError, TypeError):
        return default

def _pick(row, *keys):
    """First non-empty (non-NaN) string from candidate headers."""
    for k in keys:
        if k in row:
            v = row.get(k, '')
            if v is None:
                continue
            s = str(v).strip()
            if s and s.lower() != 'nan':
                return s
    return ''

def _split_multi(val):
    """Split on | or , and trim; ignore blanks/-."""
    if val is None:
        return []
    s = str(val).replace(',', '|')
    return [p.strip() for p in s.split('|') if p and p.strip() and p.strip() != '-']

def _allowed_field_names():
    return {f.name for f in QuestionBank._meta.get_fields()}

def _only_allowed(d: dict, allowed: set) -> dict:
    return {k: v for k, v in d.items() if k in allowed and v not in (None, '')}

def _normalize_source(val: str) -> str:
    v = (val or '').strip().lower()
    if v in {'modern', 'model', 'model question', 'model_question', 'moq'}:
        return 'moq'
    if v in {'pyq', 'previous', 'previous year', 'previous year question', 'prev'}:
        return 'pyq'
    if v in {'osq', 'other', 'other source', 'other source question'}:
        return 'osq'
    return 'moq'

def _qs_by_codes_or_names(model, code_field, name_field, codes_value, names_value):
    codes = _split_multi(codes_value)
    if codes:
        return model.objects.filter(**{f"{code_field}__in": codes})
    names = _split_multi(names_value)
    if names:
        return model.objects.filter(**{f"{name_field}__in": names})
    return model.objects.none()

# ---------- the view ----------

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            xfile = request.FILES['file']
            fs = FileSystemStorage()
            filename = fs.save(xfile.name, xfile)

            data = pd.read_excel(fs.path(filename))
            data = data.fillna({
                'marks': 0,
                'negative_marks': 0,
                'exam_year1': 0,
                'exam_year2': 0,
                'exam_year3': 0,
                'exam_year4': 0,
            }).fillna('')

            with transaction.atomic():

                for _, row in data.iterrows():

                    # =========================
                    # BASE QUESTION ID
                    # =========================
                    base_id_raw = _pick(row, 'base_question_id')
                    try:
                        base_id = int(float(base_id_raw)) if base_id_raw else None
                    except:
                        base_id = None

                    # =========================
                    # AUTO DETECT LANGUAGE
                    # =========================
                    has_english = bool(_pick(row, 'question_part') or _pick(row, 'answer_option_a'))
                    has_hindi = bool(_pick(row, 'question_part_hindi', 'question_part_hi') or _pick(row, 'answer_option_a_hi'))

                    file_language = 'h' if (has_hindi and not has_english) else 'e'

                    # =========================
                    # FIND EXISTING QUESTION
                    # =========================
                    existing_q = None

                    if base_id:
                        existing_q = QuestionBank.objects.filter(
                            base_question_id=base_id,
                            language=file_language
                        ).first()

                    # =========================
                    # COMMON VALUES
                    # =========================
                    type_of_question = _normalize_source(
                        _pick(row, 'question_type_source', 'type_of_question')
                    )

                    years = [
                        safe_int(row.get('exam_year1', 0)),
                        safe_int(row.get('exam_year2', 0)),
                        safe_int(row.get('exam_year3', 0)),
                        safe_int(row.get('exam_year4', 0))
                    ]
                    exam_year = next((y for y in years if y != 0), None)

                    marks_val = safe_float(_pick(row, 'exam_year1_marks', 'marks'))
                    neg_val = safe_float(_pick(row, 'exam_year1_negative_marks', 'negative_marks'))

                    question_sub_type = _pick(row, 'question_sub_type') or 'simple_type'
                    correct_choice = _pick(row, 'correct_answer_choice')

                    # =========================
                    # BUILD PAYLOAD
                    # =========================
                    payload = {
                        'base_question_id': base_id,
                        'type_of_question': type_of_question,
                        'exam_stage': _pick(row, 'exam_stage'),
                        'exam_year': exam_year,
                        'language': file_language,
                        'script': _pick(row, 'script', 'script_en', 'script_hi'),
                        'marks': marks_val,
                        'negative_marks': neg_val,
                        'degree_of_difficulty': _pick(row, 'degree_of_difficulty'),
                        'elim_tactics_degree': _pick(row, 'elim_tactics_degree'),
                        'current_relevance': _pick(row, 'current_relevance'),
                        'current_relevance_topic': _pick(row, 'current_relevance_topic'),
                        'question_sub_type': question_sub_type,
                        'correct_answer_choice': correct_choice,
                        'created_by': request.user,
                    }

                    # =========================
                    # ENGLISH FIELDS
                    # =========================
                    if file_language == 'e':
                        payload.update({
                            'question_part': _pick(row, 'question_part'),
                            'question_part_first': _pick(row, 'question_part_first_part', 'question_part_first'),
                            'question_part_third': _pick(row, 'question_part_third_part', 'question_part_third'),
                            'assertion': _pick(row, 'assertion'),
                            'reason': _pick(row, 'reason'),
                            'list_1_name': _pick(row, 'list_1_name'),
                            'list_2_name': _pick(row, 'list_2_name'),
                            'answer_option_a': _pick(row, 'answer_option_a'),
                            'answer_option_b': _pick(row, 'answer_option_b'),
                            'answer_option_c': _pick(row, 'answer_option_c'),
                            'answer_option_d': _pick(row, 'answer_option_d'),
                            'correct_answer_description': _pick(row, 'correct_answer_description'),
                        })

                    # =========================
                    # HINDI FIELDS
                    # =========================
                    else:
                        payload.update({
                            'question_part_hi': _pick(row, 'question_part_hindi', 'question_part_hi'),
                            'question_part_first_hi': _pick(row, 'question_part_first_part_hindi', 'question_part_first_hi'),
                            'question_part_third_hi': _pick(row, 'question_part_third_part_hindi', 'question_part_third_hi'),
                            'assertion_hi': _pick(row, 'assertion_hindi', 'assertion_hi'),
                            'reason_hi': _pick(row, 'reason_hindi', 'reason_hi'),
                            'list_1_name_hi': _pick(row, 'list_1_name_hi'),
                            'list_2_name_hi': _pick(row, 'list_2_name_hi'),
                            'answer_option_a_hi': _pick(row, 'answer_option_a_hi'),
                            'answer_option_b_hi': _pick(row, 'answer_option_b_hi'),
                            'answer_option_c_hi': _pick(row, 'answer_option_c_hi'),
                            'answer_option_d_hi': _pick(row, 'answer_option_d_hi'),
                            'correct_answer_description_hi': _pick(row, 'correct_answer_description_hi'),
                        })

                    # =========================
                    # UPDATE OR CREATE
                    # =========================
                    if existing_q:
                        for key, value in payload.items():
                            setattr(existing_q, key, value)
                        existing_q.save()
                    else:
                        QuestionBank.objects.create(**payload)

            messages.success(request, "File uploaded and questions processed successfully!")
            return redirect('upload-file')

    else:
        form = UploadFileForm()

    return render(request, 'question_bank/upload.html', {'form': form})

# ************************* End Upload Excel file (updated) *********************************************


from django.http import JsonResponse
from django.views.decorators.http import require_GET
from .models import Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName

# ✅ Helper function for consistent JSON responses
def json_response(data, status=200):
    return JsonResponse(data, status=status)

# ✅ Get all Areas (used when loading the form)
@require_GET
def get_areas(request):
    areas = Area.objects.values('area_SI_Code', 'name')
    return json_response({'areas': list(areas)})

# ✅ Get Areas by selected Subject(s) (optional - if subject filtering is needed)
@require_GET
def get_areas_list(request):
    subject_ids = request.GET.getlist('subject_ids[]')
    if not subject_ids:
        return json_response({'areas': []})
    areas = Area.objects.filter(subject_name__id__in=subject_ids).values('id', 'name')
    return json_response({'areas': list(areas)})

# ✅ Get Sections by selected Area(s)
@require_GET
def get_sections_list(request):
    area_ids = [str(a) for a in request.GET.getlist('area_ids[]')]
    if not area_ids:
        return json_response({'sections': []})
    sections = Section.objects.filter(area__area_SI_Code__in=area_ids).values('section_Unit_SI', 'name')
    return json_response({'sections': list(sections)})

# ✅ Get Parts by selected Section(s)
@require_GET
def get_parts_list(request):
    section_ids = [str(s) for s in request.GET.getlist('section_ids[]')]
    if not section_ids:
        return json_response({'parts': []})
    parts = PartName.objects.filter(section__section_Unit_SI__in=section_ids).values('part_serial', 'name')
    return json_response({'parts': list(parts)})

# ✅ Get Chapters by selected Part(s)
@require_GET
def get_chapters_list(request):
    part_ids = [str(p) for p in request.GET.getlist('part_ids[]')]
    if not part_ids:
        return json_response({'chapters': []})
    chapters = ChapterName.objects.filter(part__part_serial__in=part_ids).values('chapter_number', 'name')
    return json_response({'chapters': list(chapters)})

# ✅ Get Topics by selected Chapter(s)
@require_GET
def get_topics_list(request):
    chapter_ids = [str(c) for c in request.GET.getlist('chapter_ids[]')]
    if not chapter_ids:
        return json_response({'topics': []})
    topics = TopicName.objects.filter(chapter__chapter_number__in=chapter_ids).values('topic_SI_number', 'name')
    return json_response({'topics': list(topics)})

# ✅ Get Subtopics by selected Topic(s)
@require_GET
def get_subtopics_list(request):
    topic_ids = [str(t) for t in request.GET.getlist('topic_ids[]')]
    if not topic_ids:
        return json_response({'subtopics': []})

    subtopics = SubTopicName.objects.filter(
        topic__topic_SI_number__in=topic_ids
    ).values('sub_topic_SI_Number', 'name')

    return json_response({'subtopics': list(subtopics)})


# ✅ Get Exams by selected Subtopic(s)
@require_GET
def get_exams_list(request):
    subtopic_ids = [str(t) for t in request.GET.getlist('subtopic_ids[]')]
    if not subtopic_ids:
        return json_response({'related_exams': [], 'all_exams': []})

    related_exams_qs = ExamName.objects.filter(
        subtopics__sub_topic_SI_Number__in=subtopic_ids
    ).distinct()

    all_exams_qs = ExamName.objects.all()

    related_exams = [
        {
            'exam_SI_Number': exam.exam_SI_Number,
            'name': exam.name,
            'exam_code': exam.exam_code,
        }
        for exam in related_exams_qs
    ]

    all_exams = [
        {
            'exam_SI_Number': exam.exam_SI_Number,
            'name': exam.name,
            'exam_code': exam.exam_code,
        }
        for exam in all_exams_qs
    ]

    return json_response({
        'related_exams': related_exams,
        'all_exams': all_exams
    })


# ✅ NEW: Get Parts directly by selected Area(s) for "Modern" questions

@require_GET
def get_parts_by_area(request):
    area_ids = request.GET.getlist('area_ids[]')
    if not area_ids:
        return JsonResponse({'parts': []})

    parts = PartName.objects.filter(section__area__area_SI_Code__in=area_ids).values('part_serial', 'name')
    return JsonResponse({'parts': list(parts)})

from django.views.decorators.http import require_GET
from django.http import JsonResponse
from .models import HashtagsName, SubTopicName

# ✅ Helper for JSON
def json_response(data, status=200):
    return JsonResponse(data, status=status)

from django.shortcuts import render, get_object_or_404
from django.views.decorators.http import require_GET
from .models import HashtagsName, InputSuggestion
from django.http import JsonResponse

# Helper function for JSON response
def json_response(data):
    return JsonResponse(data, safe=True)


# ✅ Get Hashtags by selected Subtopic(s)
@require_GET
def get_hashtags_list(request):
    subtopic_ids = [str(t) for t in request.GET.getlist('subtopic_ids[]')]
    if not subtopic_ids:
        return json_response({'related_hashtags': [], 'all_hashtags': []})

    # Get hashtags related to selected subtopics
    related_hashtags_qs = HashtagsName.objects.filter(
        subtopics__sub_topic_SI_Number__in=subtopic_ids
    ).order_by("name").distinct()  # distinct ensures no duplicates

    # Get all hashtags (distinct)
    all_hashtags_qs = HashtagsName.objects.all().order_by("name").distinct()

    # Serialize queryset
    related_hashtags = [
        {'hashtags_SI_Number': h.hashtags_SI_Number, 'name': h.name}
        for h in related_hashtags_qs
    ]
    all_hashtags = [
        {'hashtags_SI_Number': h.hashtags_SI_Number, 'name': h.name}
        for h in all_hashtags_qs
    ]

    return json_response({
        'related_hashtags': related_hashtags,
        'all_hashtags': all_hashtags
    })


# Example view: hashtag_detail
def hashtag_detail(request, slug):
    hashtag = get_object_or_404(HashtagsName, hashtags_SI_Number=slug)
    suggestions = InputSuggestion.objects.filter(hashtags=hashtag).distinct()
    return render(request, 'question_bank/hashtag_detail.html', {
        'hashtag': hashtag,
        'suggestions': suggestions,
    })


# ✅ Add to your views.py or a separate api_views.py
from django.views.decorators.http import require_GET
from .models import SubTopicName
from django.http import JsonResponse

from django.views.decorators.http import require_GET
from django.http import JsonResponse
from .models import SubTopicName

@require_GET
def get_hierarchy_from_shortcode(request):
    """
    Accepts multiple shortcodes via:
      - ?codes[]=CODE1&codes[]=CODE2
      - or ?code=CODE1,CODE2
      - or space separated ?code=CODE1 CODE2
    Returns merged hierarchy lists for multi-select filling.
    """
    # ✅ Collect all codes
    codes = request.GET.getlist('codes[]')
    if not codes:
        code_param = request.GET.get("code", "").strip()
        if code_param:
            codes = [c.strip() for c in code_param.replace(',', ' ').split() if c.strip()]

    if not codes:
        return JsonResponse({'status': 'error', 'message': 'No code(s) provided'}, status=400)

    # ✅ Query subtopics
    subtopics = SubTopicName.objects.select_related(
        'topic__chapter__part__section__area'
    ).filter(sub_topic_short_Code__in=codes)

    if not subtopics.exists():
        return JsonResponse({'status': 'error', 'message': 'No matching subtopics found'}, status=404)

    # ✅ Helper to build unique lists while preserving order
    def unique_list(seq):
        seen = set()
        result = []
        for item in seq:
            if item not in seen:
                seen.add(item)
                result.append(item)
        return result

    # ✅ Build merged lists
    area_ids, area_names = [], []
    section_ids, section_names = [], []
    part_ids, part_names = [], []
    chapter_ids, chapter_names = [], []
    topic_ids, topic_names = [], []
    subtopic_ids, subtopic_names = [], []

    for st in subtopics:
        # Area
        area_ids.append(st.topic.chapter.part.section.area.area_SI_Code)
        area_names.append(st.topic.chapter.part.section.area.name)
        # Section
        section_ids.append(st.topic.chapter.part.section.section_Unit_SI)
        section_names.append(st.topic.chapter.part.section.name)
        # Part
        part_ids.append(st.topic.chapter.part.part_serial)
        part_names.append(st.topic.chapter.part.name)
        # Chapter
        chapter_ids.append(st.topic.chapter.chapter_number)
        chapter_names.append(st.topic.chapter.name)
        # Topic
        topic_ids.append(st.topic.topic_SI_number)
        topic_names.append(st.topic.name)
        # Subtopic
        subtopic_ids.append(st.sub_topic_SI_Number)
        subtopic_names.append(st.name)

    data = {
        'status': 'success',
        'data': {
            'area_ids': unique_list(area_ids),
            'area_names': unique_list(area_names),
            'section_ids': unique_list(section_ids),
            'section_names': unique_list(section_names),
            'part_ids': unique_list(part_ids),
            'part_names': unique_list(part_names),
            'chapter_ids': unique_list(chapter_ids),
            'chapter_names': unique_list(chapter_names),
            'topic_ids': unique_list(topic_ids),
            'topic_names': unique_list(topic_names),
            'subtopic_ids': unique_list(subtopic_ids),
            'subtopic_names': unique_list(subtopic_names),
        }
    }

    return JsonResponse(data)

from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName,
    QuestionBank, ExamName   # ✅ import ExamName
)
import random

@login_required
def add_simple_type_question(request):
    return save_simple_type_question(request)

from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName,
    QuestionBank, ExamName
)
import random

@login_required
def add_simple_type_question(request):
    return save_simple_type_question(request)

@login_required
def save_simple_type_question(request, question=None):
    # ---------- Defaults for preselected data (from shortcode) ----------
    preselected = {
        'area_ids': [],
        'section_ids': [],
        'part_ids': [],
        'chapter_ids': [],
        'topic_ids': [],
        'subtopic_ids': [],
    }

    # Multi-shortcode handling via GET
    codes = request.GET.getlist('codes[]')
    if not codes:
        shortcode_param = (request.GET.get('shortcode') or '').strip()
        if shortcode_param:
            codes = [c.strip() for c in shortcode_param.replace(',', ' ').split() if c.strip()]

    # Preselect hierarchy when editing/adding via shortcode(s)
    if codes:
        subtopics = SubTopicName.objects.select_related(
            'topic__chapter__part__section__area'
        ).filter(sub_topic_short_Code__in=codes)

        if subtopics.exists():
            preselected['area_ids']      = list({st.topic.chapter.part.section.area.area_SI_Code for st in subtopics})
            preselected['section_ids']   = list({st.topic.chapter.part.section.section_Unit_SI for st in subtopics})
            preselected['part_ids']      = list({st.topic.chapter.part.part_serial for st in subtopics})
            preselected['chapter_ids']   = list({st.topic.chapter.chapter_number for st in subtopics})
            preselected['topic_ids']     = list({st.topic.topic_SI_number for st in subtopics})
            preselected['subtopic_ids']  = list({st.sub_topic_SI_Number for st in subtopics})
        else:
            messages.warning(request, "No matching subtopics found for provided shortcode(s).")

    # ---------- Handle POST ----------
    if request.method == "POST":
        try:
            # Core fields
            question_type        = request.POST.get('questionType', 'simple_type')
            languages            = request.POST.getlist('language')
            script               = request.POST.get('script', '')

            # Question text
            question_part_first    = request.POST.get('question_part_first', '')
            question_part_first_hi = request.POST.get('question_part_first_hi', '')

            # Options
            answer_option_a    = request.POST.get('answer_option_a', '')
            answer_option_a_hi = request.POST.get('answer_option_a_hi', '')
            answer_option_b    = request.POST.get('answer_option_b', '')
            answer_option_b_hi = request.POST.get('answer_option_b_hi', '')
            answer_option_c    = request.POST.get('answer_option_c', '')
            answer_option_c_hi = request.POST.get('answer_option_c_hi', '')
            answer_option_d    = request.POST.get('answer_option_d', '')
            answer_option_d_hi = request.POST.get('answer_option_d_hi', '')

            # Answer meta
            correct_answer_choice        = request.POST.get('correct_answer_choice', '')
            correct_answer_description   = request.POST.get('correct_answer_description', '')
            correct_answer_description_hi= request.POST.get('correct_answer_description_hi', '')

            # Hierarchy (accept both legacy & new names for subtopic)
            area_ids     = request.POST.getlist('area_name[]')
            section_ids  = request.POST.getlist('section_name[]')
            part_ids     = request.POST.getlist('part_name[]')
            chapter_ids  = request.POST.getlist('chapter_name[]')
            topic_ids    = request.POST.getlist('topic_name[]')
            subtopic_ids = request.POST.getlist('subtopic_name[]') or request.POST.getlist('sub_topic_name[]')

            # Exams
            exam_ids = request.POST.getlist('exam_name[]')

            # Scoring / meta
            marks                 = float(request.POST.get('marks') or 0.0)
            negative_marks        = float(request.POST.get('negative_marks') or 0.0)
            degree_of_difficulty  = (request.POST.get('degree_of_difficulty') or '').strip()
            elim_tactics_degree   = (request.POST.get('elim_tactics_degree') or '').strip()
            # evergreen_index       = (request.POST.get('evergreen_index') or '').strip()
            current_relevance     = (request.POST.get('current_relevance') or '').strip()
            current_relevance_topic = request.POST.get('current_relevance_topic', '')

            # Source | type_of_question
            source = (request.POST.get('question_type_source') or '').strip()
            if source in ('pyq', 'osq'):
                type_of_question = source
            else:
                # treat anything else (incl. 'modern') as MO(Q)
                type_of_question = 'moq'

            # Exam year (optional int)
            exam_year_raw = request.POST.get('exam_year')
            if exam_year_raw in (None, '', 'null'):
                exam_year = None
            else:
                try:
                    exam_year = int(exam_year_raw)
                except ValueError:
                    messages.error(request, "Please provide a valid exam year.")
                    return redirect(request.path_info)

            # Basic validation
            if not languages or not question_part_first:
                messages.error(request, "Please fill in all required fields.")
                return redirect(request.path_info)

            # ---------- DB writes ----------
            with transaction.atomic():
                # Resolve M2M querysets
                areas     = Area.objects.filter(area_SI_Code__in=area_ids)
                sections  = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts     = PartName.objects.filter(part_serial__in=part_ids)
                chapters  = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics    = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)
                exams     = ExamName.objects.filter(exam_SI_Number__in=exam_ids)

                # Next question number
                last_q = QuestionBank.objects.order_by('-question_number').first()
                next_question_number = (last_q.question_number + 1) if last_q else 1

                # Unique base_question_id
                while True:
                    base_question_id = random.randint(100000, 999999)
                    if not QuestionBank.objects.filter(base_question_id=base_question_id).exists():
                        break

                created_questions = []

                for lang in languages:
                    is_en = (lang == 'e')
                    is_hi = (lang == 'h')

                    q = QuestionBank.objects.create(
                        question_number=next_question_number,
                        question_sub_type=question_type,
                        base_question_id=base_question_id,
                        language=lang,
                        script=script,

                        # Question text (per language)
                        question_part_first = question_part_first if is_en else '',
                        question_part_first_hi = question_part_first_hi if is_hi else '',

                        # Options (per language)
                        answer_option_a = answer_option_a if is_en else '',
                        answer_option_a_hi = answer_option_a_hi if is_hi else '',
                        answer_option_b = answer_option_b if is_en else '',
                        answer_option_b_hi = answer_option_b_hi if is_hi else '',
                        answer_option_c = answer_option_c if is_en else '',
                        answer_option_c_hi = answer_option_c_hi if is_hi else '',
                        answer_option_d = answer_option_d if is_en else '',
                        answer_option_d_hi = answer_option_d_hi if is_hi else '',

                        # Answers
                        correct_answer_choice = correct_answer_choice,
                        correct_answer_description = correct_answer_description if is_en else '',
                        correct_answer_description_hi = correct_answer_description_hi if is_hi else '',

                        # Scoring/meta
                        marks=marks,
                        negative_marks=negative_marks,
                        degree_of_difficulty=degree_of_difficulty,
                        elim_tactics_degree=elim_tactics_degree,
                        # evergreen_index=evergreen_index,
                        current_relevance=current_relevance,
                        current_relevance_topic=current_relevance_topic,
                        exam_year=exam_year,

                        # Source
                        type_of_question=type_of_question,

                        created_by=request.user,
                    )

                    # Set M2M
                    q.area_name.set(areas)
                    q.section_name.set(sections)
                    q.part_name.set(parts)
                    q.chapter_name.set(chapters)
                    q.topic_name.set(topics)
                    q.subtopic_name.set(subtopics)
                    q.exam_name.set(exams)

                    created_questions.append(q)

                messages.success(request, "Question(s) added successfully!")
                return redirect('view_questions')

        except Exception as e:
            messages.error(request, f"An error occurred: {e}")
            return redirect(request.path_info)

    # ---------- Render form (GET) ----------
    template = 'question_bank/add_question/simple_type_form.html'
    return render(request, template, {
        'question': question,
        'areas': Area.objects.all(),
        'sections': Section.objects.all(),
        'parts': PartName.objects.all(),
        'chapters': ChapterName.objects.all(),
        'topics': TopicName.objects.all(),
        'subtopics': SubTopicName.objects.all(),
        **preselected,  # Preselect values based on shortcode if passed
    })



# ************************* Edit Simple Type Question Start *********************************************
from django.shortcuts import get_object_or_404, render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName, QuestionBank
)

@login_required
def edit_simple_type_question(request, pk):
    english_q = get_object_or_404(QuestionBank, pk=pk, language='e')
    hindi_q = QuestionBank.objects.filter(base_question_id=english_q.base_question_id, language='h').first()

    areas = Area.objects.all()
    sections = Section.objects.all()
    parts = PartName.objects.all()
    chapters = ChapterName.objects.all()
    topics = TopicName.objects.all()
    subtopics = SubTopicName.objects.all()
    exams = ExamName.objects.all()

    if request.method == "POST":
        try:
            with transaction.atomic():
                question_type = request.POST.get('questionType', 'simple_type')
                script = request.POST.get('script', '')

                question_part_first = request.POST.get('question_part_first', '')
                question_part_first_hi = request.POST.get('question_part_first_hi', '')

                answer_option_a = request.POST.get('answer_option_a', '')
                answer_option_a_hi = request.POST.get('answer_option_a_hi', '')

                answer_option_b = request.POST.get('answer_option_b', '')
                answer_option_b_hi = request.POST.get('answer_option_b_hi', '')

                answer_option_c = request.POST.get('answer_option_c', '')
                answer_option_c_hi = request.POST.get('answer_option_c_hi', '')

                answer_option_d = request.POST.get('answer_option_d', '')
                answer_option_d_hi = request.POST.get('answer_option_d_hi', '')

                correct_answer_choice = request.POST.get('correct_answer_choice', '')
                correct_answer_description = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi = request.POST.get('correct_answer_description_hi', '')

                area_ids = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids = request.POST.getlist('topic_name[]')
                subtopic_ids = request.POST.getlist('sub_topic_name[]')
                exam_ids = request.POST.getlist('exam_name[]')

                new_topic_name = request.POST.get('new_topic_name', None)

                marks = float(request.POST.get('marks') or 0.0)
                negative_marks = float(request.POST.get('negative_marks') or 0.0)
                degree_of_difficulty = request.POST.get('degree_of_difficulty', '')
                evergreen_index = request.POST.get('evergreen_index', '')
                new_or_pyq = request.POST.get('new_or_pyq', '')

                current_relevance = request.POST.get('current_relevance', '')
                current_relevance_topic = request.POST.get('current_relevance_topic', '')
                exam_year = request.POST.get('exam_year') or None

                # ✅ New topic creation if 'other' selected
                if 'other' in topic_ids:
                    topic_ids.remove('other')
                    if new_topic_name and chapter_ids:
                        selected_chapter = ChapterName.objects.get(chapter_number=chapter_ids[0])
                        new_topic = TopicName.objects.create(name=new_topic_name, chapter=selected_chapter)
                        topic_ids.append(new_topic.topic_SI_number)

                # ✅ Related M2M
                areas_qs = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)
                exams_qs = ExamName.objects.filter(exam_SI_Number__in=exam_ids)

                # ✅ Update English version
                english_q.script = script
                english_q.question_sub_type = question_type
                english_q.question_part_first = question_part_first
                english_q.answer_option_a = answer_option_a
                english_q.answer_option_b = answer_option_b
                english_q.answer_option_c = answer_option_c
                english_q.answer_option_d = answer_option_d
                english_q.correct_answer_choice = correct_answer_choice
                english_q.correct_answer_description = correct_answer_description
                english_q.marks = marks
                english_q.negative_marks = negative_marks
                english_q.degree_of_difficulty = degree_of_difficulty
                english_q.evergreen_index = evergreen_index
                english_q.exam_year = exam_year
                english_q.new_or_pyq = new_or_pyq
                english_q.current_relevance = current_relevance
                english_q.current_relevance_topic = current_relevance_topic
                english_q.save()

                english_q.area_name.set(areas_qs)
                english_q.section_name.set(sections_qs)
                english_q.part_name.set(parts_qs)
                english_q.chapter_name.set(chapters_qs)
                english_q.topic_name.set(topics_qs)
                english_q.subtopic_name.set(subtopics_qs)
                english_q.exam_name.set(exams_qs)

                # ✅ Update Hindi version if exists
                if hindi_q:
                    hindi_q.script = script
                    hindi_q.question_sub_type = question_type
                    hindi_q.question_part_first_hi = question_part_first_hi
                    hindi_q.answer_option_a_hi = answer_option_a_hi
                    hindi_q.answer_option_b_hi = answer_option_b_hi
                    hindi_q.answer_option_c_hi = answer_option_c_hi
                    hindi_q.answer_option_d_hi = answer_option_d_hi
                    hindi_q.correct_answer_choice = correct_answer_choice
                    hindi_q.correct_answer_description_hi = correct_answer_description_hi
                    hindi_q.marks = marks
                    hindi_q.negative_marks = negative_marks
                    hindi_q.degree_of_difficulty = degree_of_difficulty
                    hindi_q.evergreen_index = evergreen_index
                    hindi_q.exam_year = exam_year
                    hindi_q.new_or_pyq = new_or_pyq
                    hindi_q.current_relevance = current_relevance
                    hindi_q.current_relevance_topic = current_relevance_topic
                    hindi_q.save()

                    hindi_q.area_name.set(areas_qs)
                    hindi_q.section_name.set(sections_qs)
                    hindi_q.part_name.set(parts_qs)
                    hindi_q.chapter_name.set(chapters_qs)
                    hindi_q.topic_name.set(topics_qs)
                    hindi_q.subtopic_name.set(subtopics_qs)
                    hindi_q.exam_name.set(exams_qs)

                messages.success(request, "✅ Simple Type Question updated successfully!")
                return redirect('view_questions')

        except Exception as e:
            messages.error(request, f" An error occurred while editing: {e}")

    context = {
        'english_q': english_q,
        'hindi_q': hindi_q,
        'areas': areas,
        'sections': sections,
        'parts': parts,
        'chapters': chapters,
        'topics': topics,
        'subtopics': subtopics,
        'exams': exams,
        'selected_area_ids': [str(id) for id in english_q.area_name.values_list('area_SI_Code', flat=True)],
        'selected_section_ids': [str(id) for id in english_q.section_name.values_list('section_Unit_SI', flat=True)],
        'selected_part_ids': [str(id) for id in english_q.part_name.values_list('part_serial', flat=True)],
        'selected_chapter_ids': [str(id) for id in english_q.chapter_name.values_list('chapter_number', flat=True)],
        'selected_topic_ids': [str(id) for id in english_q.topic_name.values_list('topic_SI_number', flat=True)],
        'selected_subtopic_ids': [str(id) for id in english_q.subtopic_name.values_list('sub_topic_SI_Number', flat=True)],
        'selected_exam_ids': [str(id) for id in english_q.exam_name.values_list('exam_SI_Number', flat=True)],
        "mark_options": ["0.5", "1.0", "1.5", "2.0", "2.5", "3.0"],
        "negative_mark_options": ["1.0", "0.5", "0.33", "0.25", "0.2", "0"],
        "range_1_to_5": range(1, 6),
    }

    return render(request, 'question_bank/edit_question/edit_simple_type_form.html', context)

# ************************* Edit Simple Type Question End *********************************************

from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect
from django.contrib import messages
from django.db import transaction
from .models import QuestionBank

# ************************* DELETE Simple Type Question *********************************************
@login_required
def delete_simple_type_question(request, pk):
    try:
        english_q = get_object_or_404(QuestionBank, pk=pk, language='e')
        hindi_q = QuestionBank.objects.filter(base_question_id=english_q.base_question_id, language='h').first()

        with transaction.atomic():
            if hindi_q:
                hindi_q.delete()
            english_q.delete()

        messages.success(request, "Simple Type Question deleted successfully!")
    except Exception as e:
        messages.error(request, f"An error occurred while deleting Simple Type Question: {e}")

    return redirect('view_questions')

# ************************* DELETE R and A Type Question *********************************************
@login_required
def delete_r_and_a_type_question(request, pk):
    try:
        english_q = get_object_or_404(QuestionBank, pk=pk, language='e')
        hindi_q = QuestionBank.objects.filter(base_question_id=english_q.base_question_id, language='h').first()

        with transaction.atomic():
            if hindi_q:
                hindi_q.delete()
            english_q.delete()

        messages.success(request, "R and A Type Question deleted successfully!")
    except Exception as e:
        messages.error(request, f"An error occurred while deleting R and A Type Question: {e}")

    return redirect('view_questions')

# ************************* DELETE List Type 1 Question *********************************************
@login_required
def delete_list_type_1_question(request, pk):
    try:
        english_q = get_object_or_404(QuestionBank, pk=pk, language='e')
        hindi_q = QuestionBank.objects.filter(base_question_id=english_q.base_question_id, language='h').first()

        with transaction.atomic():
            if hindi_q:
                hindi_q.delete()
            english_q.delete()

        messages.success(request, "List Type 1 Question deleted successfully!")
    except Exception as e:
        messages.error(request, f"An error occurred while deleting List Type 1 Question: {e}")

    return redirect('view_questions')

# ************************* DELETE List Type 2 Question *********************************************
@login_required
def delete_list_type_2_question(request, pk):
    try:
        english_q = get_object_or_404(QuestionBank, pk=pk, language='e')
        hindi_q = QuestionBank.objects.filter(base_question_id=english_q.base_question_id, language='h').first()

        with transaction.atomic():
            if hindi_q:
                hindi_q.delete()
            english_q.delete()

        messages.success(request, "List Type 2 Question deleted successfully!")
    except Exception as e:
        messages.error(request, f"An error occurred while deleting List Type 2 Question: {e}")

    return redirect('view_questions')

# ************************* DELETE True and False Type Question *********************************************
@login_required
def delete_true_and_false_type_question(request, pk):
    try:
        english_q = get_object_or_404(QuestionBank, pk=pk, language='e')
        hindi_q = QuestionBank.objects.filter(base_question_id=english_q.base_question_id, language='h').first()

        with transaction.atomic():
            if hindi_q:
                hindi_q.delete()
            english_q.delete()

        messages.success(request, "True and False Type Question deleted successfully!")
    except Exception as e:
        messages.error(request, f"An error occurred while deleting True and False Type Question: {e}")

    return redirect('view_questions')

# ************************* DELETE Fill in the Blank Type Question *********************************************
@login_required
def delete_fill_in_the_blank_question(request, pk):
    try:
        english_q = get_object_or_404(QuestionBank, pk=pk, language='e')
        hindi_q = QuestionBank.objects.filter(base_question_id=english_q.base_question_id, language='h').first()

        with transaction.atomic():
            if hindi_q:
                hindi_q.delete()
            english_q.delete()

        messages.success(request, "Fill in the Blank Type Question deleted successfully!")
    except Exception as e:
        messages.error(request, f"An error occurred while deleting Fill in the Blank Type Question: {e}")

    return redirect('view_questions')






# ************************* Create R and A Type Question Start *************************
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName, QuestionBank
)
import random

@login_required
def add_r_and_a_type_question(request, question=None):
    # ---------- Defaults for preselected data (from shortcode) ----------
    preselected = {
        'area_ids': [], 'section_ids': [], 'part_ids': [],
        'chapter_ids': [], 'topic_ids': [], 'subtopic_ids': [], 'exam_ids': []
    }

    # Multi-shortcode handling via GET
    codes = request.GET.getlist('codes[]')
    if not codes:
        shortcode_param = (request.GET.get('shortcode') or '').strip()
        if shortcode_param:
            codes = [c.strip() for c in shortcode_param.replace(',', ' ').split() if c.strip()]

    # Preselect hierarchy when adding via shortcode(s)
    if codes:
        subtopics = SubTopicName.objects.select_related(
            'topic__chapter__part__section__area'
        ).filter(sub_topic_short_Code__in=codes)

        if subtopics.exists():
            preselected['area_ids']     = list({st.topic.chapter.part.section.area.area_SI_Code for st in subtopics})
            preselected['section_ids']  = list({st.topic.chapter.part.section.section_Unit_SI for st in subtopics})
            preselected['part_ids']     = list({st.topic.chapter.part.part_serial for st in subtopics})
            preselected['chapter_ids']  = list({st.topic.chapter.chapter_number for st in subtopics})
            preselected['topic_ids']    = list({st.topic.topic_SI_number for st in subtopics})
            preselected['subtopic_ids'] = list({st.sub_topic_SI_Number for st in subtopics})
        else:
            messages.warning(request, "No matching subtopics found for provided shortcode(s).")

    # ---------- Handle POST ----------
    if request.method == "POST":
        try:
            # Hierarchy (accept both legacy & new names for subtopic)
            area_ids     = request.POST.getlist('area_name[]')
            section_ids  = request.POST.getlist('section_name[]')
            part_ids     = request.POST.getlist('part_name[]')
            chapter_ids  = request.POST.getlist('chapter_name[]')
            topic_ids    = request.POST.getlist('topic_name[]')
            subtopic_ids = request.POST.getlist('subtopic_name[]') or request.POST.getlist('sub_topic_name[]')
            exam_ids     = request.POST.getlist('exam_name[]')

            languages = request.POST.getlist('language')

            # Question content
            script                = request.POST.get('script', '')
            question_part_first   = request.POST.get('question_part_first', '')
            question_part_first_hi= request.POST.get('question_part_first_hi', '')
            assertion             = request.POST.get('assertion', '')
            assertion_hi          = request.POST.get('assertion_hi', '')
            reason                = request.POST.get('reason', '')
            reason_hi             = request.POST.get('reason_hi', '')

            # Options & answers
            correct_answer_choice        = request.POST.get('correct_answer_choice', '')
            correct_answer_description   = request.POST.get('correct_answer_description', '')
            correct_answer_description_hi= request.POST.get('correct_answer_description_hi', '')

            answer_option_a    = request.POST.get('answer_option_a', '')
            answer_option_b    = request.POST.get('answer_option_b', '')
            answer_option_c    = request.POST.get('answer_option_c', '')
            answer_option_d    = request.POST.get('answer_option_d', '')
            answer_option_a_hi = request.POST.get('answer_option_a_hi', '')
            answer_option_b_hi = request.POST.get('answer_option_b_hi', '')
            answer_option_c_hi = request.POST.get('answer_option_c_hi', '')
            answer_option_d_hi = request.POST.get('answer_option_d_hi', '')

            # Scoring / meta
            marks                = float(request.POST.get('marks') or 0)
            negative_marks       = float(request.POST.get('negative_marks') or 0)
            degree_of_difficulty = (request.POST.get('degree_of_difficulty') or '').strip()
            elim_tactics_degree  = (request.POST.get('elim_tactics_degree') or '').strip()
            # evergreen_index      = (request.POST.get('evergreen_index') or '').strip()

            # Source | type_of_question
            question_type_source = (request.POST.get('question_type_source') or '').strip()
            if question_type_source in ('pyq', 'osq'):
                type_of_question = question_type_source
            else:
                type_of_question = 'moq'

            # Current relevance
            current_relevance       = (request.POST.get('current_relevance') or '').strip()
            current_relevance_topic = request.POST.get('current_relevance_topic', '')

            # Exam year (optional int)
            exam_year_raw = request.POST.get('exam_year')
            if exam_year_raw in (None, '', 'null'):
                exam_year = None
            else:
                try:
                    exam_year = int(exam_year_raw)
                except ValueError:
                    messages.error(request, "Please provide a valid exam year.")
                    return redirect(request.path_info)

            # Basic validation
            if not languages or not question_part_first:
                messages.error(request, "Please fill in all required fields.")
                return redirect(request.path_info)

            # ---------- DB writes ----------
            with transaction.atomic():
                # Resolve M2M querysets
                areas_qs     = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs  = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs     = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs  = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs    = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)
                exams_qs     = ExamName.objects.filter(exam_SI_Number__in=exam_ids)

                # Unique IDs
                while True:
                    base_question_id = random.randint(100000, 999999)
                    if not QuestionBank.objects.filter(base_question_id=base_question_id).exists():
                        break

                last_q = QuestionBank.objects.order_by('-question_number').first()
                next_question_number = last_q.question_number + 1 if last_q else 1

                # Create per-language rows
                for lang in languages:
                    is_en = (lang == 'e')
                    is_hi = (lang == 'h')

                    q = QuestionBank.objects.create(
                        question_number=next_question_number,
                        base_question_id=base_question_id,
                        question_sub_type='r_and_a_type',
                        language=lang,
                        script=script,

                        # Content (per language)
                        question_part_first   = question_part_first if is_en else '',
                        question_part_first_hi= question_part_first_hi if is_hi else '',
                        assertion             = assertion if is_en else '',
                        assertion_hi          = assertion_hi if is_hi else '',
                        reason                = reason if is_en else '',
                        reason_hi             = reason_hi if is_hi else '',

                        # Options (per language)
                        answer_option_a    = answer_option_a if is_en else '',
                        answer_option_b    = answer_option_b if is_en else '',
                        answer_option_c    = answer_option_c if is_en else '',
                        answer_option_d    = answer_option_d if is_en else '',
                        answer_option_a_hi = answer_option_a_hi if is_hi else '',
                        answer_option_b_hi = answer_option_b_hi if is_hi else '',
                        answer_option_c_hi = answer_option_c_hi if is_hi else '',
                        answer_option_d_hi = answer_option_d_hi if is_hi else '',

                        # Answers
                        correct_answer_choice        = correct_answer_choice,
                        correct_answer_description   = correct_answer_description if is_en else '',
                        correct_answer_description_hi= correct_answer_description_hi if is_hi else '',

                        # Scoring / meta
                        marks=marks,
                        negative_marks=negative_marks,
                        degree_of_difficulty=degree_of_difficulty,
                        elim_tactics_degree=elim_tactics_degree,
                        # evergreen_index=evergreen_index,
                        current_relevance=current_relevance,
                        current_relevance_topic=current_relevance_topic,  # store same text for both langs
                        exam_year=exam_year,

                        # Source
                        type_of_question=type_of_question,

                        created_by=request.user
                    )

                    # M2M sets
                    q.area_name.set(areas_qs)
                    q.section_name.set(sections_qs)
                    q.part_name.set(parts_qs)
                    q.chapter_name.set(chapters_qs)
                    q.topic_name.set(topics_qs)
                    q.subtopic_name.set(subtopics_qs)
                    q.exam_name.set(exams_qs)

            messages.success(request, "✅ R & A Type Question saved successfully!")
            return redirect('add-r-and-a-type-question')

        except Exception as e:
            messages.error(request, f"  Error: {e}")

    # ---------- Render (GET) ----------
    context = {
        'areas': Area.objects.all(),
        'sections': Section.objects.all(),
        'parts': PartName.objects.all(),
        'chapters': ChapterName.objects.all(),
        'topics': TopicName.objects.all(),
        'subtopics': SubTopicName.objects.all(),
        'exams': ExamName.objects.all(),
        **preselected,
    }
    return render(request, 'question_bank/add_question/r_and_a_type_form.html', context)
# ************************* Create R and A Type Question End *************************






# ************************* Edit R and A Type Question Start *********************************************
from django.shortcuts import get_object_or_404, render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName, QuestionBank
)

@login_required
def edit_r_and_a_type_question(request, pk):
    english_q = get_object_or_404(QuestionBank, pk=pk, language='e')
    hindi_q = QuestionBank.objects.filter(base_question_id=english_q.base_question_id, language='h').first()

    areas = Area.objects.all()
    sections = Section.objects.all()
    parts = PartName.objects.all()
    chapters = ChapterName.objects.all()
    topics = TopicName.objects.all()
    subtopics = SubTopicName.objects.all()
    exams = ExamName.objects.all()

    if request.method == 'POST':
        try:
            with transaction.atomic():
                # ✅ IDs
                area_ids = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids = request.POST.getlist('topic_name[]')
                subtopic_ids = request.POST.getlist('sub_topic_name[]')
                exam_ids = request.POST.getlist('exam_name[]')
                new_topic_name = request.POST.get('new_topic_name', None)

                # ✅ Fields
                script = request.POST.get('script', '')
                question_part_first = request.POST.get('question_part_first', '')
                question_part_first_hi = request.POST.get('question_part_first_hi', '')

                reason = request.POST.get('reason', '')
                reason_hi = request.POST.get('reason_hi', '')
                assertion = request.POST.get('assertion', '')
                assertion_hi = request.POST.get('assertion_hi', '')
                question_part_third = request.POST.get('question_part_third', '')
                question_part_third_hi = request.POST.get('question_part_third_hi', '')

                correct_answer_choice = request.POST.get('correct_answer_choice', '')
                correct_answer_description = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi = request.POST.get('correct_answer_description_hi', '')

                answer_option_a = request.POST.get('answer_option_a', '')
                answer_option_a_hi = request.POST.get('answer_option_a_hi', '')
                answer_option_b = request.POST.get('answer_option_b', '')
                answer_option_b_hi = request.POST.get('answer_option_b_hi', '')
                answer_option_c = request.POST.get('answer_option_c', '')
                answer_option_c_hi = request.POST.get('answer_option_c_hi', '')
                answer_option_d = request.POST.get('answer_option_d', '')
                answer_option_d_hi = request.POST.get('answer_option_d_hi', '')

                marks = float(request.POST.get('marks') or 0.0)
                negative_marks = float(request.POST.get('negative_marks') or 0.0)
                degree_of_difficulty = request.POST.get('degree_of_difficulty', '')
                evergreen_index = request.POST.get('evergreen_index', '')
                current_relevance = request.POST.get('current_relevance', '')
                current_relevance_topic = request.POST.get('current_relevance_topic', '')
                exam_year = request.POST.get('exam_year') or None

                # ✅ New topic if 'other'
                if 'other' in topic_ids:
                    topic_ids.remove('other')
                    if new_topic_name and chapter_ids:
                        selected_chapter = ChapterName.objects.get(chapter_number=chapter_ids[0])
                        new_topic = TopicName.objects.create(name=new_topic_name, chapter=selected_chapter)
                        topic_ids.append(new_topic.topic_SI_number)

                # ✅ Related objects
                areas_qs = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)
                exams_qs = ExamName.objects.filter(exam_SI_Number__in=exam_ids)

                # ✅ Update English
                english_q.script = script
                english_q.question_part_first = question_part_first
                english_q.reason = reason
                english_q.assertion = assertion
                english_q.question_part_third = question_part_third
                english_q.correct_answer_choice = correct_answer_choice
                english_q.correct_answer_description = correct_answer_description
                english_q.answer_option_a = answer_option_a
                english_q.answer_option_b = answer_option_b
                english_q.answer_option_c = answer_option_c
                english_q.answer_option_d = answer_option_d
                english_q.marks = marks
                english_q.negative_marks = negative_marks
                english_q.degree_of_difficulty = degree_of_difficulty
                english_q.evergreen_index = evergreen_index
                english_q.exam_year = exam_year
                english_q.current_relevance = current_relevance
                english_q.current_relevance_topic = current_relevance_topic
                english_q.save()

                english_q.area_name.set(areas_qs)
                english_q.section_name.set(sections_qs)
                english_q.part_name.set(parts_qs)
                english_q.chapter_name.set(chapters_qs)
                english_q.topic_name.set(topics_qs)
                english_q.subtopic_name.set(subtopics_qs)
                english_q.exam_name.set(exams_qs)

                # ✅ Update Hindi
                if hindi_q:
                    hindi_q.script = script
                    hindi_q.question_part_first_hi = question_part_first_hi
                    hindi_q.reason_hi = reason_hi
                    hindi_q.assertion_hi = assertion_hi
                    hindi_q.question_part_third_hi = question_part_third_hi
                    hindi_q.correct_answer_choice = correct_answer_choice
                    hindi_q.correct_answer_description_hi = correct_answer_description_hi
                    hindi_q.answer_option_a_hi = answer_option_a_hi
                    hindi_q.answer_option_b_hi = answer_option_b_hi
                    hindi_q.answer_option_c_hi = answer_option_c_hi
                    hindi_q.answer_option_d_hi = answer_option_d_hi
                    hindi_q.marks = marks
                    hindi_q.negative_marks = negative_marks
                    hindi_q.degree_of_difficulty = degree_of_difficulty
                    hindi_q.evergreen_index = evergreen_index
                    hindi_q.exam_year = exam_year
                    hindi_q.current_relevance = current_relevance
                    hindi_q.current_relevance_topic = current_relevance_topic
                    hindi_q.save()

                    hindi_q.area_name.set(areas_qs)
                    hindi_q.section_name.set(sections_qs)
                    hindi_q.part_name.set(parts_qs)
                    hindi_q.chapter_name.set(chapters_qs)
                    hindi_q.topic_name.set(topics_qs)
                    hindi_q.subtopic_name.set(subtopics_qs)
                    hindi_q.exam_name.set(exams_qs)

                messages.success(request, "✅ R & A Type Question updated successfully!")
                return redirect('view_questions')

        except Exception as e:
            messages.error(request, f"  An error occurred while editing: {e}")

    context = {
        'english_q': english_q,
        'hindi_q': hindi_q,
        'areas': areas,
        'sections': sections,
        'parts': parts,
        'chapters': chapters,
        'topics': topics,
        'subtopics': subtopics,
        'exams': exams,
        'selected_area_ids': [str(id) for id in english_q.area_name.values_list('area_SI_Code', flat=True)],
        'selected_section_ids': [str(id) for id in english_q.section_name.values_list('section_Unit_SI', flat=True)],
        'selected_part_ids': [str(id) for id in english_q.part_name.values_list('part_serial', flat=True)],
        'selected_chapter_ids': [str(id) for id in english_q.chapter_name.values_list('chapter_number', flat=True)],
        'selected_topic_ids': [str(id) for id in english_q.topic_name.values_list('topic_SI_number', flat=True)],
        'selected_subtopic_ids': [str(id) for id in english_q.subtopic_name.values_list('sub_topic_SI_Number', flat=True)],
        'selected_exam_ids': [str(id) for id in english_q.exam_name.values_list('exam_SI_Number', flat=True)],
        "mark_options": ["0.5", "1.0", "1.5", "2.0", "2.5", "3.0"],
        "negative_mark_options": ["1.0", "0.5", "0.33", "0.25", "0.2", "0"],
        "range_1_to_5": range(1, 6),
    }

    return render(request, 'question_bank/edit_question/edit_r_and_a_type_form.html', context)
# ************************* Edit R and A Type Question End *********************************************





# ************************* Create List-I Type Question Start *************************
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName, QuestionBank
)
import random

@login_required
def add_list_type_1_question(request):
    context = {
        'areas': Area.objects.all(),
        'sections': Section.objects.all(),
        'parts': PartName.objects.all(),
        'chapters': ChapterName.objects.all(),
        'topics': TopicName.objects.all(),
        'subtopics': SubTopicName.objects.all(),
    }

    if request.method == 'POST':
        try:
            with transaction.atomic():
                # ----- Hierarchy selections -----
                area_ids    = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids    = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids   = request.POST.getlist('topic_name[]')

                # ✅ Accept both legacy and new param names for subtopics
                subtopic_ids = request.POST.getlist('sub_topic_name[]') or request.POST.getlist('subtopic_name[]')
                subtopic_ids = [str(s).strip() for s in subtopic_ids if str(s).strip()]

                # ✅ Exams (M2M)
                exam_ids = [str(x).strip() for x in request.POST.getlist('exam_name[]') if str(x).strip()]

                new_topic_name = request.POST.get('new_topic_name')
                script = request.POST.get('script', '')

                # Validate/parse exam year
                exam_year_raw = request.POST.get('exam_year')
                if exam_year_raw in (None, '', 'null'):
                    exam_year = None
                else:
                    try:
                        exam_year = int(exam_year_raw)
                    except ValueError:
                        messages.error(request, "Please provide a valid exam year.")
                        return redirect(request.path_info)

                # ----- Stems / text -----
                question_part_first     = request.POST.get('question_part_first', '')
                question_part_first_hi  = request.POST.get('question_part_first_hi', '')
                question_part_third     = request.POST.get('question_part_third', '')
                question_part_third_hi  = request.POST.get('question_part_third_hi', '')

                # ----- Answers -----
                correct_answer_choice        = request.POST.get('correct_answer_choice', '')
                correct_answer_description   = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi= request.POST.get('correct_answer_description_hi', '')

                # ----- Meta -----
                marks                 = float(request.POST.get('marks') or 0.0)
                negative_marks        = float(request.POST.get('negative_marks') or 0.0)
                degree_of_difficulty  = (request.POST.get('degree_of_difficulty') or '').strip()
                elim_tactics_degree   = (request.POST.get('elim_tactics_degree') or '').strip()  # ✅ NEW
                evergreen_index       = (request.POST.get('evergreen_index') or '').strip()
                question_type_source  = (request.POST.get('question_type_source') or 'modern').strip()
                current_relevance     = (request.POST.get('current_relevance') or '').strip()
                current_relevance_topic = request.POST.get('current_relevance_topic', '')

                # Map source to type
                if question_type_source == 'pyq':
                    type_of_question = 'pyq'
                elif question_type_source == 'osq':
                    type_of_question = 'osq'
                else:
                    type_of_question = 'moq'

                # ----- M2M QuerySets -----
                areas_qs    = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs    = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs   = TopicName.objects.filter(topic_SI_number__in=topic_ids)

                # Handle new topic creation if "other" selected
                if 'other' in topic_ids and new_topic_name and chapter_ids:
                    topic_ids.remove('other')
                    selected_chapter = ChapterName.objects.get(chapter_number=chapter_ids[0])
                    new_topic = TopicName.objects.create(name=new_topic_name, chapter=selected_chapter)
                    topic_ids.append(str(new_topic.topic_SI_number))

                # Refresh topics after potential creation
                topics_qs = TopicName.objects.filter(topic_SI_number__in=topic_ids)

                # ✅ Subtopics queryset (works with either param name)
                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)

                # ✅ Exams queryset
                exams_qs = ExamName.objects.filter(exam_SI_Number__in=exam_ids)

                # Guard — if you require subtopics
                if not subtopics_qs.exists():
                    messages.error(request, "Please choose at least one Sub Topic.")
                    return redirect(request.path_info)

                # ----- IDs / numbering -----
                while True:
                    base_question_id = random.randint(100000, 999999)
                    if not QuestionBank.objects.filter(base_question_id=base_question_id).exists():
                        break

                last_q = QuestionBank.objects.order_by('-question_number').first()
                next_question_number = last_q.question_number + 1 if last_q else 1

                # ----- List items (List-I) -----
                list_items = {}
                for i in range(1, 9):
                    list_items[f"list_1_row{i}"]    = request.POST.get(f"list_1_row{i}", '')
                    list_items[f"list_1_row{i}_hi"] = request.POST.get(f"list_1_row{i}_hi", '')

                # ----- Options A-D -----
                answer_options = {}
                for opt in 'abcd':
                    answer_options[f"answer_option_{opt}"]     = request.POST.get(f"answer_option_{opt}", '')
                    answer_options[f"answer_option_{opt}_hi"]  = request.POST.get(f"answer_option_{opt}_hi", '')

                # ----- Create English question -----
                question_en = QuestionBank.objects.create(
                    question_number=next_question_number,
                    base_question_id=base_question_id,
                    question_sub_type='list_type_1',
                    type_of_question=type_of_question,
                    language='e',
                    script=script,
                    question_part_first=question_part_first,
                    question_part_third=question_part_third,
                    correct_answer_choice=correct_answer_choice,
                    correct_answer_description=correct_answer_description,
                    marks=marks,
                    negative_marks=negative_marks,
                    degree_of_difficulty=degree_of_difficulty,
                    elim_tactics_degree=elim_tactics_degree,  # ✅ NEW
                    evergreen_index=evergreen_index,
                    exam_year=exam_year,
                    current_relevance=current_relevance,
                    current_relevance_topic=current_relevance_topic,
                    created_by=request.user,
                    **{f"list_1_row{i}": list_items[f"list_1_row{i}"] for i in range(1, 9)},
                    **{f"answer_option_{opt}": answer_options[f"answer_option_{opt}"] for opt in 'abcd'},
                )
                # M2M sets (subtopics + exams included)
                question_en.area_name.set(areas_qs)
                question_en.section_name.set(sections_qs)
                question_en.part_name.set(parts_qs)
                question_en.chapter_name.set(chapters_qs)
                question_en.topic_name.set(topics_qs)
                question_en.subtopic_name.set(subtopics_qs)
                question_en.exam_name.set(exams_qs)  # ✅ NEW

                # ----- Create Hindi question -----
                question_hi = QuestionBank.objects.create(
                    question_number=next_question_number,
                    base_question_id=base_question_id,
                    question_sub_type='list_type_1',
                    type_of_question=type_of_question,
                    language='h',
                    script=script,
                    question_part_first_hi=question_part_first_hi,
                    question_part_third_hi=question_part_third_hi,
                    correct_answer_choice=correct_answer_choice,
                    correct_answer_description_hi=correct_answer_description_hi,
                    marks=marks,
                    negative_marks=negative_marks,
                    degree_of_difficulty=degree_of_difficulty,
                    elim_tactics_degree=elim_tactics_degree,  # ✅ NEW
                    evergreen_index=evergreen_index,
                    exam_year=exam_year,
                    current_relevance=current_relevance,
                    current_relevance_topic=current_relevance_topic,
                    created_by=request.user,
                    **{f"list_1_row{i}_hi": list_items[f"list_1_row{i}_hi"] for i in range(1, 9)},
                    **{f"answer_option_{opt}_hi": answer_options[f"answer_option_{opt}_hi"] for opt in 'abcd'},
                )
                question_hi.area_name.set(areas_qs)
                question_hi.section_name.set(sections_qs)
                question_hi.part_name.set(parts_qs)
                question_hi.chapter_name.set(chapters_qs)
                question_hi.topic_name.set(topics_qs)
                question_hi.subtopic_name.set(subtopics_qs)
                question_hi.exam_name.set(exams_qs)  # ✅ NEW

                messages.success(request, '✅ List-I Type Question saved successfully!')
                return redirect('add-list-type-1-question')

        except Exception as e:
            messages.error(request, f'  An error occurred: {str(e)}')

    return render(request, 'question_bank/add_question/list_type_1_form.html', context)
# ************************* Create List-I Type Question End *************************






# ************************* Edit List-I Type Question Updated *********************************************
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName, QuestionBank
)

@login_required
def edit_list_type_1_question(request, pk):
    english_q = get_object_or_404(QuestionBank, pk=pk, language='e')
    hindi_q = QuestionBank.objects.filter(
        base_question_id=english_q.base_question_id, language='h'
    ).first()

    areas = Area.objects.all()
    sections = Section.objects.all()
    parts = PartName.objects.all()
    chapters = ChapterName.objects.all()
    topics = TopicName.objects.all()
    subtopics = SubTopicName.objects.all()
    exams = ExamName.objects.all()  # ✅ include exams for select

    if request.method == 'POST':
        try:
            with transaction.atomic():
                # ===== Basic fields =====
                script = request.POST.get('script', '')
                exam_year = request.POST.get('exam_year') or None

                question_part_first = request.POST.get('question_part_first', '')
                question_part_first_hi = request.POST.get('question_part_first_hi', '')
                question_part_third = request.POST.get('question_part_third', '')
                question_part_third_hi = request.POST.get('question_part_third_hi', '')

                correct_answer_choice = request.POST.get('correct_answer_choice', '')
                correct_answer_description = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi = request.POST.get('correct_answer_description_hi', '')

                marks = float(request.POST.get('marks') or 0.0)
                negative_marks = float(request.POST.get('negative_marks') or 0.0)

                # ✅ Difficulty & Elimination tactics (CharFields)
                degree_of_difficulty = (request.POST.get('degree_of_difficulty') or '').strip()
                elim_tactics_degree = (request.POST.get('elim_tactics_degree') or '').strip()

                # ✅ Current relevance (parity with Simple Type)
                current_relevance = (request.POST.get('current_relevance') or '').strip()
                current_relevance_topic = request.POST.get('current_relevance_topic', '')

                evergreen_index = request.POST.get('evergreen_index', '')
                type_of_question = (request.POST.get('question_type_source') or '').strip()

                # ===== Answer options and list items =====
                answer_options = {
                    f"answer_option_{opt}": request.POST.get(f"answer_option_{opt}", '')
                    for opt in "abcd"
                }
                answer_options_hi = {
                    f"answer_option_{opt}_hi": request.POST.get(f"answer_option_{opt}_hi", '')
                    for opt in "abcd"
                }

                list_items = {f"list_1_row{i}": request.POST.get(f"list_1_row{i}", '') for i in range(1, 9)}
                list_items_hi = {f"list_1_row{i}_hi": request.POST.get(f"list_1_row{i}_hi", '') for i in range(1, 9)}

                # ===== Relationships =====
                area_ids = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids = request.POST.getlist('topic_name[]')
                subtopic_ids = request.POST.getlist('sub_topic_name[]')
                exam_ids = request.POST.getlist('exam_name[]')  # ✅ exams

                areas_qs = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)
                exams_qs = ExamName.objects.filter(exam_SI_Number__in=exam_ids)  # ✅

                # ===== Update English =====
                english_q.script = script
                english_q.exam_year = exam_year
                english_q.question_part_first = question_part_first
                english_q.question_part_third = question_part_third
                english_q.correct_answer_choice = correct_answer_choice
                english_q.correct_answer_description = correct_answer_description
                english_q.marks = marks
                english_q.negative_marks = negative_marks
                english_q.degree_of_difficulty = degree_of_difficulty
                english_q.elim_tactics_degree = elim_tactics_degree
                english_q.current_relevance = current_relevance            # ✅
                english_q.current_relevance_topic = current_relevance_topic # ✅
                english_q.evergreen_index = evergreen_index
                english_q.type_of_question = type_of_question

                for k, v in list_items.items():
                    setattr(english_q, k, v)
                for k, v in answer_options.items():
                    setattr(english_q, k, v)

                english_q.save()
                english_q.area_name.set(areas_qs)
                english_q.section_name.set(sections_qs)
                english_q.part_name.set(parts_qs)
                english_q.chapter_name.set(chapters_qs)
                english_q.topic_name.set(topics_qs)
                english_q.subtopic_name.set(subtopics_qs)
                english_q.exam_name.set(exams_qs)  # ✅

                # ===== Update Hindi (if exists) =====
                if hindi_q:
                    hindi_q.script = script
                    hindi_q.exam_year = exam_year
                    hindi_q.question_part_first_hi = question_part_first_hi
                    hindi_q.question_part_third_hi = question_part_third_hi
                    hindi_q.correct_answer_choice = correct_answer_choice
                    hindi_q.correct_answer_description_hi = correct_answer_description_hi
                    hindi_q.marks = marks
                    hindi_q.negative_marks = negative_marks
                    hindi_q.degree_of_difficulty = degree_of_difficulty
                    hindi_q.elim_tactics_degree = elim_tactics_degree
                    hindi_q.current_relevance = current_relevance            # ✅
                    hindi_q.current_relevance_topic = current_relevance_topic # ✅
                    hindi_q.evergreen_index = evergreen_index
                    hindi_q.type_of_question = type_of_question

                    for k, v in list_items_hi.items():
                        setattr(hindi_q, k, v)
                    for k, v in answer_options_hi.items():
                        setattr(hindi_q, k, v)

                    hindi_q.save()
                    hindi_q.area_name.set(areas_qs)
                    hindi_q.section_name.set(sections_qs)
                    hindi_q.part_name.set(parts_qs)
                    hindi_q.chapter_name.set(chapters_qs)
                    hindi_q.topic_name.set(topics_qs)
                    hindi_q.subtopic_name.set(subtopics_qs)
                    hindi_q.exam_name.set(exams_qs)  # ✅

                messages.success(request, "✅ List-I Type Question updated successfully!")
                return redirect('view_questions')  # ✅ fixed: underscore to match your Simple Type code

        except Exception as e:
            messages.error(request, f"  An error occurred while editing: {e}")

    # ===== GET: prefill context =====
    list_items = {f"list_1_row{i}": getattr(english_q, f"list_1_row{i}", '') for i in range(1, 9)}
    list_items_hi = {f"list_1_row{i}_hi": getattr(hindi_q, f"list_1_row{i}_hi", '') for i in range(1, 9)} if hindi_q else {}

    context = {
        'english_q': english_q,
        'hindi_q': hindi_q,
        'areas': areas,
        'sections': sections,
        'parts': parts,
        'chapters': chapters,
        'topics': topics,
        'subtopics': subtopics,
        'exams': exams,  # ✅ provide to template
        'list_items': list_items,
        'list_items_hi': list_items_hi,
        'selected_area_ids': [str(v) for v in english_q.area_name.values_list('area_SI_Code', flat=True)],
        'selected_section_ids': [str(v) for v in english_q.section_name.values_list('section_Unit_SI', flat=True)],
        'selected_part_ids': [str(v) for v in english_q.part_name.values_list('part_serial', flat=True)],
        'selected_chapter_ids': [str(v) for v in english_q.chapter_name.values_list('chapter_number', flat=True)],
        'selected_topic_ids': [str(v) for v in english_q.topic_name.values_list('topic_SI_number', flat=True)],
        'selected_subtopic_ids': [str(v) for v in english_q.subtopic_name.values_list('sub_topic_SI_Number', flat=True)],
        'selected_exam_ids': [str(v) for v in english_q.exam_name.values_list('exam_SI_Number', flat=True)],  # ✅
        "mark_options": ["0.5", "1.0", "1.5", "2.0", "2.5", "3.0"],
        "negative_mark_options": ["1.0", "0.5", "0.33", "0.25", "0.2", "0"],
        "range_1_to_5": range(1, 6),  # for degree_of_difficulty & elim_tactics_degree
        "range_1_to_8": range(1, 9),  # for list rows
    }

    return render(request, 'question_bank/edit_question/edit_list_type_1_form.html', context)
# ************************* Edit List-I Type Question Updated *********************************************

# ************************* Create Statement Type Question Start *************************
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName, QuestionBank
)
import random

@login_required
def add_statement_type_question(request):
    context = {
        'areas': Area.objects.all(),
        'sections': Section.objects.all(),
        'parts': PartName.objects.all(),
        'chapters': ChapterName.objects.all(),
        'topics': TopicName.objects.all(),
        'subtopics': SubTopicName.objects.all(),
    }

    if request.method == 'POST':
        try:
            with transaction.atomic():
                # ----- Hierarchy selections -----
                area_ids    = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids    = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids   = request.POST.getlist('topic_name[]')

                # Accept both param names for subtopics
                subtopic_ids = request.POST.getlist('sub_topic_name[]') or request.POST.getlist('subtopic_name[]')
                subtopic_ids = [str(s).strip() for s in subtopic_ids if str(s).strip()]

                # Exams (M2M)
                exam_ids = [str(x).strip() for x in request.POST.getlist('exam_name[]') if str(x).strip()]

                new_topic_name = request.POST.get('new_topic_name')
                script = request.POST.get('script', '')

                # Exam year
                exam_year_raw = request.POST.get('exam_year')
                if exam_year_raw in (None, '', 'null'):
                    exam_year = None
                else:
                    try:
                        exam_year = int(exam_year_raw)
                    except ValueError:
                        messages.error(request, "Please provide a valid exam year.")
                        return redirect(request.path_info)

                # ----- Stems / text -----
                question_part_first     = request.POST.get('question_part_first', '')
                question_part_first_hi  = request.POST.get('question_part_first_hi', '')
                question_part_third     = request.POST.get('question_part_third', '')
                question_part_third_hi  = request.POST.get('question_part_third_hi', '')

                # ----- Answers (A-D) -----
                correct_answer_choice        = request.POST.get('correct_answer_choice', '')
                correct_answer_description   = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi= request.POST.get('correct_answer_description_hi', '')

                # ----- Meta -----
                marks                 = float(request.POST.get('marks') or 0.0)
                negative_marks        = float(request.POST.get('negative_marks') or 0.0)
                degree_of_difficulty  = (request.POST.get('degree_of_difficulty') or '').strip()
                elim_tactics_degree   = (request.POST.get('elim_tactics_degree') or '').strip()
                # evergreen_index       = (request.POST.get('evergreen_index') or '').strip()
                question_type_source  = (request.POST.get('question_type_source') or 'modern').strip()
                current_relevance     = (request.POST.get('current_relevance') or '').strip()
                current_relevance_topic = request.POST.get('current_relevance_topic', '')

                # Map source -> type_of_question
                if question_type_source == 'pyq':
                    type_of_question = 'pyq'
                elif question_type_source == 'osq':
                    type_of_question = 'osq'
                else:
                    type_of_question = 'moq'

                # ----- M2M QuerySets -----
                areas_qs    = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs    = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs   = TopicName.objects.filter(topic_SI_number__in=topic_ids)

                # Allow new topic creation if "other" chosen
                if 'other' in topic_ids and new_topic_name and chapter_ids:
                    topic_ids.remove('other')
                    selected_chapter = ChapterName.objects.get(chapter_number=chapter_ids[0])
                    new_topic = TopicName.objects.create(name=new_topic_name, chapter=selected_chapter)
                    topic_ids.append(str(new_topic.topic_SI_number))

                topics_qs = TopicName.objects.filter(topic_SI_number__in=topic_ids)

                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)
                exams_qs     = ExamName.objects.filter(exam_SI_Number__in=exam_ids)

                if not subtopics_qs.exists():
                    messages.error(request, "Please choose at least one Sub Topic.")
                    return redirect(request.path_info)

                # ----- IDs / numbering -----
                while True:
                    base_question_id = random.randint(100000, 999999)
                    if not QuestionBank.objects.filter(base_question_id=base_question_id).exists():
                        break

                last_q = QuestionBank.objects.order_by('-question_number').first()
                next_question_number = last_q.question_number + 1 if last_q else 1

                # ----- Statement lines & List-II (rows 1..9) -----
                stmt_lines = {}
                list2_rows = {}
                for i in range(1, 10):  # 1..9
                    stmt_lines[f"stmt_line_row{i}"]     = request.POST.get(f"stmt_line_row{i}", '')
                    stmt_lines[f"stmt_line_row{i}_hi"]  = request.POST.get(f"stmt_line_row{i}_hi", '')
                    list2_rows[f"list_2_row{i}"]        = request.POST.get(f"list_2_row{i}", '')
                    list2_rows[f"list_2_row{i}_hi"]     = request.POST.get(f"list_2_row{i}_hi", '')

                # ----- Options A-D -----
                answer_options = {}
                for opt in 'abcd':
                    answer_options[f"answer_option_{opt}"]     = request.POST.get(f"answer_option_{opt}", '')
                    answer_options[f"answer_option_{opt}_hi"]  = request.POST.get(f"answer_option_{opt}_hi", '')

                # ===== Create English question =====
                question_en = QuestionBank.objects.create(
                    question_number=next_question_number,
                    base_question_id=base_question_id,
                    question_sub_type='statement_type',
                    type_of_question=type_of_question,
                    language='e',
                    script=script,
                    question_part_first=question_part_first,
                    question_part_third=question_part_third,
                    correct_answer_choice=correct_answer_choice,
                    correct_answer_description=correct_answer_description,
                    marks=marks,
                    negative_marks=negative_marks,
                    degree_of_difficulty=degree_of_difficulty,
                    elim_tactics_degree=elim_tactics_degree,
                    # evergreen_index=evergreen_index,
                    exam_year=exam_year,
                    current_relevance=current_relevance,
                    current_relevance_topic=current_relevance_topic,
                    created_by=request.user,
                    # stmt_line_row1..9 + list_2_row1..9
                    **{f"stmt_line_row{i}": stmt_lines[f"stmt_line_row{i}"] for i in range(1, 10)},
                    **{f"list_2_row{i}":  list2_rows[f"list_2_row{i}"]  for i in range(1, 10)},
                    # options
                    **{f"answer_option_{opt}": answer_options[f"answer_option_{opt}"] for opt in 'abcd'},
                )
                question_en.area_name.set(areas_qs)
                question_en.section_name.set(sections_qs)
                question_en.part_name.set(parts_qs)
                question_en.chapter_name.set(chapters_qs)
                question_en.topic_name.set(topics_qs)
                question_en.subtopic_name.set(subtopics_qs)
                question_en.exam_name.set(exams_qs)

                # ===== Create Hindi question =====
                question_hi = QuestionBank.objects.create(
                    question_number=next_question_number,
                    base_question_id=base_question_id,
                    question_sub_type='statement_type',
                    type_of_question=type_of_question,
                    language='h',
                    script=script,
                    question_part_first_hi=question_part_first_hi,
                    question_part_third_hi=question_part_third_hi,
                    correct_answer_choice=correct_answer_choice,
                    correct_answer_description_hi=correct_answer_description_hi,
                    marks=marks,
                    negative_marks=negative_marks,
                    degree_of_difficulty=degree_of_difficulty,
                    elim_tactics_degree=elim_tactics_degree,
                    # evergreen_index=evergreen_index,
                    exam_year=exam_year,
                    current_relevance=current_relevance,
                    current_relevance_topic=current_relevance_topic,
                    created_by=request.user,
                    # stmt_line_row1..9_hi + list_2_row1..9_hi
                    **{f"stmt_line_row{i}_hi": stmt_lines[f"stmt_line_row{i}_hi"] for i in range(1, 10)},
                    **{f"list_2_row{i}_hi":  list2_rows[f"list_2_row{i}_hi"]  for i in range(1, 10)},
                    # options
                    **{f"answer_option_{opt}_hi": answer_options[f"answer_option_{opt}_hi"] for opt in 'abcd'},
                )
                question_hi.area_name.set(areas_qs)
                question_hi.section_name.set(sections_qs)
                question_hi.part_name.set(parts_qs)
                question_hi.chapter_name.set(chapters_qs)
                question_hi.topic_name.set(topics_qs)
                question_hi.subtopic_name.set(subtopics_qs)
                question_hi.exam_name.set(exams_qs)

                messages.success(request, '✅ Statement Type Question saved successfully!')
                return redirect('add-statement-type-question')

        except Exception as e:
            messages.error(request, f'  An error occurred: {str(e)}')

    return render(request, 'question_bank/add_question/statement_type_form.html', context)
# ************************* Create Statement Type Question End *************************

# ************************* Edit Statement Type Question *********************************************
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName, QuestionBank
)

@login_required
def edit_statement_type_question(request, pk):
    # Only English PK is passed; we pair it with the Hindi twin via base_question_id
    english_q = get_object_or_404(
        QuestionBank,
        pk=pk,
        language='e',
        question_sub_type='statement_type'
    )
    hindi_q = QuestionBank.objects.filter(
        base_question_id=english_q.base_question_id, language='h'
    ).first()

    areas = Area.objects.all()
    sections = Section.objects.all()
    parts = PartName.objects.all()
    chapters = ChapterName.objects.all()
    topics = TopicName.objects.all()
    subtopics = SubTopicName.objects.all()
    exams = ExamName.objects.all()

    if request.method == 'POST':
        try:
            with transaction.atomic():
                # ===== Basic fields =====
                script = request.POST.get('script', '')

                exam_year_raw = request.POST.get('exam_year')
                try:
                    exam_year = int(exam_year_raw) if exam_year_raw not in (None, '', 'null') else None
                except (TypeError, ValueError):
                    exam_year = None

                question_part_first     = request.POST.get('question_part_first', '')
                question_part_first_hi  = request.POST.get('question_part_first_hi', '')
                question_part_third     = request.POST.get('question_part_third', '')
                question_part_third_hi  = request.POST.get('question_part_third_hi', '')

                correct_answer_choice           = request.POST.get('correct_answer_choice', '')
                correct_answer_description      = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi   = request.POST.get('correct_answer_description_hi', '')

                marks = float(request.POST.get('marks') or 0.0)
                negative_marks = float(request.POST.get('negative_marks') or 0.0)

                # CharFields (stored as strings, consistent with your other views)
                degree_of_difficulty = (request.POST.get('degree_of_difficulty') or '').strip()
                elim_tactics_degree  = (request.POST.get('elim_tactics_degree') or '').strip()
                current_relevance     = (request.POST.get('current_relevance') or '').strip()
                current_relevance_topic = request.POST.get('current_relevance_topic', '')

                # Optional, only set if your model actually has the field
                evergreen_index = request.POST.get('evergreen_index', '')

                # Source mapping (kept simple to mirror your other edit views)
                type_of_question = (request.POST.get('question_type_source') or english_q.type_of_question).strip()

                # ===== Answer options =====
                answer_options_en = {f"answer_option_{opt}": request.POST.get(f"answer_option_{opt}", '') for opt in "abcd"}
                answer_options_hi = {f"answer_option_{opt}_hi": request.POST.get(f"answer_option_{opt}_hi", '') for opt in "abcd"}

                # ===== Statement lines & List-II rows (1..9) =====
                stmt_lines_en = {f"stmt_line_row{i}": request.POST.get(f"stmt_line_row{i}", '') for i in range(1, 10)}
                stmt_lines_hi = {f"stmt_line_row{i}_hi": request.POST.get(f"stmt_line_row{i}_hi", '') for i in range(1, 10)}

                list2_rows_en = {f"list_2_row{i}": request.POST.get(f"list_2_row{i}", '') for i in range(1, 10)}
                list2_rows_hi = {f"list_2_row{i}_hi": request.POST.get(f"list_2_row{i}_hi", '') for i in range(1, 10)}

                # ===== Relationships =====
                area_ids    = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids    = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids   = request.POST.getlist('topic_name[]')

                # support both names for subtopics
                subtopic_ids = request.POST.getlist('sub_topic_name[]') or request.POST.getlist('subtopic_name[]')
                exam_ids     = request.POST.getlist('exam_name[]')

                areas_qs    = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs    = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs   = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics_qs= SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)
                exams_qs    = ExamName.objects.filter(exam_SI_Number__in=exam_ids)

                # ===== Update English =====
                english_q.script = script
                english_q.exam_year = exam_year
                english_q.question_part_first = question_part_first
                english_q.question_part_third = question_part_third
                english_q.correct_answer_choice = correct_answer_choice
                english_q.correct_answer_description = correct_answer_description
                english_q.marks = marks
                english_q.negative_marks = negative_marks
                english_q.degree_of_difficulty = degree_of_difficulty
                english_q.elim_tactics_degree = elim_tactics_degree
                english_q.current_relevance = current_relevance
                english_q.current_relevance_topic = current_relevance_topic
                english_q.type_of_question = type_of_question

                # Set evergreen_index only if the field exists on the model
                if hasattr(english_q, 'evergreen_index'):
                    english_q.evergreen_index = evergreen_index

                # Bulk set statement lines and list-II rows
                for k, v in {**stmt_lines_en, **list2_rows_en, **answer_options_en}.items():
                    setattr(english_q, k, v)

                english_q.save()
                english_q.area_name.set(areas_qs)
                english_q.section_name.set(sections_qs)
                english_q.part_name.set(parts_qs)
                english_q.chapter_name.set(chapters_qs)
                english_q.topic_name.set(topics_qs)
                english_q.subtopic_name.set(subtopics_qs)
                english_q.exam_name.set(exams_qs)

                # ===== Update Hindi (if exists) =====
                if hindi_q:
                    hindi_q.script = script
                    hindi_q.exam_year = exam_year
                    hindi_q.question_part_first_hi = question_part_first_hi
                    hindi_q.question_part_third_hi = question_part_third_hi
                    hindi_q.correct_answer_choice = correct_answer_choice
                    hindi_q.correct_answer_description_hi = correct_answer_description_hi
                    hindi_q.marks = marks
                    hindi_q.negative_marks = negative_marks
                    hindi_q.degree_of_difficulty = degree_of_difficulty
                    hindi_q.elim_tactics_degree = elim_tactics_degree
                    hindi_q.current_relevance = current_relevance
                    hindi_q.current_relevance_topic = current_relevance_topic
                    hindi_q.type_of_question = type_of_question

                    if hasattr(hindi_q, 'evergreen_index'):
                        hindi_q.evergreen_index = evergreen_index

                    for k, v in {**stmt_lines_hi, **list2_rows_hi, **answer_options_hi}.items():
                        setattr(hindi_q, k, v)

                    hindi_q.save()
                    hindi_q.area_name.set(areas_qs)
                    hindi_q.section_name.set(sections_qs)
                    hindi_q.part_name.set(parts_qs)
                    hindi_q.chapter_name.set(chapters_qs)
                    hindi_q.topic_name.set(topics_qs)
                    hindi_q.subtopic_name.set(subtopics_qs)
                    hindi_q.exam_name.set(exams_qs)

                messages.success(request, "✅ Statement Type Question updated successfully!")
                return redirect('view_questions')

        except Exception as e:
            messages.error(request, f"  An error occurred while editing: {e}")

    # ===== GET: prefill context for the form =====
    stmt_lines_en = {f"stmt_line_row{i}": getattr(english_q, f"stmt_line_row{i}", '') for i in range(1, 10)}
    stmt_lines_hi = {f"stmt_line_row{i}_hi": (getattr(hindi_q, f"stmt_line_row{i}_hi", '') if hindi_q else '') for i in range(1, 10)}

    list2_rows_en = {f"list_2_row{i}": getattr(english_q, f"list_2_row{i}", '') for i in range(1, 10)}
    list2_rows_hi = {f"list_2_row{i}_hi": (getattr(hindi_q, f"list_2_row{i}_hi", '') if hindi_q else '') for i in range(1, 10)}

    answer_options_hi = {f"answer_option_{opt}_hi": (getattr(hindi_q, f"answer_option_{opt}_hi", '') if hindi_q else '') for opt in "abcd"}

    context = {
        'english_q': english_q,
        'hindi_q': hindi_q,
        'areas': areas,
        'sections': sections,
        'parts': parts,
        'chapters': chapters,
        'topics': topics,
        'subtopics': subtopics,
        'exams': exams,

        # prefill maps
        'stmt_lines_en': stmt_lines_en,
        'stmt_lines_hi': stmt_lines_hi,
        'list2_rows_en': list2_rows_en,
        'list2_rows_hi': list2_rows_hi,
        'answer_options_hi': answer_options_hi,

        # selected M2M ids (strings for template compatibility)
        'selected_area_ids':     [str(v) for v in english_q.area_name.values_list('area_SI_Code', flat=True)],
        'selected_section_ids':  [str(v) for v in english_q.section_name.values_list('section_Unit_SI', flat=True)],
        'selected_part_ids':     [str(v) for v in english_q.part_name.values_list('part_serial', flat=True)],
        'selected_chapter_ids':  [str(v) for v in english_q.chapter_name.values_list('chapter_number', flat=True)],
        'selected_topic_ids':    [str(v) for v in english_q.topic_name.values_list('topic_SI_number', flat=True)],
        'selected_subtopic_ids': [str(v) for v in english_q.subtopic_name.values_list('sub_topic_SI_Number', flat=True)],
        'selected_exam_ids':     [str(v) for v in english_q.exam_name.values_list('exam_SI_Number', flat=True)],

        "mark_options": ["0.5", "1.0", "1.5", "2.0", "2.5", "3.0"],
        "negative_mark_options": ["1.0", "0.5", "0.33", "0.25", "0.2", "0"],
        "range_1_to_5": range(1, 6),   # for degree_of_difficulty & elim_tactics_degree
        "range_1_to_9": range(1, 10),  # for statement/list-II rows
    }

    return render(request, 'question_bank/edit_question/edit_statement_type_form.html', context)
# ************************* Edit Statement Type Question *********************************************




# ************************* Create List-II Type Question Start *********************************************
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName, QuestionBank
)
import random

@login_required
def add_list_type_2_question(request):
    context = {
        'areas': Area.objects.all(),
        'sections': Section.objects.all(),
        'parts': PartName.objects.all(),
        'chapters': ChapterName.objects.all(),
        'topics': TopicName.objects.all(),
        'subtopics': SubTopicName.objects.all(),
    }

    if request.method == 'POST':
        try:
            with transaction.atomic():
                # ----- Hierarchy selections -----
                area_ids    = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids    = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids   = request.POST.getlist('topic_name[]')

                # ✅ Accept both legacy and new param names for subtopics
                subtopic_ids = request.POST.getlist('sub_topic_name[]') or request.POST.getlist('subtopic_name[]')
                subtopic_ids = [str(s).strip() for s in subtopic_ids if str(s).strip()]

                # ✅ Exams (M2M)
                exam_ids = [str(x).strip() for x in request.POST.getlist('exam_name[]') if str(x).strip()]

                new_topic_name = request.POST.get('new_topic_name', '').strip()
                script = request.POST.get('script', '')

                # ----- Validate/parse exam year -----
                exam_year_raw = request.POST.get('exam_year')
                if exam_year_raw in (None, '', 'null'):
                    exam_year = None
                else:
                    try:
                        exam_year = int(exam_year_raw)
                    except ValueError:
                        messages.error(request, "Please provide a valid exam year.")
                        return redirect(request.path_info)

                # ----- Text / stems -----
                question_part_first     = request.POST.get('question_part_first', '')
                question_part_first_hi  = request.POST.get('question_part_first_hi', '')
                question_part_third     = request.POST.get('question_part_third', '')
                question_part_third_hi  = request.POST.get('question_part_third_hi', '')

                # ----- Answers -----
                correct_answer_choice        = request.POST.get('correct_answer_choice', '')
                correct_answer_description   = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi= request.POST.get('correct_answer_description_hi', '')

                # ----- Meta -----
                marks                 = float(request.POST.get('marks') or 0.0)
                negative_marks        = float(request.POST.get('negative_marks') or 0.0)
                degree_of_difficulty  = (request.POST.get('degree_of_difficulty') or '').strip()
                elim_tactics_degree   = (request.POST.get('elim_tactics_degree') or '').strip()  # ✅ NEW
                evergreen_index       = (request.POST.get('evergreen_index') or '').strip()

                list_1_name    = request.POST.get('list_1_name', '')
                list_2_name    = request.POST.get('list_2_name', '')
                list_1_name_hi = request.POST.get('list_1_name_hi', '')
                list_2_name_hi = request.POST.get('list_2_name_hi', '')

                # ✅ Current Relevance
                current_relevance       = (request.POST.get('current_relevance') or '').strip()
                current_relevance_topic = request.POST.get('current_relevance_topic', '')

                # Question source -> type
                question_type_source = (request.POST.get('question_type_source', 'modern') or '').strip()
                if question_type_source == 'pyq':
                    type_of_question = 'pyq'
                elif question_type_source == 'osq':
                    type_of_question = 'osq'
                else:
                    type_of_question = 'moq'

                # ----- M2M QuerySets -----
                areas_qs    = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs    = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs = ChapterName.objects.filter(chapter_number__in=chapter_ids)

                # New topic handling (if "other")
                if 'other' in topic_ids and new_topic_name and chapter_ids:
                    topic_ids.remove('other')
                    selected_chapter = ChapterName.objects.get(chapter_number=chapter_ids[0])
                    new_topic = TopicName.objects.create(name=new_topic_name, chapter=selected_chapter)
                    topic_ids.append(str(new_topic.topic_SI_number))

                topics_qs    = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)
                exams_qs     = ExamName.objects.filter(exam_SI_Number__in=exam_ids)

                # (Optional) enforce subtopics selected
                if not subtopics_qs.exists():
                    messages.error(request, "Please choose at least one Sub Topic.")
                    return redirect(request.path_info)

                # ----- Generate identifiers -----
                last_question = QuestionBank.objects.order_by('-question_number').first()
                next_question_number = last_question.question_number + 1 if last_question else 1

                while True:
                    base_question_id = random.randint(100000, 999999)
                    if not QuestionBank.objects.filter(base_question_id=base_question_id).exists():
                        break

                # ----- List items & options -----
                list_items    = {}
                list_items_hi = {}
                for i in range(1, 6):
                    list_items[f"list_1_row{i}"]    = request.POST.get(f"list_1_row{i}", '')
                    list_items[f"list_2_row{i}"]    = request.POST.get(f"list_2_row{i}", '')
                    list_items_hi[f"list_1_row{i}_hi"] = request.POST.get(f"list_1_row{i}_hi", '')
                    list_items_hi[f"list_2_row{i}_hi"] = request.POST.get(f"list_2_row{i}_hi", '')

                answer_options    = {f"answer_option_{opt}": request.POST.get(f"answer_option_{opt}", '') for opt in 'abcd'}
                answer_options_hi = {f"answer_option_{opt}_hi": request.POST.get(f"answer_option_{opt}_hi", '') for opt in 'abcd'}

                # ----- Create EN row -----
                question_en = QuestionBank.objects.create(
                    question_number=next_question_number,
                    question_sub_type='list_type_2',
                    base_question_id=base_question_id,
                    type_of_question=type_of_question,
                    language='e',
                    script=script,
                    question_part_first=question_part_first,
                    question_part_third=question_part_third,
                    correct_answer_choice=correct_answer_choice,
                    correct_answer_description=correct_answer_description,
                    marks=marks,
                    negative_marks=negative_marks,
                    degree_of_difficulty=degree_of_difficulty,
                    elim_tactics_degree=elim_tactics_degree,  # ✅ NEW
                    evergreen_index=evergreen_index,
                    list_1_name=list_1_name,
                    list_2_name=list_2_name,
                    exam_year=exam_year,
                    current_relevance=current_relevance,
                    current_relevance_topic=current_relevance_topic,
                    created_by=request.user,
                    **list_items,
                    **answer_options
                )
                question_en.area_name.set(areas_qs)
                question_en.section_name.set(sections_qs)
                question_en.part_name.set(parts_qs)
                question_en.chapter_name.set(chapters_qs)
                question_en.topic_name.set(topics_qs)
                question_en.subtopic_name.set(subtopics_qs)
                question_en.exam_name.set(exams_qs)  # ✅ NEW

                # ----- Create HI row -----
                question_hi = QuestionBank.objects.create(
                    question_number=next_question_number,
                    question_sub_type='list_type_2',
                    base_question_id=base_question_id,
                    type_of_question=type_of_question,
                    language='h',
                    script=script,
                    question_part_first_hi=question_part_first_hi,
                    question_part_third_hi=question_part_third_hi,
                    correct_answer_choice=correct_answer_choice,
                    correct_answer_description_hi=correct_answer_description_hi,
                    marks=marks,
                    negative_marks=negative_marks,
                    degree_of_difficulty=degree_of_difficulty,
                    elim_tactics_degree=elim_tactics_degree,  # ✅ NEW
                    evergreen_index=evergreen_index,
                    list_1_name=list_1_name_hi,
                    list_2_name=list_2_name_hi,
                    exam_year=exam_year,
                    current_relevance=current_relevance,
                    current_relevance_topic=current_relevance_topic,
                    created_by=request.user,
                    **list_items_hi,
                    **answer_options_hi
                )
                question_hi.area_name.set(areas_qs)
                question_hi.section_name.set(sections_qs)
                question_hi.part_name.set(parts_qs)
                question_hi.chapter_name.set(chapters_qs)
                question_hi.topic_name.set(topics_qs)
                question_hi.subtopic_name.set(subtopics_qs)
                question_hi.exam_name.set(exams_qs)  # ✅ NEW

                messages.success(request, '✅ List-II Type Question added successfully!')
                return redirect('add-list-type-2-question')

        except Exception as e:
            messages.error(request, f'  An unexpected error occurred: {str(e)}')

    return render(request, 'question_bank/add_question/list_type_2_form.html', context)

# ************************* Create List-II Type Question End *********************************************



# ************************* Edit List-II Type Question Updated *********************************************
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName, QuestionBank
)

@login_required
def edit_list_type_2_question(request, pk):
    english_q = get_object_or_404(QuestionBank, pk=pk, language='e')
    hindi_q = QuestionBank.objects.filter(base_question_id=english_q.base_question_id, language='h').first()

    areas = Area.objects.all()
    sections = Section.objects.all()
    parts = PartName.objects.all()
    chapters = ChapterName.objects.all()
    topics = TopicName.objects.all()
    subtopics = SubTopicName.objects.all()
    exams = ExamName.objects.all()

    if request.method == 'POST':
        try:
            with transaction.atomic():
                # ---------- Basics ----------
                script = request.POST.get('script', '')
                exam_year = request.POST.get('exam_year') or None

                question_part_first = request.POST.get('question_part_first', '')
                question_part_first_hi = request.POST.get('question_part_first_hi', '')

                question_part_third = request.POST.get('question_part_third', '')
                question_part_third_hi = request.POST.get('question_part_third_hi', '')

                correct_answer_choice = request.POST.get('correct_answer_choice', '')
                correct_answer_description = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi = request.POST.get('correct_answer_description_hi', '')

                list_1_name = request.POST.get('list_1_name', '')
                list_2_name = request.POST.get('list_2_name', '')
                list_1_name_hi = request.POST.get('list_1_name_hi', '')
                list_2_name_hi = request.POST.get('list_2_name_hi', '')

                marks = float(request.POST.get('marks') or 0.0)
                negative_marks = float(request.POST.get('negative_marks') or 0.0)

                # ---------- Difficulty & Elimination tactics ----------
                degree_of_difficulty = (request.POST.get('degree_of_difficulty') or '').strip()
                elim_tactics_degree = (request.POST.get('elim_tactics_degree') or '').strip()

                # ---------- Other meta ----------
                evergreen_index = request.POST.get('evergreen_index', '')
                current_relevance = request.POST.get('current_relevance', '')
                current_relevance_topic = request.POST.get('current_relevance_topic', '')
                type_of_question = (request.POST.get('question_type_source') or '').strip()

                # ---------- Answers & lists ----------
                answer_options = {f"answer_option_{opt}": request.POST.get(f"answer_option_{opt}", '') for opt in "abcd"}
                answer_options_hi = {f"answer_option_{opt}_hi": request.POST.get(f"answer_option_{opt}_hi", '') for opt in "abcd"}

                list_items = {f"list_1_row{i}": request.POST.get(f"list_1_row{i}", '') for i in range(1, 6)}
                list_items.update({f"list_2_row{i}": request.POST.get(f"list_2_row{i}", '') for i in range(1, 6)})

                list_items_hi = {f"list_1_row{i}_hi": request.POST.get(f"list_1_row{i}_hi", '') for i in range(1, 6)}
                list_items_hi.update({f"list_2_row{i}_hi": request.POST.get(f"list_2_row{i}_hi", '') for i in range(1, 6)})

                # ---------- Relationships ----------
                area_ids = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids = request.POST.getlist('topic_name[]')
                subtopic_ids = request.POST.getlist('sub_topic_name[]')
                exam_ids = request.POST.getlist('exam_name[]')

                areas_qs = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)
                exams_qs = ExamName.objects.filter(exam_SI_Number__in=exam_ids)

                # ---------- Update English ----------
                english_q.script = script
                english_q.question_part_first = question_part_first
                english_q.question_part_third = question_part_third
                english_q.correct_answer_choice = correct_answer_choice
                english_q.correct_answer_description = correct_answer_description
                english_q.list_1_name = list_1_name
                english_q.list_2_name = list_2_name
                english_q.marks = marks
                english_q.negative_marks = negative_marks
                english_q.degree_of_difficulty = degree_of_difficulty
                english_q.elim_tactics_degree = elim_tactics_degree
                english_q.evergreen_index = evergreen_index
                english_q.current_relevance = current_relevance
                english_q.current_relevance_topic = current_relevance_topic
                english_q.exam_year = exam_year
                english_q.type_of_question = type_of_question

                for k, v in list_items.items():
                    setattr(english_q, k, v)
                for k, v in answer_options.items():
                    setattr(english_q, k, v)

                english_q.save()
                english_q.area_name.set(areas_qs)
                english_q.section_name.set(sections_qs)
                english_q.part_name.set(parts_qs)
                english_q.chapter_name.set(chapters_qs)
                english_q.topic_name.set(topics_qs)
                english_q.subtopic_name.set(subtopics_qs)
                english_q.exam_name.set(exams_qs)

                # ---------- Update Hindi (if exists) ----------
                if hindi_q:
                    hindi_q.script = script
                    hindi_q.question_part_first_hi = question_part_first_hi
                    hindi_q.question_part_third_hi = question_part_third_hi
                    hindi_q.correct_answer_choice = correct_answer_choice
                    hindi_q.correct_answer_description_hi = correct_answer_description_hi
                    hindi_q.list_1_name = list_1_name_hi
                    hindi_q.list_2_name = list_2_name_hi
                    hindi_q.marks = marks
                    hindi_q.negative_marks = negative_marks
                    hindi_q.degree_of_difficulty = degree_of_difficulty
                    hindi_q.elim_tactics_degree = elim_tactics_degree
                    hindi_q.evergreen_index = evergreen_index
                    hindi_q.current_relevance = current_relevance
                    hindi_q.current_relevance_topic = current_relevance_topic
                    hindi_q.exam_year = exam_year
                    hindi_q.type_of_question = type_of_question

                    for k, v in list_items_hi.items():
                        setattr(hindi_q, k, v)
                    for k, v in answer_options_hi.items():
                        setattr(hindi_q, k, v)

                    hindi_q.save()
                    hindi_q.area_name.set(areas_qs)
                    hindi_q.section_name.set(sections_qs)
                    hindi_q.part_name.set(parts_qs)
                    hindi_q.chapter_name.set(chapters_qs)
                    hindi_q.topic_name.set(topics_qs)
                    hindi_q.subtopic_name.set(subtopics_qs)
                    hindi_q.exam_name.set(exams_qs)

                messages.success(request, "✅ List-II Type Question updated successfully!")
                return redirect('view_questions')

        except Exception as e:
            messages.error(request, f"  An error occurred while editing: {e}")

    # ---------- GET: prefill context ----------
    list_1_items = {f"list_1_row{i}": getattr(english_q, f"list_1_row{i}", '') for i in range(1, 6)}
    list_2_items = {f"list_2_row{i}": getattr(english_q, f"list_2_row{i}", '') for i in range(1, 6)}
    list_1_items_hi = {f"list_1_row{i}_hi": getattr(hindi_q, f"list_1_row{i}_hi", '') for i in range(1, 6)} if hindi_q else {}
    list_2_items_hi = {f"list_2_row{i}_hi": getattr(hindi_q, f"list_2_row{i}_hi", '') for i in range(1, 6)} if hindi_q else {}

    context = {
        'english_q': english_q,
        'hindi_q': hindi_q,
        'areas': areas,
        'sections': sections,
        'parts': parts,
        'chapters': chapters,
        'topics': topics,
        'subtopics': subtopics,
        'exams': exams,
        'list_1_items': list_1_items,
        'list_2_items': list_2_items,
        'list_1_items_hi': list_1_items_hi,
        'list_2_items_hi': list_2_items_hi,
        'selected_area_ids': [str(v) for v in english_q.area_name.values_list('area_SI_Code', flat=True)],
        'selected_section_ids': [str(v) for v in english_q.section_name.values_list('section_Unit_SI', flat=True)],
        'selected_part_ids': [str(v) for v in english_q.part_name.values_list('part_serial', flat=True)],
        'selected_chapter_ids': [str(v) for v in english_q.chapter_name.values_list('chapter_number', flat=True)],
        'selected_topic_ids': [str(v) for v in english_q.topic_name.values_list('topic_SI_number', flat=True)],
        'selected_subtopic_ids': [str(v) for v in english_q.subtopic_name.values_list('sub_topic_SI_Number', flat=True)],
        'selected_exam_ids': [str(v) for v in english_q.exam_name.values_list('exam_SI_Number', flat=True)],
        "mark_options": ["0.5", "1.0", "1.5", "2.0", "2.5", "3.0"],
        "negative_mark_options": ["1.0", "0.5", "0.33", "0.25", "0.2", "0"],
        "range_1_to_5": range(1, 6),  # for degree_of_difficulty & elim_tactics_degree selects
    }

    return render(request, 'question_bank/edit_question/edit_list_type_2_form.html', context)
# ************************* Edit List-II Type Question Updated *********************************************




# ************************* Create True and False Type Question Start *********************************************
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName,
    QuestionBank, ExamName  # ✅ include ExamName
)
import random

@login_required
def add_true_and_false_type_question(request):
    context = {
        'areas': Area.objects.all(),
        'sections': Section.objects.all(),
        'parts': PartName.objects.all(),
        'chapters': ChapterName.objects.all(),
        'topics': TopicName.objects.all(),
        'subtopics': SubTopicName.objects.all(),
    }

    if request.method == 'POST':
        try:
            with transaction.atomic():
                # ----- Hierarchy selections -----
                area_ids    = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids    = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids   = request.POST.getlist('topic_name[]')

                # ✅ Accept both legacy and new param names for subtopics
                subtopic_ids = request.POST.getlist('sub_topic_name[]') or request.POST.getlist('subtopic_name[]')
                subtopic_ids = [str(s).strip() for s in subtopic_ids if str(s).strip()]

                # ✅ Exams (M2M)
                exam_ids = [str(x).strip() for x in request.POST.getlist('exam_name[]') if str(x).strip()]

                new_topic_name = (request.POST.get('new_topic_name') or '').strip()

                # ----- Validate/parse exam year -----
                exam_year_raw = request.POST.get('exam_year')
                if exam_year_raw in (None, '', 'null'):
                    exam_year = None
                else:
                    try:
                        exam_year = int(exam_year_raw)
                    except ValueError:
                        messages.error(request, "Please provide a valid exam year.")
                        return redirect(request.path_info)

                script = request.POST.get('script', '')

                # ----- Stems -----
                question_part_first    = request.POST.get('question_part_first', '')
                question_part_first_hi = request.POST.get('question_part_first_hi', '')

                # ----- Answer / explanation -----
                correct_answer_choice         = request.POST.get('correct_answer_choice', '')
                correct_answer_description    = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi = request.POST.get('correct_answer_description_hi', '')

                # ----- Meta -----
                marks                = float(request.POST.get('marks') or 0.0)
                negative_marks       = float(request.POST.get('negative_marks') or 0.0)
                degree_of_difficulty = (request.POST.get('degree_of_difficulty') or '').strip()
                elim_tactics_degree  = (request.POST.get('elim_tactics_degree') or '').strip()  # ✅ NEW
                evergreen_index      = (request.POST.get('evergreen_index') or '').strip()

                current_relevance       = (request.POST.get('current_relevance') or '').strip()
                current_relevance_topic = request.POST.get('current_relevance_topic', '')

                # Source | type
                question_type_source = (request.POST.get('question_type_source', 'modern') or '').strip()
                if question_type_source == 'pyq':
                    type_of_question = 'pyq'
                elif question_type_source == 'osq':
                    type_of_question = 'osq'
                else:
                    type_of_question = 'moq'

                # ----- New topic (if "other") -----
                if 'other' in topic_ids and new_topic_name and chapter_ids:
                    topic_ids.remove('other')
                    selected_chapter = ChapterName.objects.get(chapter_number=chapter_ids[0])
                    new_topic = TopicName.objects.create(name=new_topic_name, chapter=selected_chapter)
                    topic_ids.append(str(new_topic.topic_SI_number))

                # ----- M2M QuerySets -----
                areas_qs     = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs  = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs     = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs  = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs    = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)
                exams_qs     = ExamName.objects.filter(exam_SI_Number__in=exam_ids)

                # (Optional) enforce at least one subtopic
                if not subtopics_qs.exists():
                    messages.error(request, "Please choose at least one Sub Topic.")
                    return redirect(request.path_info)

                # ----- IDs -----
                last_q = QuestionBank.objects.order_by('-question_number').first()
                next_question_number = last_q.question_number + 1 if last_q else 1

                while True:
                    base_question_id = random.randint(100000, 999999)
                    if not QuestionBank.objects.filter(base_question_id=base_question_id).exists():
                        break

                # ----- Create EN -----
                question_en = QuestionBank.objects.create(
                    question_number=next_question_number,
                    question_sub_type='true_and_false_type',
                    base_question_id=base_question_id,
                    type_of_question=type_of_question,
                    language='e',
                    script=script,
                    question_part_first=question_part_first,
                    correct_answer_choice=correct_answer_choice,
                    correct_answer_description=correct_answer_description,
                    marks=marks,
                    negative_marks=negative_marks,
                    degree_of_difficulty=degree_of_difficulty,
                    elim_tactics_degree=elim_tactics_degree,   # ✅ NEW
                    evergreen_index=evergreen_index,
                    exam_year=exam_year,
                    current_relevance=current_relevance,
                    current_relevance_topic=current_relevance_topic,
                    # Force True/False options
                    answer_option_a="True",
                    answer_option_b="False",
                    created_by=request.user
                )
                question_en.area_name.set(areas_qs)
                question_en.section_name.set(sections_qs)
                question_en.part_name.set(parts_qs)
                question_en.chapter_name.set(chapters_qs)
                question_en.topic_name.set(topics_qs)
                question_en.subtopic_name.set(subtopics_qs)
                question_en.exam_name.set(exams_qs)  # ✅ save Exams

                # ----- Create HI -----
                question_hi = QuestionBank.objects.create(
                    question_number=next_question_number,
                    question_sub_type='true_and_false_type',
                    base_question_id=base_question_id,
                    type_of_question=type_of_question,
                    language='h',
                    script=script,
                    question_part_first_hi=question_part_first_hi,
                    correct_answer_choice=correct_answer_choice,
                    correct_answer_description_hi=correct_answer_description_hi,
                    marks=marks,
                    negative_marks=negative_marks,
                    degree_of_difficulty=degree_of_difficulty,
                    elim_tactics_degree=elim_tactics_degree,   # ✅ NEW
                    evergreen_index=evergreen_index,
                    exam_year=exam_year,
                    current_relevance=current_relevance,
                    current_relevance_topic=current_relevance_topic,
                    # Force True/False options (Hindi)
                    answer_option_a="सही",
                    answer_option_b="गलत",
                    created_by=request.user
                )
                question_hi.area_name.set(areas_qs)
                question_hi.section_name.set(sections_qs)
                question_hi.part_name.set(parts_qs)
                question_hi.chapter_name.set(chapters_qs)
                question_hi.topic_name.set(topics_qs)
                question_hi.subtopic_name.set(subtopics_qs)
                question_hi.exam_name.set(exams_qs)  # ✅ save Exams

                messages.success(request, '✅ True & False Type Question added successfully!')
                return redirect('add-true-and-false-type-question')

        except Exception as e:
            messages.error(request, f'  An unexpected error occurred: {str(e)}')

    return render(request, 'question_bank/add_question/true_false_type_form.html', context)

# ************************* Create True and False Type Question End *********************************************




# ************************* Edit True and False Type Question Updated *********************************************
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName, QuestionBank
)

@login_required
def edit_true_and_false_type_question(request, base_question_id):
    english_q = get_object_or_404(QuestionBank, base_question_id=base_question_id, language='e')
    hindi_q = QuestionBank.objects.filter(base_question_id=base_question_id, language='h').first()

    areas = Area.objects.all()
    sections = Section.objects.all()
    parts = PartName.objects.all()
    chapters = ChapterName.objects.all()
    topics = TopicName.objects.all()
    subtopics = SubTopicName.objects.all()

    if request.method == 'POST':
        try:
            with transaction.atomic():
                script = request.POST.get('script', '')
                question_part_first = request.POST.get('question_part_first', '')
                question_part_first_hi = request.POST.get('question_part_first_hi', '')

                correct_answer_choice = request.POST.get('correct_answer_choice', '')
                correct_answer_description = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi = request.POST.get('correct_answer_description_hi', '')

                marks = float(request.POST.get('marks') or 0.0)
                negative_marks = float(request.POST.get('negative_marks') or 0.0)
                degree_of_difficulty = request.POST.get('degree_of_difficulty', '')
                evergreen_index = request.POST.get('evergreen_index', '')
                current_relevance = request.POST.get('current_relevance', '')
                current_relevance_topic = request.POST.get('current_relevance_topic', '')

                exam_year = request.POST.get('exam_year') or None

                area_ids = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids = request.POST.getlist('topic_name[]')
                subtopic_ids = request.POST.getlist('sub_topic_name[]')

                areas_qs = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)

                # ✅ Update English version
                english_q.script = script
                english_q.question_part_first = question_part_first
                english_q.correct_answer_choice = correct_answer_choice
                english_q.correct_answer_description = correct_answer_description
                english_q.marks = marks
                english_q.negative_marks = negative_marks
                english_q.degree_of_difficulty = degree_of_difficulty
                english_q.evergreen_index = evergreen_index
                english_q.current_relevance = current_relevance
                english_q.current_relevance_topic = current_relevance_topic
                english_q.exam_year = exam_year
                english_q.answer_option_a = "True"
                english_q.answer_option_b = "False"
                english_q.save()

                english_q.area_name.set(areas_qs)
                english_q.section_name.set(sections_qs)
                english_q.part_name.set(parts_qs)
                english_q.chapter_name.set(chapters_qs)
                english_q.topic_name.set(topics_qs)
                english_q.subtopic_name.set(subtopics_qs)

                # ✅ Update Hindi version if exists
                if hindi_q:
                    hindi_q.script = script
                    hindi_q.question_part_first_hi = question_part_first_hi
                    hindi_q.correct_answer_choice = correct_answer_choice
                    hindi_q.correct_answer_description_hi = correct_answer_description_hi
                    hindi_q.marks = marks
                    hindi_q.negative_marks = negative_marks
                    hindi_q.degree_of_difficulty = degree_of_difficulty
                    hindi_q.evergreen_index = evergreen_index
                    hindi_q.current_relevance = current_relevance
                    hindi_q.current_relevance_topic = current_relevance_topic
                    hindi_q.exam_year = exam_year
                    hindi_q.answer_option_a = "सही"
                    hindi_q.answer_option_b = "गलत"
                    hindi_q.save()

                    hindi_q.area_name.set(areas_qs)
                    hindi_q.section_name.set(sections_qs)
                    hindi_q.part_name.set(parts_qs)
                    hindi_q.chapter_name.set(chapters_qs)
                    hindi_q.topic_name.set(topics_qs)
                    hindi_q.subtopic_name.set(subtopics_qs)

                messages.success(request, "✅ True & False Type Question updated successfully!")
                return redirect('view_questions')

        except Exception as e:
            messages.error(request, f"  An error occurred while editing: {e}")

    context = {
        'english_q': english_q,
        'hindi_q': hindi_q,
        'areas': areas,
        'sections': sections,
        'parts': parts,
        'chapters': chapters,
        'topics': topics,
        'subtopics': subtopics,
        "mark_options": ["0.5", "1.0", "1.5", "2.0", "2.5", "3.0"],
        "negative_mark_options": ["1.0", "0.5", "0.33", "0.25", "0.2", "0"],
    }

    return render(request, 'question_bank/edit_question/edit_true_false_type_form.html', context)
# ************************* Edit True and False Type Question Updated *********************************************



# ************************* Create Fill in the Blank Type Question Start *********************************************
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, QuestionBank
)
import random

@login_required
def add_fill_in_the_blank_question(request):
    context = {
        'areas': Area.objects.all(),
        'sections': Section.objects.all(),
        'parts': PartName.objects.all(),
        'chapters': ChapterName.objects.all(),
        'topics': TopicName.objects.all(),
        'subtopics': SubTopicName.objects.all(),
    }

    if request.method == 'POST':
        try:
            with transaction.atomic():
                # ✅ Extract fields
                area_ids = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids = request.POST.getlist('topic_name[]')
                subtopic_ids = request.POST.getlist('sub_topic_name[]')

                new_topic_name = request.POST.get('new_topic_name', '').strip()
                new_subtopic_name = request.POST.get('new_subtopic_name', '').strip()

                exam_year = request.POST.get('exam_year') or None
                script = request.POST.get('script', '')

                question_part_first = request.POST.get('question_part_first', '')
                question_part_first_hi = request.POST.get('question_part_first_hi', '')
                correct_answer_choice = request.POST.get('correct_answer_choice', '')
                correct_answer_description = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi = request.POST.get('correct_answer_description_hi', '')

                marks = float(request.POST.get('marks') or 0.0)
                negative_marks = float(request.POST.get('negative_marks') or 0.0)
                degree_of_difficulty = request.POST.get('degree_of_difficulty', '')
                evergreen_index = request.POST.get('evergreen_index', '')

                current_relevance = request.POST.get('current_relevance', '')
                current_relevance_topic = request.POST.get('current_relevance_topic', '')

                question_type_source = request.POST.get('question_type_source', 'modern')
                type_of_question = 'pyq' if question_type_source == 'pyq' else (
                    'osq' if question_type_source == 'osq' else 'moq'
                )

                # ✅ Handle new topic creation
                if 'other' in topic_ids:
                    topic_ids.remove('other')
                    if new_topic_name and chapter_ids:
                        selected_chapter = ChapterName.objects.get(chapter_number=chapter_ids[0])
                        new_topic = TopicName.objects.create(
                            name=new_topic_name,
                            chapter=selected_chapter
                        )
                        topic_ids.append(new_topic.topic_SI_number)

                # ✅ Handle new subtopic creation
                if 'other' in subtopic_ids:
                    subtopic_ids.remove('other')
                    if new_subtopic_name and topic_ids:
                        selected_topic = TopicName.objects.get(topic_SI_number=topic_ids[0])
                        new_subtopic = SubTopicName.objects.create(
                            name=new_subtopic_name,
                            topic=selected_topic
                        )
                        subtopic_ids.append(new_subtopic.sub_topic_SI_Number)

                # ✅ Fetch related M2M objects
                areas_qs = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)

                # ✅ Generate question number & unique base ID
                last_question = QuestionBank.objects.order_by('-question_number').first()
                next_question_number = last_question.question_number + 1 if last_question else 1

                while True:
                    base_question_id = random.randint(100000, 999999)
                    if not QuestionBank.objects.filter(base_question_id=base_question_id).exists():
                        break

                # ✅ Create English question
                question_en = QuestionBank.objects.create(
                    question_number=next_question_number,
                    question_sub_type='fill_in_the_blank_type',
                    base_question_id=base_question_id,
                    type_of_question=type_of_question,
                    language='e',
                    script=script,
                    question_part_first=question_part_first,
                    correct_answer_choice=correct_answer_choice,
                    correct_answer_description=correct_answer_description,
                    marks=marks,
                    negative_marks=negative_marks,
                    degree_of_difficulty=degree_of_difficulty,
                    evergreen_index=evergreen_index,
                    exam_year=exam_year,
                    current_relevance=current_relevance,
                    current_relevance_topic=current_relevance_topic,
                    created_by=request.user
                )

                # ✅ Create Hindi question
                question_hi = QuestionBank.objects.create(
                    question_number=next_question_number,
                    question_sub_type='fill_in_the_blank_type',
                    base_question_id=base_question_id,
                    type_of_question=type_of_question,
                    language='h',
                    script=script,
                    question_part_first_hi=question_part_first_hi,
                    correct_answer_choice=correct_answer_choice,
                    correct_answer_description_hi=correct_answer_description_hi,
                    marks=marks,
                    negative_marks=negative_marks,
                    degree_of_difficulty=degree_of_difficulty,
                    evergreen_index=evergreen_index,
                    exam_year=exam_year,
                    current_relevance=current_relevance,
                    current_relevance_topic=current_relevance_topic,
                    created_by=request.user
                )

                # ✅ Save M2M relations
                for q in [question_en, question_hi]:
                    q.area_name.set(areas_qs)
                    q.section_name.set(sections_qs)
                    q.part_name.set(parts_qs)
                    q.chapter_name.set(chapters_qs)
                    q.topic_name.set(topics_qs)
                    q.subtopic_name.set(subtopics_qs)

                messages.success(request, '✅ Fill in the Blank Question added successfully in English and Hindi!')
                return redirect('add-fill-in-the-blank-question')

        except Exception as e:
            messages.error(request, f'  An unexpected error occurred: {str(e)}')

    return render(request, 'question_bank/add_question/fill_in_the_blank_form.html', context)

# ************************* Create Fill in the Blank Type Question End *********************************************



# ************************* Edit Fill in the Blank Type Question Updated *********************************************
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from .models import (
    Area, Section, PartName, ChapterName, TopicName, SubTopicName, ExamName, QuestionBank
)

@login_required
def edit_fill_in_the_blank_question(request, base_question_id):
    english_q = get_object_or_404(QuestionBank, base_question_id=base_question_id, language='e')
    hindi_q = QuestionBank.objects.filter(base_question_id=base_question_id, language='h').first()

    areas = Area.objects.all()
    sections = Section.objects.all()
    parts = PartName.objects.all()
    chapters = ChapterName.objects.all()
    topics = TopicName.objects.all()
    subtopics = SubTopicName.objects.all()

    if request.method == 'POST':
        try:
            with transaction.atomic():
                script = request.POST.get('script', '')
                question_part_first = request.POST.get('question_part_first', '')
                question_part_first_hi = request.POST.get('question_part_first_hi', '')

                correct_answer_choice = request.POST.get('correct_answer_choice', '')
                correct_answer_description = request.POST.get('correct_answer_description', '')
                correct_answer_description_hi = request.POST.get('correct_answer_description_hi', '')

                marks = float(request.POST.get('marks') or 0.0)
                negative_marks = float(request.POST.get('negative_marks') or 0.0)
                degree_of_difficulty = request.POST.get('degree_of_difficulty', '')
                evergreen_index = request.POST.get('evergreen_index', '')
                current_relevance = request.POST.get('current_relevance', '')
                current_relevance_topic = request.POST.get('current_relevance_topic', '')

                exam_year = request.POST.get('exam_year') or None

                area_ids = request.POST.getlist('area_name[]')
                section_ids = request.POST.getlist('section_name[]')
                part_ids = request.POST.getlist('part_name[]')
                chapter_ids = request.POST.getlist('chapter_name[]')
                topic_ids = request.POST.getlist('topic_name[]')
                subtopic_ids = request.POST.getlist('sub_topic_name[]')

                areas_qs = Area.objects.filter(area_SI_Code__in=area_ids)
                sections_qs = Section.objects.filter(section_Unit_SI__in=section_ids)
                parts_qs = PartName.objects.filter(part_serial__in=part_ids)
                chapters_qs = ChapterName.objects.filter(chapter_number__in=chapter_ids)
                topics_qs = TopicName.objects.filter(topic_SI_number__in=topic_ids)
                subtopics_qs = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)

                # ✅ Update English Question
                english_q.script = script
                english_q.question_part_first = question_part_first
                english_q.correct_answer_choice = correct_answer_choice
                english_q.correct_answer_description = correct_answer_description
                english_q.marks = marks
                english_q.negative_marks = negative_marks
                english_q.degree_of_difficulty = degree_of_difficulty
                english_q.evergreen_index = evergreen_index
                english_q.current_relevance = current_relevance
                english_q.current_relevance_topic = current_relevance_topic
                english_q.exam_year = exam_year
                english_q.save()

                english_q.area_name.set(areas_qs)
                english_q.section_name.set(sections_qs)
                english_q.part_name.set(parts_qs)
                english_q.chapter_name.set(chapters_qs)
                english_q.topic_name.set(topics_qs)
                english_q.subtopic_name.set(subtopics_qs)

                # ✅ Update Hindi Question if exists
                if hindi_q:
                    hindi_q.script = script
                    hindi_q.question_part_first_hi = question_part_first_hi
                    hindi_q.correct_answer_choice = correct_answer_choice
                    hindi_q.correct_answer_description_hi = correct_answer_description_hi
                    hindi_q.marks = marks
                    hindi_q.negative_marks = negative_marks
                    hindi_q.degree_of_difficulty = degree_of_difficulty
                    hindi_q.evergreen_index = evergreen_index
                    hindi_q.current_relevance = current_relevance
                    hindi_q.current_relevance_topic = current_relevance_topic
                    hindi_q.exam_year = exam_year
                    hindi_q.save()

                    hindi_q.area_name.set(areas_qs)
                    hindi_q.section_name.set(sections_qs)
                    hindi_q.part_name.set(parts_qs)
                    hindi_q.chapter_name.set(chapters_qs)
                    hindi_q.topic_name.set(topics_qs)
                    hindi_q.subtopic_name.set(subtopics_qs)

                messages.success(request, "✅ Fill in the Blank Question updated successfully!")
                return redirect('view_questions')

        except Exception as e:
            messages.error(request, f"  An error occurred while editing: {e}")

    context = {
        'english_q': english_q,
        'hindi_q': hindi_q,
        'areas': areas,
        'sections': sections,
        'parts': parts,
        'chapters': chapters,
        'topics': topics,
        'subtopics': subtopics,
        "mark_options": ["0.5", "1.0", "1.5", "2.0", "2.5", "3.0"],
        "negative_mark_options": ["1.0", "0.5", "0.33", "0.25", "0.2", "0"],
    }

    return render(request, 'question_bank/edit_question/edit_fill_in_the_blank_form.html', context)
# ************************* Edit Fill in the Blank Type Question Updated *********************************************


from django.shortcuts import get_object_or_404, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from .models import QuestionBank

@login_required
def delete_question(request, pk):
    question = get_object_or_404(QuestionBank, pk=pk)
    question.delete()
    messages.success(request, "Question deleted successfully.")
    return redirect('view_questions')

# Lectures Notes Views

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction

from .models import Area, PartName, ChapterName, TopicName, SubTopicName, LectureNote
from .forms import LectureNoteForm


@login_required
def upload_lecture_note_view(request):
    if request.method == "POST":
        form = LectureNoteForm(request.POST, request.FILES)

        # ✅ Manually fetch files because they are not part of the model
        note_file_en = request.FILES.get("note_file_en")
        note_file_hi = request.FILES.get("note_file_hi")

        if not (note_file_en or note_file_hi):
            messages.error(request, "Please upload at least one file (English or Hindi).")
            return redirect(request.path_info)

        # ✅ Check required fields
        area = request.POST.get("area")
        part = request.POST.get("part")
        chapter = request.POST.get("chapter")
        ctpl = request.POST.get("ctpl")
        note_type = request.POST.get("note_type")

        if not area or not part or not chapter:
            messages.error(request, "Area, Part, and Chapter are required.")
            return redirect(request.path_info)

        topic = request.POST.get("topic") or None
        subtopic = request.POST.get("subtopic") or None

        try:
            with transaction.atomic():
                if note_file_en:
                    LectureNote.objects.create(
                        language="en",
                        note_type=note_type,
                        ctpl=ctpl,
                        note_file=note_file_en,
                        area_id=area,
                        part_id=part,
                        chapter_id=chapter,
                        topic_id=topic,
                        subtopic_id=subtopic,
                        created_by=request.user
                    )
                if note_file_hi:
                    LectureNote.objects.create(
                        language="hi",
                        note_type=note_type,
                        ctpl=ctpl,
                        note_file=note_file_hi,
                        area_id=area,
                        part_id=part,
                        chapter_id=chapter,
                        topic_id=topic,
                        subtopic_id=subtopic,
                        created_by=request.user
                    )
            messages.success(request, "Lecture note(s) uploaded successfully.")
            return redirect("upload_lecture_note")

        except Exception as e:
            messages.error(request, f"An error occurred: {e}")
            return redirect(request.path_info)

    else:
        form = LectureNoteForm()

    return render(request, "question_bank/upload_lecture_note.html", {
        "form": form,
        "areas": Area.objects.all(),
        "parts": PartName.objects.all(),
        "chapters": ChapterName.objects.all(),
        "topics": TopicName.objects.all(),
        "subtopics": SubTopicName.objects.all(),
    })


@login_required
def list_lecture_notes(request):
    notes = LectureNote.objects.all().order_by('-created_at')
    return render(request, "question_bank/list_notes.html", {"notes": notes})


@login_required
def view_lecture_note_detail(request, pk):
    note = get_object_or_404(LectureNote, pk=pk)
    return render(request, "question_bank/note_detail_flipbook.html", {"note": note})




# Input Suggestion Views Started 

from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from django.db.utils import IntegrityError
import re

from .models import (
    InputSuggestion,
    InputSuggestionImage,
    InputSuggestionDocument,
    Area, PartName, ChapterName, TopicName, SubTopicName, ExamName, HashtagsName
)


@login_required
def add_input_suggestion(request):
    if request.method == "POST":
        try:
            # ✅ Basic fields
            languages = request.POST.getlist('language')
            language = ",".join(languages)

            brief_description = request.POST.get('brief_description')
            details = request.POST.get('details')
            other_text = request.POST.get('other_text')
            question_video = request.FILES.get('question_video')
            source = request.POST.get('source', 'self')
            approval_status = 'pending_faculty'

            # ✅ Links & credits
            question_links_list = request.POST.getlist('question_link[]')
            question_link = ', '.join([l.strip() for l in question_links_list if l.strip()])
            credits_list = request.POST.getlist('credit_or_courtesy[]')
            credit_or_courtesy = ', '.join([c.strip() for c in credits_list if c.strip()])

            # ✅ Relevance
            relevance_topics_list = request.POST.getlist('current_relevance_topic[]')
            current_relevance_topic = ' || '.join([t.strip() for t in relevance_topics_list if t.strip()])
            current_relevance = request.POST.get('current_relevance')

            # ✅ Dropdown IDs
            area_ids = request.POST.getlist('area_name[]')
            part_ids = request.POST.getlist('part_name[]')
            chapter_ids = request.POST.getlist('chapter_name[]')
            topic_ids = request.POST.getlist('topic_name[]')
            subtopic_ids = request.POST.getlist('sub_topic_name[]')
            exam_ids = request.POST.getlist('exam_name[]')

            # ✅ NEW: Shortcodes (split on comma OR space)
            shortcode_raw = request.POST.get('shortcodeInput', '')
            shortcodes = [s.strip() for s in re.split(r'[\s,]+', shortcode_raw) if s.strip()]

            # ✅ Hashtags
            hashtags_input = request.POST.get('hashtags') or request.POST.get('hashtagsHiddenInput', '')
            user_hashtags = [h.strip().lstrip('#') for h in hashtags_input.split(',') if h.strip()]

            if not languages or not brief_description or not details or not current_relevance:
                messages.error(request, "Please fill in all required fields.")
                return redirect(request.path_info)

            with transaction.atomic():
                suggestion = InputSuggestion.objects.create(
                    language=language,
                    brief_description=brief_description,
                    details=details,
                    question_link=question_link,
                    other_text=other_text,
                    question_video=question_video,
                    source=source,
                    approval_status=approval_status,
                    credit_or_courtesy=credit_or_courtesy,
                    current_relevance=current_relevance,
                    current_relevance_topic=current_relevance_topic,
                    created_by=request.user
                )

                # ✅ If shortcodes | resolve hierarchy
                if shortcodes:
                    resolved_subtopics = SubTopicName.objects.filter(sub_topic_short_Code__in=shortcodes)
                    if resolved_subtopics.exists():
                        suggestion.subtopic_name.set(resolved_subtopics)

                        # Cascade relations
                        topic_ids = set(resolved_subtopics.values_list("topic__topic_SI_number", flat=True))
                        chapter_ids = set(resolved_subtopics.values_list("topic__chapter__chapter_number", flat=True))
                        part_ids = set(resolved_subtopics.values_list("topic__chapter__part__part_serial", flat=True))
                        area_ids = set(resolved_subtopics.values_list("topic__chapter__part__section__area__area_SI_Code", flat=True))
                        exam_ids = set(
                            ExamName.objects.filter(subtopics__in=resolved_subtopics)
                            .values_list("exam_SI_Number", flat=True)
                        )

                        # Apply relations
                        suggestion.topic_name.set(TopicName.objects.filter(topic_SI_number__in=topic_ids))
                        suggestion.chapter_name.set(ChapterName.objects.filter(chapter_number__in=chapter_ids))
                        suggestion.part_name.set(PartName.objects.filter(part_serial__in=part_ids))
                        suggestion.area_name.set(Area.objects.filter(area_SI_Code__in=area_ids))
                        suggestion.exams.set(ExamName.objects.filter(exam_SI_Number__in=exam_ids))

                        # Auto hashtags
                        auto_hashtags = HashtagsName.objects.filter(subtopics__in=resolved_subtopics).distinct()
                        for tag in auto_hashtags:
                            suggestion.hashtags.add(tag)

                # ✅ Else | use manual dropdowns
                else:
                    if area_ids:
                        suggestion.area_name.set(Area.objects.filter(area_SI_Code__in=area_ids))
                    if part_ids:
                        suggestion.part_name.set(PartName.objects.filter(part_serial__in=part_ids))
                    if chapter_ids:
                        suggestion.chapter_name.set(ChapterName.objects.filter(chapter_number__in=chapter_ids))
                    if topic_ids:
                        suggestion.topic_name.set(TopicName.objects.filter(topic_SI_number__in=topic_ids))
                    if subtopic_ids:
                        subtopics = SubTopicName.objects.filter(sub_topic_SI_Number__in=subtopic_ids)
                        suggestion.subtopic_name.set(subtopics)

                        auto_hashtags = HashtagsName.objects.filter(subtopics__in=subtopics).distinct()
                        for tag in auto_hashtags:
                            suggestion.hashtags.add(tag)
                    if exam_ids:
                        suggestion.exams.set(ExamName.objects.filter(exam_SI_Number__in=exam_ids))

                    # ✅ Create/link manual hashtags (SAFE VERSION)

                    for tag in user_hashtags:
                        base_slug = re.sub(r'[^\w\s-]', '', tag).strip().replace(' ', '_')

                        if not base_slug:
                            continue

                        slug = base_slug
                        counter = 1

                        # Keep checking DB until unique slug found
                        while HashtagsName.objects.filter(hashtags_SI_Number=slug).exists():
                            slug = f"{base_slug}_{counter}"
                            counter += 1

                        obj, created = HashtagsName.objects.get_or_create(
                            hashtags_SI_Number=slug,
                            defaults={'name': tag}
                        )

                        suggestion.hashtags.add(obj)

                        # Attach hashtag to subtopics
                        if suggestion.subtopic_name.exists():
                            for subtopic in suggestion.subtopic_name.all():
                                subtopic.hashtags.add(obj)

                # ✅ Save files
                for image in request.FILES.getlist('question_images'):
                    InputSuggestionImage.objects.create(question=suggestion, image=image)
                for document in request.FILES.getlist('question_documents'):
                    InputSuggestionDocument.objects.create(question=suggestion, document=document)

                messages.success(request, "✅ Input Suggestion added successfully!")
                return redirect('input-suggestion-list')

        except Exception as e:
            messages.error(request, f" An error occurred: {e}")
            return redirect(request.path_info)

    return render(request, 'question_bank/add_input_suggestion.html', {
        'areas': Area.objects.all(),
        'parts': PartName.objects.all(),
        'chapters': ChapterName.objects.all(),
        'topics': TopicName.objects.all(),
        'subtopics': SubTopicName.objects.all(),
        'exams': ExamName.objects.all(),
    })

from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required
from .models import (
    InputSuggestion, QuestionBank, Area, PartName, ChapterName,
    TopicName, SubTopicName, HashtagsName, LectureNote  # ✅ include LectureNote
)

@login_required
def view_input_suggestion(request, pk=None):
    # ✅ Base queryset
    questions = InputSuggestion.objects.prefetch_related(
        'area_name', 'part_name', 'chapter_name',
        'topic_name', 'subtopic_name', 'hashtags'
    ).distinct()

    # ✅ Extract updated filters
    area_name = request.GET.get('area_name')
    part_name = request.GET.get('part_name')
    chapter_name = request.GET.get('chapter_name')
    topic_name = request.GET.get('topic_name')
    subtopic_name = request.GET.get('subtopic_name')
    hashtag = request.GET.get('hashtag')

    # ✅ Apply filters (uses ManyToMany robust match)
    if area_name:
        questions = questions.filter(area_name__area_SI_Code__in=[str(area_name)])
    if part_name:
        questions = questions.filter(part_name__part_serial__in=[str(part_name)])
    if chapter_name:
        questions = questions.filter(chapter_name__chapter_number__in=[str(chapter_name)])
    if topic_name:
        questions = questions.filter(topic_name__topic_SI_number__in=[str(topic_name)])
    if subtopic_name:
        questions = questions.filter(subtopic_name__sub_topic_SI_Number__in=[str(subtopic_name)])
    if hashtag:
        questions = questions.filter(hashtags__hashtags_SI_Number__in=[str(hashtag)])

    # ✅ Related subtopic and chapter lookup
    suggestion = None
    subtopic_ids = []
    chapter_ids = []
    lecture_notes = LectureNote.objects.none()

    if pk:
        suggestion = get_object_or_404(InputSuggestion, pk=pk)
        subtopic_ids = list(suggestion.subtopic_name.values_list('sub_topic_SI_Number', flat=True))
        chapter_ids = list(suggestion.chapter_name.values_list('chapter_number', flat=True))

        # ✅ Fetch lecture notes based on chapter match
        if chapter_ids:
            lecture_notes = LectureNote.objects.filter(chapter__chapter_number__in=chapter_ids).order_by('-created_at')[:10]
    else:
        subtopic_ids = (
            questions.filter(subtopic_name__isnull=False)
            .values_list('subtopic_name__sub_topic_SI_Number', flat=True)
            .distinct()
        )

    # ✅ Build grouped related QuestionBank pairs
    grouped_questions = {}
    if subtopic_ids:
        related_qs = (
            QuestionBank.objects.filter(subtopic_name__sub_topic_SI_Number__in=subtopic_ids)
            .distinct().order_by('base_question_id', 'language')
        )
        for q in related_qs:
            base_id = q.base_question_id
            if base_id not in grouped_questions:
                grouped_questions[base_id] = {'english': None, 'hindi': None}
            if q.language == 'e':
                grouped_questions[base_id]['english'] = q
            elif q.language == 'h':
                grouped_questions[base_id]['hindi'] = q

    context = {
        'questions': questions.distinct(),
        'suggestion': suggestion if pk else None,
        'areas': Area.objects.all(),
        'parts': PartName.objects.all(),
        'chapters': ChapterName.objects.all(),
        'topics': TopicName.objects.all(),
        'subtopics': SubTopicName.objects.all(),
        'hashtags': HashtagsName.objects.all(),
        'grouped_questions': grouped_questions,
        'lecture_notes': lecture_notes,  # ✅ include lecture notes
        'request': request,
    }
    return render(request, 'question_bank/input_suggestion_list.html', context)

from django.shortcuts import get_object_or_404, render
from .models import InputSuggestion, LectureNote

from django.shortcuts import get_object_or_404, render
from .models import QuestionBank, InputSuggestion, LectureNote

def question_blog_view(request, question_id):
    question = get_object_or_404(InputSuggestion, id=question_id)

    # ✅ Related LectureNotes by chapter
    chapter_ids = list(question.chapter_name.values_list('chapter_number', flat=True)) if hasattr(question.chapter_name, 'all') else [question.chapter_name.chapter_number]
    related_notes = LectureNote.objects.filter(chapter__chapter_number__in=chapter_ids).order_by('-created_at') if chapter_ids else []

    # ✅ Related Questions by subtopic
    subtopic_ids = list(question.subtopic_name.values_list('sub_topic_SI_Number', flat=True))
    grouped_questions = {}

    if subtopic_ids:
        related_qs = QuestionBank.objects.filter(subtopic_name__sub_topic_SI_Number__in=subtopic_ids).distinct().order_by('base_question_id', 'language')
        for q in related_qs:
            if q.base_question_id not in grouped_questions:
                grouped_questions[q.base_question_id] = {'english': None, 'hindi': None}
            if q.language == 'e':
                grouped_questions[q.base_question_id]['english'] = q
            elif q.language == 'h':
                grouped_questions[q.base_question_id]['hindi'] = q

    return render(
        request,
        'question_bank/view_input_suggestion.html',
        {
            'question': question,
            'grouped_questions': grouped_questions,
            'related_notes': related_notes,
        }
    )

import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from openai import OpenAI

client = OpenAI(api_key=config("OPENAI_API_KEY"))

@login_required
@csrf_exempt
def generate_ai_hashtags(request):
    if request.method == "POST":
        try:
            data = json.loads(request.body)
            brief = data.get("brief_description", "")
            details = data.get("details", "")
            resources = data.get("resources", [])
            existing_hashtags = data.get("existing_hashtags", "")

            prompt = f"""
            You are an expert content strategist. Based on the following input, suggest 5-10 new hashtags.
            
            Brief Description: {brief}
            Details: {details}
            Resource Links: {', '.join(resources)}
            Existing Hashtags: {existing_hashtags}
            
            Return only hashtags (without #), separated by commas.
            """

            response = client.chat.completions.create(
                model="gpt-4o-mini",
                messages=[{"role": "user", "content": prompt}]
            )
            hashtags_text = response.choices[0].message.content
            hashtags = [h.strip().lstrip("#") for h in hashtags_text.split(",") if h.strip()]

            return JsonResponse({"status": "success", "hashtags": hashtags})
        except Exception as e:
            return JsonResponse({"status": "error", "message": str(e)})
    return JsonResponse({"status": "error", "message": "Invalid request"})


from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.text import slugify
import json

from .models import HashtagsName, SubTopicName

def generate_unique_slug(tag):
    """
    Generates a unique slug for hashtags_SI_Number field.
    Handles Hindi and English hashtags.
    """
    base_slug = slugify(tag, allow_unicode=True)
    slug = base_slug
    counter = 1
    while HashtagsName.objects.filter(hashtags_SI_Number=slug).exists():
        slug = f"{base_slug}_{counter}"
        counter += 1
    return slug

from django.utils.text import slugify
from django.db import transaction

@login_required
@csrf_exempt
def save_ai_hashtags(request):
    if request.method == "POST":
        try:
            data = json.loads(request.body)
            hashtags = data.get("hashtags", [])
            subtopic_ids = data.get("subtopic_ids", [])

            saved = []

            with transaction.atomic():

                for tag in hashtags:
                    tag = tag.strip()
                    if not tag:
                        continue

                    # ✅ First check if name already exists
                    existing = HashtagsName.objects.filter(name__iexact=tag).first()
                    if existing:
                        obj = existing
                    else:
                        # ✅ Generate safe unique slug
                        base_slug = slugify(tag, allow_unicode=True)
                        slug = base_slug
                        counter = 1

                        while HashtagsName.objects.filter(hashtags_SI_Number=slug).exists():
                            slug = f"{base_slug}_{counter}"
                            counter += 1

                        obj = HashtagsName.objects.create(
                            name=tag,
                            hashtags_SI_Number=slug
                        )

                    # ✅ Attach to subtopics
                    for sid in subtopic_ids:
                        sub = SubTopicName.objects.filter(
                            sub_topic_SI_Number=sid
                        ).first()

                        if sub:
                            sub.hashtags.add(obj)

                    saved.append(tag)

            return JsonResponse({"status": "success", "saved": saved})

        except Exception as e:
            return JsonResponse({"status": "error", "message": str(e)})

    return JsonResponse({"status": "error", "message": "Invalid request method"})


from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.shortcuts import render
from question_bank.models import (
    QuestionBank, Area, Section, PartName,
    ChapterName, TopicName, SubTopicName
)

def view_questions(request):
    # 🔹 Base queryset (ALL questions, not paginated yet)
    questions = QuestionBank.objects.filter(
        created_by=request.user
    ).prefetch_related(
        'area_name', 'section_name', 'part_name',
        'chapter_name', 'topic_name', 'subtopic_name'
    )

    # 🔹 Read filters
    type_of_question = request.GET.get('question_source')
    question_sub_type = request.GET.get('question_type')
    area_name = request.GET.get('area_name')
    section_name = request.GET.get('section_name')
    part_name = request.GET.get('part_name')
    chapter_name = request.GET.get('chapter_name')
    topic_name = request.GET.get('topic_name')
    subtopic_name = request.GET.get('subtopic_name')

    # 🔹 Apply filters
    if type_of_question:
        questions = questions.filter(type_of_question=type_of_question)
    if question_sub_type:
        questions = questions.filter(question_sub_type=question_sub_type)
    # if area_name:
    #     questions = questions.filter(area_name__id=area_name)
    # if area_name:
    #     questions = questions.filter(area_name=area_name)

    # if section_name:
    #     questions = questions.filter(section_name__id=section_name)
    # if part_name:
    #     questions = questions.filter(part_name__id=part_name)
    # if chapter_name:
    #     questions = questions.filter(chapter_name__id=chapter_name)
    # if topic_name:
    #     questions = questions.filter(topic_name__id=topic_name)
    # if subtopic_name:
    #     questions = questions.filter(subtopic_name__id=subtopic_name)

    # questions = questions.distinct()

    if area_name:
        questions = questions.filter(area_name=area_name)

    if section_name:
        questions = questions.filter(section_name=section_name)

    if part_name:
        questions = questions.filter(part_name=part_name)

    if chapter_name:
        questions = questions.filter(chapter_name=chapter_name)

    if topic_name:
        questions = questions.filter(topic_name=topic_name)

    if subtopic_name:
        questions = questions.filter(subtopic_name=subtopic_name)


    # ======================================================
    # | LANGUAGE COUNTS (FILTER AWARE)
    # ======================================================

    total_questions = (
    questions
    .values('base_question_id')
    .distinct()
    .count()
    )
 
    total_english = (
        questions.filter(language='e')
        .values('base_question_id')
        .distinct()
        .count()
    )

    total_hindi = (
        questions.filter(language='h')
        .values('base_question_id')
        .distinct()
        .count()
    )

    # | TOTAL AI QUESTIONS (FILTER AWARE)

    total_ai = (
        questions
        .filter(ai_version__gt=0)
        .values('base_question_id', 'ai_version')
        .distinct()
        .count()
    )
    # ======================================================
    # 🔹 GROUP FIRST (NO PAGINATION YET)
    # ======================================================

    grouped_questions = {}

    for q in questions.order_by('-created_at'):
        base_id = q.base_question_id
        ai_version = q.ai_version or 0

        if base_id not in grouped_questions:
            grouped_questions[base_id] = {
                'original': {'english': None, 'hindi': None},
                'ai_versions': {}
            }

        # ORIGINAL
        if ai_version == 0:
            if q.language == 'e':
                grouped_questions[base_id]['original']['english'] = q
            elif q.language == 'h':
                grouped_questions[base_id]['original']['hindi'] = q

        # AI
        else:
            if ai_version not in grouped_questions[base_id]['ai_versions']:
                grouped_questions[base_id]['ai_versions'][ai_version] = {
                    'english': None,
                    'hindi': None
                }

            if q.language == 'e':
                grouped_questions[base_id]['ai_versions'][ai_version]['english'] = q
            elif q.language == 'h':
                grouped_questions[base_id]['ai_versions'][ai_version]['hindi'] = q


    # ======================================================
    # 🔹 NOW PAGINATE BASE QUESTIONS (NOT RAW ROWS)
    # ======================================================

    grouped_list = list(grouped_questions.items())

    paginator = Paginator(grouped_list, 20)  # 20 base questions per page
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    grouped_questions = dict(page_obj.object_list)
    # Convert ai_versions dict into list (template-safe)
    for base_id, data in grouped_questions.items():
        data['ai_versions_list'] = [
            {
                'version': version,
                'english': pair['english'],
                'hindi': pair['hindi'],
            }
            for version, pair in data['ai_versions'].items()
        ]

    # ======================================================
    # 🔹 CONTEXT
    # ======================================================
    context = {
        'grouped_questions': grouped_questions,
        'QUESTION_SOURCES': QuestionBank.QUESTION_SOURCES,
        'QUESTION_TYPES': QuestionBank.QUESTION_TYPES,
        'areas': Area.objects.all(),
        'sections': Section.objects.all(),
        'parts': PartName.objects.all(),
        'chapters': ChapterName.objects.all(),
        'topics': TopicName.objects.all(),
        'subtopics': SubTopicName.objects.all(),
        'page_obj': page_obj,

        # | NEW COUNTS
        'total_questions': total_questions,
        'total_english': total_english,
        'total_hindi': total_hindi,
        'total_ai': total_ai,   # ✅ added
        
    }

    return render(request, 'question_bank/add_question/view_questions.html', context)










# Input Suggestion Views End 

# from django.contrib.auth.decorators import login_required
# from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
# from django.shortcuts import render
# from .models import (
#     QuestionBank,           
#     Area,
#     Section,
#     PartName,
#     ChapterName,
#     TopicName,
#     SubTopicName
# )

# @login_required
# def view_questions(request):
#     # Filter questions created by the logged-in user
#     questions = QuestionBank.objects.filter(
#         created_by=request.user
#     ).prefetch_related(
#         'area_name', 'section_name', 'part_name',
#         'chapter_name', 'topic_name', 'subtopic_name'
#     ).order_by('-created_at')  # Order by creation date (latest first)

    # # Get filter parameters from the request
    # type_of_question = request.GET.get('question_source')
    # question_sub_type = request.GET.get('question_type')
    # area_name = request.GET.get('area_name')
    # section_name = request.GET.get('section_name')
    # part_name = request.GET.get('part_name')
    # chapter_name = request.GET.get('chapter_name')
    # topic_name = request.GET.get('topic_name')
    # subtopic_name = request.GET.get('subtopic_name')

    # # Apply filters based on the URL parameters
    # if type_of_question:
    #     questions = questions.filter(type_of_question=type_of_question)
    # if question_sub_type:
    #     questions = questions.filter(question_sub_type=question_sub_type)
    # if area_name:
    #     questions = questions.filter(area_name__area_SI_Code=area_name)
    # if section_name:
    #     questions = questions.filter(section_name__section_Unit_SI=section_name)
    # if part_name:
    #     questions = questions.filter(part_name__part_serial=part_name)
    # if chapter_name:
    #     questions = questions.filter(chapter_name__chapter_number=chapter_name)
    # if topic_name:
    #     questions = questions.filter(topic_name__topic_SI_number=topic_name)
    # if subtopic_name:
    #     questions = questions.filter(subtopic_name__sub_topic_SI_Number=subtopic_name)

    # questions = questions.distinct()  # Ensure distinct questions

    # # Paginate the questions, 50 per page
    # paginator = Paginator(questions, 500)  # Show 50 questions per page
    # page_number = request.GET.get('page')  # Get the current page number

    # # Handle invalid page numbers
    # try:
    #     page_obj = paginator.get_page(page_number)  # Get the page object
    # except PageNotAnInteger:
    #     page_obj = paginator.get_page(1)  # Default to the first page if page number is not an integer
    # except EmptyPage:
    #     page_obj = paginator.get_page(paginator.num_pages)  # Show the last page if the page number is out of range

    # # Group questions by base_question_id
    # grouped_questions = {}
    # for question in page_obj:
    #     base_id = question.base_question_id
    #     if base_id not in grouped_questions:
    #         grouped_questions[base_id] = {'english': None, 'hindi': None}
    #     if question.language == 'e':
    #         grouped_questions[base_id]['english'] = question
    #     elif question.language == 'h':
    #         grouped_questions[base_id]['hindi'] = question

    # context = {
    #     'grouped_questions': grouped_questions,
    #     'QUESTION_SOURCES': QuestionBank.QUESTION_SOURCES,
    #     'QUESTION_TYPES': QuestionBank.QUESTION_TYPES,
    #     'areas': Area.objects.all(),
    #     'sections': Section.objects.all(),
    #     'parts': PartName.objects.all(),
    #     'chapters': ChapterName.objects.all(),
    #     'topics': TopicName.objects.all(),
    #     'subtopics': SubTopicName.objects.all(),
    #     'request': request,
    #     'page_obj': page_obj,  # Add page_obj for pagination
    # }
    # return render(request, 'question_bank/add_question/view_questions.html', context)


def add_quote_idiom_phrase(request):
    if request.method == 'POST':
        # Get all form data
        type = request.POST.get('type')
        content = request.POST.get('content')
        meaning = request.POST.get('meaning', '')  # Optional meaning field
        author = request.POST.get('author', '')  # Optional author field
        exam_ids = request.POST.getlist('exam_name[]')  # Get multiple exam IDs
        subject_ids = request.POST.getlist('subject_name[]')  # Get multiple subject IDs
        area_ids = request.POST.getlist('area_name[]')  # Get multiple area IDs
        part_ids = request.POST.getlist('part_name[]')  # Get multiple part IDs
        chapter_ids = request.POST.getlist('chapter_name[]')  # Get multiple chapter IDs
        topic_ids = request.POST.getlist('topic_name[]')  # Get multiple topic IDs
        new_topic_name = request.POST.get('new_topic_name', '')  # New topic name if manually entered

        # Remove 'other' from topic_ids, as 'other' is not a valid ID
        if 'other' in topic_ids:
            topic_ids.remove('other')

        # Create the QuoteIdiomPhrase instance
        new_entry = QuoteIdiomPhrase.objects.create(
            type=type,
            content=content,
            meaning=meaning if type in ['idiom', 'phrase'] else '',  # Add meaning only for idioms or phrases
            author=author,  # Add author if provided
            created_by=request.user
        )

        # Handle ManyToMany fields after creating the instance
        # if exam_ids:
            # exams = ExamName.objects.filter(id__in=exam_ids)
            # new_entry.exams.set(exams)

        # if subject_ids:
            # subjects = Subject.objects.filter(id__in=subject_ids)
            # new_entry.subjects.set(subjects)

        if area_ids:
            areas = Area.objects.filter(id__in=area_ids)
            new_entry.areas.set(areas)

        if part_ids:
            parts = PartName.objects.filter(id__in=part_ids)
            new_entry.parts.set(parts)

        if chapter_ids:
            chapters = ChapterName.objects.filter(id__in=chapter_ids)
            new_entry.chapters.set(chapters)

        # Handle manually entered topic with association to the selected chapter
        if new_topic_name and chapter_ids:
            # Associate the manually entered topic with the first selected chapter
            related_chapter = ChapterName.objects.filter(id=chapter_ids[0]).first()
            new_topic = TopicName.objects.create(name=new_topic_name, chapter=related_chapter)
            new_entry.topics.add(new_topic)

        # Handle selected topics (without 'other')
        if topic_ids:
            selected_topics = TopicName.objects.filter(id__in=topic_ids)
            new_entry.topics.add(*selected_topics)

        # Display success message and redirect
        messages.success(request, 'Your Quote, Idiom, or Phrase has been added successfully!')
        return redirect('add_quote_idiom_phrase')

    # Fetch all exam names for the form
    # exam_names = ExamName.objects.all()
    return render(request, 'question_bank/add_quote_idiom_phrase.html')





def quotes_idioms_phrases_view(request):
    # Fetch all quotes, idioms, and phrases from the database
    quotes_idioms_phrases = QuoteIdiomPhrase.objects.all().order_by('-created_at')
    
    # Render the template with the fetched data
    return render(request, 'question_bank/quotes_idioms_phrases.html', {
        'quotes_idioms_phrases': quotes_idioms_phrases
    })





def analytics_dashboard(request):
    # Filter and annotate data for users with questions, suggestions, or quote/phrase/idiom entries
    users_data = User.objects.annotate(
        user_name=Concat('first_name', Value(' '), 'last_name'),
        total_input_suggestions=Count('inputsuggestion', filter=Q(inputsuggestion__isnull=False)),
        total_questions=Count('questionbank', filter=Q(questionbank__isnull=False)),
        simple_type_count=Count('questionbank', filter=Q(questionbank__question_sub_type='simple_type')),
        list1_type_count=Count('questionbank', filter=Q(questionbank__question_sub_type='list_type_1')),
        list2_type_count=Count('questionbank', filter=Q(questionbank__question_sub_type='list_type_2')),
        ra_type_count=Count('questionbank', filter=Q(questionbank__question_sub_type='r_and_a_type')),
        true_false_type_count=Count('questionbank', filter=Q(questionbank__question_sub_type='true_and_false_type')),
        fill_blank_type_count=Count('questionbank', filter=Q(questionbank__question_sub_type='fill_in_the_blank_type')),
        phrases_uploaded=Count('quoteidiomphrase', filter=Q(quoteidiomphrase__type='phrase')),
        idioms_uploaded=Count('quoteidiomphrase', filter=Q(quoteidiomphrase__type='idiom')),
        quotes_uploaded=Count('quoteidiomphrase', filter=Q(quoteidiomphrase__type='quote')),
    ).filter(
        Q(total_input_suggestions__gt=0) | 
        Q(total_questions__gt=0) | 
        Q(phrases_uploaded__gt=0) |
        Q(idioms_uploaded__gt=0) | 
        Q(quotes_uploaded__gt=0)
    ).values_list(
        'user_name', 'email', 'total_input_suggestions', 'total_questions', 
        'simple_type_count', 'list1_type_count', 'list2_type_count',
        'ra_type_count', 'true_false_type_count', 'fill_blank_type_count',
        'phrases_uploaded', 'idioms_uploaded', 'quotes_uploaded',
        named=True
    )
    # Prepare data for charts
    users = [user.user_name for user in users_data]
    emails = [user.email for user in users_data]
    suggestion_counts = [user.total_input_suggestions for user in users_data]
    question_counts = [user.total_questions for user in users_data]
    simple_counts = [user.simple_type_count for user in users_data]
    list1_counts = [user.list1_type_count for user in users_data]
    list2_counts = [user.list2_type_count for user in users_data]
    ra_counts = [user.ra_type_count for user in users_data]
    true_false_counts = [user.true_false_type_count for user in users_data]
    fill_blank_counts = [user.fill_blank_type_count for user in users_data]
    phrase_counts = [user.phrases_uploaded for user in users_data]
    idiom_counts = [user.idioms_uploaded for user in users_data]
    quote_counts = [user.quotes_uploaded for user in users_data]

    context = {
        'users': json.dumps(users),
        'emails': json.dumps(emails),
        'suggestion_counts': json.dumps(suggestion_counts),
        'question_counts': json.dumps(question_counts),
        'simple_counts': json.dumps(simple_counts),
        'list1_counts': json.dumps(list1_counts),
        'list2_counts': json.dumps(list2_counts),
        'ra_counts': json.dumps(ra_counts),
        'true_false_counts': json.dumps(true_false_counts),
        'fill_blank_counts': json.dumps(fill_blank_counts),
        'phrase_counts': json.dumps(phrase_counts),
        'idiom_counts': json.dumps(idiom_counts),
        'quote_counts': json.dumps(quote_counts),
    }

    return render(request, 'question_bank/analytics_dashboard.html', context)


@login_required
def new_dashboard_view(request):
    today = timezone.now().date()
    this_week_start = today - timedelta(days=7)  # Last 7 days
    
    # Date range for earlier week (8–14 days ago)
    earlier_week_start, earlier_week_end = today - timedelta(days=14), today - timedelta(days=7)

    user_is_admin = request.user.user_type == 'admin'

    # Prepare data for this week
    this_week_report_data = []
    earlier_week_report_data = []

    # Fetch users based on user type
    users = User.objects.all() if user_is_admin else User.objects.filter(id=request.user.id)

    # Collect This Week's Reports (last 7 days)
    for user in users:
        total_questions = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start).count()
        total_phrases = QuoteIdiomPhrase.objects.filter(created_by=user, created_at__gte=this_week_start).count()
        total_suggestions = InputSuggestion.objects.filter(created_by=user, created_at__gte=this_week_start).count()

        simple_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='simple_type').count()
        list_1_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='list_type_1').count()
        list_2_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='list_type_2').count()
        ra_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='r_and_a_type').count()
        true_false_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='true_and_false_type').count()
        fill_blank_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='fill_in_the_blank_type').count()

        this_week_report_data.append({
            'user': user,
            'total_questions': total_questions,
            'total_phrases': total_phrases,
            'total_suggestions': total_suggestions,
            'simple_type_count': simple_type_count,
            'list_1_type_count': list_1_type_count,
            'list_2_type_count': list_2_type_count,
            'ra_type_count': ra_type_count,
            'true_false_type_count': true_false_type_count,
            'fill_blank_count': fill_blank_count,
        })

    # Collect Earlier Week's Reports (8–14 days ago)
    for user in users:
        total_questions = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end).count()
        total_phrases = QuoteIdiomPhrase.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end).count()
        total_suggestions = InputSuggestion.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end).count()

        simple_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='simple_type').count()
        list_1_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='list_type_1').count()
        list_2_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='list_type_2').count()
        ra_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='r_and_a_type').count()
        true_false_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='true_and_false_type').count()
        fill_blank_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='fill_in_the_blank_type').count()

        earlier_week_report_data.append({
            'user': user,
            'total_questions': total_questions,
            'total_phrases': total_phrases,
            'total_suggestions': total_suggestions,
            'simple_type_count': simple_type_count,
            'list_1_type_count': list_1_type_count,
            'list_2_type_count': list_2_type_count,
            'ra_type_count': ra_type_count,
            'true_false_type_count': true_false_type_count,
            'fill_blank_count': fill_blank_count,
        })

    # Get the last generated dates
    this_week_generated_date = Report.objects.filter(report_type='this_week').order_by('-report_date').first()
    earlier_week_generated_date = Report.objects.filter(report_type='earlier').order_by('-report_date').first()

    context = {
        'this_week_report_data': this_week_report_data,
        'earlier_week_report_data': earlier_week_report_data,
        'this_week_generated_date': this_week_generated_date.report_date if this_week_generated_date else None,
        'earlier_week_generated_date': earlier_week_generated_date.report_date if earlier_week_generated_date else None,
    }
    return render(request, 'question_bank/dashboard.html', context)





@login_required
def generate_this_week_csv(request):
    today = timezone.now().date()
    this_week_start = today - timedelta(days=7)

    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="this_week_report.csv"'
    writer = csv.writer(response)

    writer.writerow(['Sr. No.', 'Email', 'User Name', 'No. of Questions Uploaded', 'No. of Phrases/Idioms/Quotes', 'No. of Input Suggestions',
                     'Simple Type', 'List I Type', 'List II Type', 'R & A Type', 'True & False', 'Fill in the Blank'])

    users = User.objects.all() if request.user.user_type == 'admin' else User.objects.filter(id=request.user.id)

    for idx, user in enumerate(users, 1):
        total_questions = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start).count()
        total_phrases = QuoteIdiomPhrase.objects.filter(created_by=user, created_at__gte=this_week_start).count()
        total_suggestions = InputSuggestion.objects.filter(created_by=user, created_at__gte=this_week_start).count()

        simple_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='simple_type').count()
        list_1_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='list_type_1').count()
        list_2_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='list_type_2').count()
        ra_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='r_and_a_type').count()
        true_false_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='true_and_false_type').count()
        fill_blank_count = QuestionBank.objects.filter(created_by=user, created_at__gte=this_week_start, question_sub_type='fill_in_the_blank_type').count()

        writer.writerow([idx, user.email, f"{user.first_name} {user.last_name}", total_questions, total_phrases, total_suggestions,
                         simple_type_count, list_1_type_count, list_2_type_count, ra_type_count, true_false_type_count, fill_blank_count])

        # Save the report in the Report model
        Report.objects.create(
            report_type='this_week',
            report_date=today,
            created_by=user,
            total_questions=total_questions,
            total_phrases=total_phrases,
            total_suggestions=total_suggestions,
            simple_type_count=simple_type_count,
            list_1_type_count=list_1_type_count,
            list_2_type_count=list_2_type_count,
            ra_type_count=ra_type_count,
            true_false_type_count=true_false_type_count,
            fill_blank_count=fill_blank_count,
        )

    return response



@login_required
def generate_earlier_week_csv(request):
    earlier_week_start, earlier_week_end = timezone.now() - timedelta(days=14), timezone.now() - timedelta(days=7)

    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="earlier_week_report.csv"'
    writer = csv.writer(response)

    writer.writerow(['Sr. No.', 'Email', 'User Name', 'No. of Questions Uploaded', 'No. of Phrases/Idioms/Quotes', 'No. of Input Suggestions',
                     'Simple Type', 'List I Type', 'List II Type', 'R & A Type', 'True & False', 'Fill in the Blank'])

    users = User.objects.all() if request.user.user_type == 'admin' else User.objects.filter(id=request.user.id)

    for idx, user in enumerate(users, 1):
        total_questions = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end).count()
        total_phrases = QuoteIdiomPhrase.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end).count()
        total_suggestions = InputSuggestion.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end).count()

        simple_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='simple_type').count()
        list_1_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='list_type_1').count()
        list_2_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='list_type_2').count()
        ra_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='r_and_a_type').count()
        true_false_type_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='true_and_false_type').count()
        fill_blank_count = QuestionBank.objects.filter(created_by=user, created_at__gte=earlier_week_start, created_at__lt=earlier_week_end, question_sub_type='fill_in_the_blank_type').count()

        writer.writerow([idx, user.email, f"{user.first_name} {user.last_name}", total_questions, total_phrases, total_suggestions,
                         simple_type_count, list_1_type_count, list_2_type_count, ra_type_count, true_false_type_count, fill_blank_count])

        # Save the report in the Report model
        Report.objects.create(
            report_type='earlier',
            report_date=timezone.now(),
            created_by=user,
            total_questions=total_questions,
            total_phrases=total_phrases,
            total_suggestions=total_suggestions,
            simple_type_count=simple_type_count,
            list_1_type_count=list_1_type_count,
            list_2_type_count=list_2_type_count,
            ra_type_count=ra_type_count,
            true_false_type_count=true_false_type_count,
            fill_blank_count=fill_blank_count,
        )

    return response
    


# ✅ Your standard imports
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .models import (
    Batch, Area, Section, PartName, ChapterName, TopicName, SubTopicName,
    QuestionBank, BatchGeneratedQuestion
)
from django.core.paginator import Paginator
from docx import Document
from docx.shared import Pt
import os
from io import BytesIO
import zipfile
from datetime import datetime
from django.conf import settings


# =========================================
# ✅ FORM VIEW — AI AWARE PAIRING
# =========================================
def generate_test_form(request):
    batches = Batch.objects.all()
    areas = Area.objects.all()
    sections = Section.objects.all()
    parts = PartName.objects.all()
    chapters = ChapterName.objects.all()
    topics = TopicName.objects.all()
    subtopics = SubTopicName.objects.all()

    area_id = request.GET.get("area")
    section_id = request.GET.get("section")
    part_id = request.GET.get("part")
    chapter_id = request.GET.get("chapter")
    topic_id = request.GET.get("topic")
    subtopic_id = request.GET.get("subtopic")
    question_sub_type = request.GET.get("question_sub_type")
    exam_year = request.GET.get("exam_year")
    batch_id = request.GET.get("batch_id")
    page_number = request.GET.get("page")
    ai_filter = request.GET.get("ai_filter")  # NEW

    # ✅ Only English base for pairing
    en_questions = QuestionBank.objects.filter(language='e')

    # -------- FILTERS --------
    if area_id:
        en_questions = en_questions.filter(area_name__area_SI_Code=area_id)
    if section_id:
        en_questions = en_questions.filter(section_name__section_Unit_SI=section_id)
    if part_id:
        en_questions = en_questions.filter(part_name__part_serial=part_id)
    if chapter_id:
        en_questions = en_questions.filter(chapter_name__chapter_number=chapter_id)
    if topic_id:
        en_questions = en_questions.filter(topic_name__topic_SI_number=topic_id)
    if subtopic_id:
        en_questions = en_questions.filter(subtopic_name__sub_topic_SI_Number=subtopic_id)
    if question_sub_type:
        en_questions = en_questions.filter(question_sub_type=question_sub_type)
    if exam_year:
        en_questions = en_questions.filter(exam_year=exam_year)

    # ✅ AI FILTER
    if ai_filter == "base":
        en_questions = en_questions.filter(ai_version=0)
    elif ai_filter == "ai":
        en_questions = en_questions.filter(ai_version__gt=0)

    # ✅ ORDER PROPERLY
    en_questions = en_questions.order_by("base_question_id", "ai_version").distinct()

    # -------- PAIR ENGLISH + HINDI (AI SAFE) --------
    paired_questions = []

    for q_en in en_questions:
        q_hi = QuestionBank.objects.filter(
            base_question_id=q_en.base_question_id,
            language='h',
            ai_version=q_en.ai_version  # IMPORTANT FIX
        ).first()

        paired_questions.append({
            'english': q_en,
            'hindi': q_hi,
            'is_ai': q_en.ai_version > 0
        })

    paginator = Paginator(paired_questions, 100)
    page_obj = paginator.get_page(page_number)

    return render(request, "question_bank/generate_test.html", {
        "batches": batches,
        "questions": page_obj,
        "paginator": paginator,
        "page_obj": page_obj,
        "is_paginated": page_obj.has_other_pages(),
        "areas": areas,
        "sections": sections,
        "parts": parts,
        "chapters": chapters,
        "topics": topics,
        "subtopics": subtopics,
        "selected_batch_id": batch_id,
        "ai_filter": ai_filter,  # send to template
    })


# =========================================
# ✅ MANUAL GENERATE TEST VIEW (AI SAFE EXPORT)
# =========================================
def generate_test(request):
    if request.method == 'POST':

        batch_id = request.POST.get('batch_id')
        if not batch_id:
            return HttpResponse("Error: Batch not selected.", status=400)

        try:
            batch = Batch.objects.get(id=batch_id)
        except Batch.DoesNotExist:
            return HttpResponse("Error: Batch does not exist.", status=404)

        action = request.POST.get('action')

        # -------- RESET --------
        if action == 'reset':
            BatchGeneratedQuestion.objects.filter(batch=batch).delete()
            return redirect(f'/question-bank/generate-test/?batch_id={batch_id}')

        # -------- MANUAL GENERATE --------
        elif action == 'manual_generate':

            selected_ids = request.POST.getlist('manual_questions')
            if not selected_ids:
                return HttpResponse("No questions selected.", status=400)

            # Get selected English questions
            selected_en_questions = QuestionBank.objects.filter(
                id__in=selected_ids,
                language='e'
            )

            english_questions = []
            hindi_questions = []

            for q_en in selected_en_questions:

                # Save English
                english_questions.append(q_en)

                BatchGeneratedQuestion.objects.get_or_create(
                    batch=batch,
                    question=q_en
                )

                # Find Hindi pair
                q_hi = QuestionBank.objects.filter(
                    base_question_id=q_en.base_question_id,
                    language='h',
                    ai_version=q_en.ai_version
                ).first()

                if q_hi:
                    hindi_questions.append(q_hi)

                    BatchGeneratedQuestion.objects.get_or_create(
                        batch=batch,
                        question=q_hi
                    )

            # Generate files
            en_file = generate_word_response(batch, english_questions, lang='EN')
            hi_file = generate_word_response(batch, hindi_questions, lang='HI')

            zip_buffer = BytesIO()
            with zipfile.ZipFile(zip_buffer, "w") as zf:
                zf.writestr(en_file['filename'], en_file['content'].getvalue())
                zf.writestr(hi_file['filename'], hi_file['content'].getvalue())

            response = HttpResponse(zip_buffer.getvalue(), content_type="application/zip")
            response['Content-Disposition'] = f'attachment; filename="Test_Papers_{batch.name}.zip"'
            return response
        else:
            return HttpResponse("Please use manual selection for pair-based export.", status=400)
        

# -------------------------------
# ✅ FORMAT QUESTION TEXT (NO SOLUTION / CORRECT)
# -------------------------------
from docx.shared import Inches

def format_question_text(q, display_number, document=None):
    is_hindi = q.language == 'h'
    sub_type = q.question_sub_type or 'simple_type'

    text = f"{display_number}. "

    if sub_type == 'list_type_2' and document:
        # Add heading text
        part = q.question_part_first_hi if is_hindi else q.question_part_first
        para = document.add_paragraph()
        para.add_run(text + (part or '')).bold = False

        # Build table for List-I and List-II
        list1 = q.list_1_items_hi if is_hindi else q.list_1_items
        list2 = q.list_2_items_hi if is_hindi else q.list_2_items

        table = document.add_table(rows=max(len(list1), len(list2)) + 1, cols=2)
        table.autofit = True
        remove_table_borders(table)

        # Header row
        table.cell(0, 0).text = 'List-I'
        table.cell(0, 1).text = 'List-II'

        # Fill rows
        for i in range(max(len(list1), len(list2))):
            li = f"{chr(65 + i)}. {list1[i]}" if i < len(list1) else ''
            lii = f"{i + 1}. {list2[i]}" if i < len(list2) else ''
            table.cell(i + 1, 0).text = li
            table.cell(i + 1, 1).text = lii

        # Add options below
        options = [
            (q.answer_option_a_hi if is_hindi else q.answer_option_a),
            (q.answer_option_b_hi if is_hindi else q.answer_option_b),
            (q.answer_option_c_hi if is_hindi else q.answer_option_c),
            (q.answer_option_d_hi if is_hindi else q.answer_option_d)
        ]
        for idx, opt in enumerate(options):
            if opt:
                document.add_paragraph(f"({chr(97 + idx)}) {opt}")

        return ""  # Content already added via document

    else:
        # For all other types
        part = (
            q.question_part_first_hi if is_hindi else
            (q.question_part_first or q.question_part or q.script)
        )
        text += f"{part or ''}\n"

        if sub_type == 'r_and_a_type':
            assertion = q.assertion_hi if is_hindi else q.assertion
            reason = q.reason_hi if is_hindi else q.reason
            text += f"\nAssertion: {assertion or ''}\nReason: {reason or ''}\n"

        a = q.answer_option_a_hi if is_hindi else q.answer_option_a
        b = q.answer_option_b_hi if is_hindi else q.answer_option_b
        c = q.answer_option_c_hi if is_hindi else q.answer_option_c
        d = q.answer_option_d_hi if is_hindi else q.answer_option_d

        if a: text += f"\n(a) {a}"
        if b: text += f"\n(b) {b}"
        if c: text += f"\n(c) {c}"
        if d: text += f"\n(d) {d}"

        return text

# -------------------------------
# ✅ REMOVE TABLE BORDERS HELPER
# -------------------------------
def remove_table_borders(table):
    tbl = table._tbl
    tblPr = tbl.tblPr
    tblBorders = OxmlElement('w:tblBorders')
    for border_name in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'):
        border = OxmlElement(f'w:{border_name}')
        border.set(qn('w:val'), 'none')
        tblBorders.append(border)
    tblPr.append(tblBorders)

from io import BytesIO
import os
from docx import Document
from docx.shared import Pt
from datetime import datetime
from django.conf import settings
from docx.oxml import OxmlElement
from docx.oxml.ns import qn

# ✅ Utility to remove table borders
def remove_table_borders(table):
    tbl = table._tbl
    tblPr = tbl.tblPr
    tblBorders = OxmlElement('w:tblBorders')
    for border_name in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'):
        border = OxmlElement(f'w:{border_name}')
        border.set(qn('w:val'), 'none')
        tblBorders.append(border)
    tblPr.append(tblBorders)

# ✅ ✅ FINAL GENERATOR — calls your updated format_question_text
def generate_word_response(batch, questions, lang='EN'):

    template_path = os.path.join(
        settings.BASE_DIR,
        'static', 'assets', 'templates', 'lecture_notes_template.docx'
    )

    document = Document(template_path)

    # ✅ Proper bilingual heading
    if lang == 'HI':
        heading_text = f"हाजेला आईएएस - प्रश्न पत्र ({batch.name})"
    else:
        heading_text = f"Hajela IAS - Test Paper ({batch.name})"

    document.add_heading(heading_text, level=1)

    table = document.add_table(rows=0, cols=2)
    table.autofit = True
    remove_table_borders(table)

    display_number = 1

    for i in range(0, len(questions), 2):
        row = table.add_row().cells

        q1 = questions[i]
        build_question_in_cell(q1, display_number, row[0], lang)
        display_number += 1

        if i + 1 < len(questions):
            q2 = questions[i + 1]
            build_question_in_cell(q2, display_number, row[1], lang)
            display_number += 1

        for cell in row:
            for para in cell.paragraphs:
                for run in para.runs:
                    run.font.size = Pt(11)

    file_stream = BytesIO()
    document.save(file_stream)
    file_stream.seek(0)

    subject_code = "GS4"
    exam_type = "MPPSC"
    stage = "PRE"
    set_number = f"SET{datetime.now().strftime('%d%m%H%M%S')}"
    unique_filename = f"{subject_code}_{exam_type}_{stage}_{lang}_{set_number}.docx"

    return {
        "filename": unique_filename,
        "content": file_stream
    }

def build_question_in_cell(q, display_number, cell, lang):

    is_hindi = lang == 'HI'
    sub_type = q.question_sub_type or 'simple_type'

    para = cell.add_paragraph(f"{display_number}. ")

    # -------------------------
    # LIST TYPE 2
    # -------------------------
    if sub_type == 'list_type_2':

        question_text = q.question_part_first_hi if is_hindi else q.question_part_first
        para.add_run(question_text or "")

        list1 = q.list_1_items_hi if is_hindi else q.list_1_items
        list2 = q.list_2_items_hi if is_hindi else q.list_2_items

        nested_table = cell.add_table(
            rows=max(len(list1), len(list2)) + 1,
            cols=2
        )
        remove_table_borders(nested_table)

        hdr = nested_table.rows[0].cells

        if is_hindi:
            hdr[0].text = "सूची-I"
            hdr[1].text = "सूची-II"
        else:
            hdr[0].text = "List-I"
            hdr[1].text = "List-II"

        for idx in range(max(len(list1), len(list2))):
            row_cells = nested_table.rows[idx + 1].cells

            if idx < len(list1):
                row_cells[0].text = f"{chr(65+idx)}. {list1[idx]}"
            if idx < len(list2):
                row_cells[1].text = f"{idx+1}. {list2[idx]}"

        options = [
            q.answer_option_a_hi if is_hindi else q.answer_option_a,
            q.answer_option_b_hi if is_hindi else q.answer_option_b,
            q.answer_option_c_hi if is_hindi else q.answer_option_c,
            q.answer_option_d_hi if is_hindi else q.answer_option_d,
        ]

        for idx, option in enumerate(options):
            if option:
                cell.add_paragraph(f"({chr(97 + idx)}) {option}")

    # -------------------------
    # ASSERTION & REASON
    # -------------------------
    elif sub_type == 'r_and_a_type':

        question_text = q.question_part_first_hi if is_hindi else q.question_part_first
        para.add_run(question_text or "")

        assertion = q.assertion_hi if is_hindi else q.assertion
        reason = q.reason_hi if is_hindi else q.reason

        if is_hindi:
            cell.add_paragraph(f"कथन: {assertion}")
            cell.add_paragraph(f"कारण: {reason}")
        else:
            cell.add_paragraph(f"Assertion: {assertion}")
            cell.add_paragraph(f"Reason: {reason}")

        options = [
            q.answer_option_a_hi if is_hindi else q.answer_option_a,
            q.answer_option_b_hi if is_hindi else q.answer_option_b,
            q.answer_option_c_hi if is_hindi else q.answer_option_c,
            q.answer_option_d_hi if is_hindi else q.answer_option_d,
        ]

        for idx, option in enumerate(options):
            if option:
                cell.add_paragraph(f"({chr(97 + idx)}) {option}")

    # -------------------------
    # SIMPLE & ALL OTHER TYPES
    # -------------------------
    else:

        question_text = (
            q.question_part_hi if is_hindi
            else (q.question_part or q.script)
        )

        para.add_run(question_text or "")

        options = [
            q.answer_option_a_hi if is_hindi else q.answer_option_a,
            q.answer_option_b_hi if is_hindi else q.answer_option_b,
            q.answer_option_c_hi if is_hindi else q.answer_option_c,
            q.answer_option_d_hi if is_hindi else q.answer_option_d,
        ]

        for idx, option in enumerate(options):
            if option:
                cell.add_paragraph(f"({chr(97 + idx)}) {option}")



# Image Generation Chat View
from django.shortcuts import render, redirect
from .openai_image import generate_image  # This should return a list of GeneratedImage objects
from datetime import datetime

from datetime import datetime
from django.shortcuts import render, redirect
from .openai_image import generate_image
from datetime import datetime

def generate_image_view(request):
    session_id = request.session.get('active_chat_session_id')
    selected_session_id = request.GET.get('session_id')

    # Initialize session storage
    if 'chat_sessions' not in request.session:
        request.session['chat_sessions'] = {}
    if 'chat_history_sessions' not in request.session:
        request.session['chat_history_sessions'] = {}

    chat_sessions = request.session['chat_sessions']
    chat_history_sessions = request.session['chat_history_sessions']

    # Start a new session if not exists
    if not session_id:
        session_id = str(datetime.now().timestamp())
        request.session['active_chat_session_id'] = session_id
        chat_sessions[session_id] = []

    # Handle POST (generate new image and store to current session)
    if request.method == 'POST':
        user_prompt = request.POST.get('prompt')
        if user_prompt:
            current_chat = chat_sessions.get(session_id, [])
            last_prompt = current_chat[-1]['prompt'] if current_chat else ""
            final_prompt = f"{last_prompt}. {user_prompt}" if last_prompt else user_prompt

            image_objs = generate_image(final_prompt)

            for img in image_objs:
                current_chat.append({
                    'prompt': final_prompt,
                    'image_url': img.image.url,
                    'timestamp': str(datetime.now())
                })

            chat_sessions[session_id] = current_chat

            # Save session info if first time
            if session_id not in chat_history_sessions:
                chat_history_sessions[session_id] = {
                    'id': session_id,
                    'first_prompt': final_prompt,
                    'created_at': datetime.now().isoformat()
                }

            request.session.modified = True
            return redirect('generate_image')

    # ✅ Load history: use selected session_id if present
    chat_history = chat_sessions.get(selected_session_id, []) if selected_session_id else chat_sessions.get(session_id, [])

    return render(request, 'question_bank/generate_image.html', {
        'chat_history': chat_history,
        'session_list': list(chat_history_sessions.values())
    })




def clear_image_chat(request):
    if 'chat_history' in request.session:
        request.session['chat_history'] = []
    return redirect('generate_image')


def new_image_chat(request):
    request.session.pop('chat_history', None)
    request.session.pop('active_chat_session_id', None)
    return redirect('generate_image')



from django.shortcuts import render
from .models import Area

def hierarchy_view(request):
    areas = Area.objects.prefetch_related(
        'sections__parts__chapters__topics__sub_topics'
    ).all()
    return render(request, 'question_bank/hierarchy_page.html', {'areas': areas})



import os
import re
import tempfile
from django.shortcuts import render
from django.http import HttpResponse
from decouple import config
from openai import OpenAI
from docx import Document
from django.conf import settings

client = OpenAI(api_key=config("OPENAI_API_KEY"))

def slugify_filename(text):
    """
    Replace invalid filename characters with underscores.
    This makes your filename safe for Windows and cross-platform.
    """
    text = re.sub(r'[\\/*?:"<>|]', "", text)
    text = text.strip().replace(' ', '_')
    return text

def generate_notes(request):
    if request.method == "POST":
        topic = request.POST.get("topic")
        safe_topic = slugify_filename(topic)

        # ✅ Structured UPSC Current Affairs prompt
        prompt = f"""
You are an expert UPSC mentor. Give me comprehensive UPSC notes for the topic: "{topic}"

Your output must include:
1. Short introduction (background + context)
2. Key facts, data, agreements, or dates (bullet points)
3. Strategic significance for India (national security, economy, diplomacy, GS2 linkages)
4. Stakeholders involved (India + other countries/institutions)
5. Possible benefits and opportunities for India
6. Challenges, concerns or criticisms
7. Expert views, reports, or quotes to enrich analysis
8. Diagrams, maps, or flowcharts if relevant (describe)
9. Answer framework for UPSC Mains: Intro – Body – Conclusion
10. 3-5 potential UPSC Prelims MCQs with correct answers
11. 3-5 possible UPSC Mains questions (GS2/GS3/Essay)

Use clear bullet points, formal language, and keep it crisp and exam-oriented.
Provide headings in both Hindi and English where suitable.
"""

        response = client.chat.completions.create(
            model="gpt-4o",
            messages=[{"role": "user", "content": prompt}]
        )
        notes_text = response.choices[0].message.content.strip()

        # ✅ Load Word template
        template_path = os.path.join(
            settings.BASE_DIR,
            'static',
            'assets',
            'templates',
            'lecture_notes_template.docx'
        )
        if not os.path.exists(template_path):
            return HttpResponse(f"Template not found: {template_path}", status=500)

        doc = Document(template_path)
        doc.add_heading(topic, level=1)

        # ✅ Add structured notes content
        for line in notes_text.split('\n'):
            line = line.strip()
            if line and (
                (line[0].isdigit() and line[1] == '.') or
                line.endswith(":") or
                line.startswith(("✅", "🔸", "•", "-", "*"))
            ):
                doc.add_paragraph(line, style='Heading 2')
            elif line:
                doc.add_paragraph(line)

        # ✅ Use safe filename
        output_path = os.path.join(tempfile.gettempdir(), f"{safe_topic}_UPSC_Notes.docx")
        doc.save(output_path)
        with open(output_path, 'rb') as f:
            response = HttpResponse(
                f.read(),
                content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document'
            )
            response['Content-Disposition'] = f'attachment; filename="{safe_topic}_UPSC_Notes.docx"'
            return response

    return render(request, 'question_bank/generate_notes.html')



# Database Views to show all the data at one place 


def database(request):

    return render(request,'question_bank/database.html')



from django.contrib.auth.decorators import login_required
from django.shortcuts import render, get_object_or_404
from collections import defaultdict
from .models import QuestionBank, LectureNote, InputSuggestion, SubTopicName

@login_required
def content_by_subtopic(request):
    sub_topic_short_code = request.GET.get("sub_topic_short_Code", None)

    pyqs_grouped = []
    moqs_grouped = []
    osqs_grouped = []
    lecture_notes = []
    input_suggestions = []

    if sub_topic_short_code:
        subtopic = get_object_or_404(SubTopicName, sub_topic_short_Code=sub_topic_short_code)

        # Helper function to group English & Hindi
        def group_queryset(qs):
            grouped = defaultdict(dict)
            for q in qs:
                if q.language == "e":
                    grouped[q.base_question_id]["english"] = q
                elif q.language == "h":
                    grouped[q.base_question_id]["hindi"] = q
            return list(grouped.items())  # ✅ return as list of tuples

        # --- PYQs ---
        pyqs = QuestionBank.objects.filter(
            type_of_question="pyq", subtopic_name=subtopic
        ).order_by("-created_at")
        pyqs_grouped = group_queryset(pyqs)

        # --- MOQs ---
        moqs = QuestionBank.objects.filter(
            type_of_question="moq", subtopic_name=subtopic
        ).order_by("-created_at")
        moqs_grouped = group_queryset(moqs)

        # --- OSQs ---
        osqs = QuestionBank.objects.filter(
            type_of_question="osq", subtopic_name=subtopic
        ).order_by("-created_at")
        osqs_grouped = group_queryset(osqs)

        # --- Notes & Suggestions ---
        lecture_notes = LectureNote.objects.filter(subtopic=subtopic)
        input_suggestions = InputSuggestion.objects.filter(subtopic_name=subtopic)

    context = {
        "sub_topic_short_code": sub_topic_short_code,
        "pyqs_grouped": pyqs_grouped,
        "moqs_grouped": moqs_grouped,
        "osqs_grouped": osqs_grouped,
        "lecture_notes": lecture_notes,
        "input_suggestions": input_suggestions,
    }
    return render(request, "question_bank/content_by_subtopic.html", context)
