from flask import session, request, jsonify
from src import db
from src.models import (
        StudentAssesmentResultTable,
        StudentTable,
        SubConceptTable,
        SchoolTable,
        TeacherAssessmentTable,
        QuestionTable, 
        ConceptTable,
        RankingTable
    )
from datetime import datetime, timezone
from src.utils.response import error_response
from sqlalchemy import Select, func
from src.utils.random import (
    shuffle_question_options,
    shuffle_questions_options_batch
)
from src.utils.rankings import update_student_rankings
from openai import OpenAI
from env import OPEN_AI_API_KEY
from src.utils.prompt import SYSTEM_PROMPT

client = OpenAI(api_key=OPEN_AI_API_KEY)
difficulty = ["easy", "medium", "hard"]

def submit_func():
    student = session.get("student")
    if not student:
        return error_response("No active student found", 400)

    student_id = student.get("id")
    section = student.get("section")
    grade = student.get("grade")
    school_id = student.get("school_id")
    body = request.get_json()

    submit_type = body.get("type")  # 'assessment' or 'practice'
    answers = body.get("answers")
    assesment_id = body.get("assesment_id")
    concepts_with_subconcepts = body.get("concepts_with_subconcepts", [])

    if not answers:
        return error_response("Missing answers data", 400)

    concept_stats = {}
    subconcept_stats = {}
    correct_count = 0

    for ans in answers:
        concept = ans.get("concept")
        subconcept = ans.get("subconcept", "")
        user_answer = ans.get("userAnswer")
        correct_answer = ans.get("answer")
        
        # Compare answers (both should be text values now)
        is_correct = user_answer == correct_answer

        if is_correct:
            correct_count += 1

        # Concept level tracking
        if concept not in concept_stats:
            concept_stats[concept] = {"total": 0, "correct": 0}

        concept_stats[concept]["total"] += 1
        if is_correct:
            concept_stats[concept]["correct"] += 1

        # Subconcept level tracking
        if subconcept:
            subconcept_key = f"{concept}::{subconcept}"
            if subconcept_key not in subconcept_stats:
                subconcept_stats[subconcept_key] = {
                    "total": 0, 
                    "correct": 0, 
                    "concept": concept, 
                    "subconcept": subconcept
                }
            
            subconcept_stats[subconcept_key]["total"] += 1
            if is_correct:
                subconcept_stats[subconcept_key]["correct"] += 1

    concept_detail = [
        {"concept": k, "total": v["total"], "correct": v["correct"]}
        for k, v in concept_stats.items()
    ]

    subconcept_detail = [
        {
            "concept": v["concept"],
            "subconcept": v["subconcept"],
            "total": v["total"],
            "correct": v["correct"]
        }
        for k, v in subconcept_stats.items()
    ]

    coins_earned = correct_count * 20
    gems_earned = correct_count * 1

    stmt = Select(StudentTable).where(StudentTable.id == student_id)
    student_user = db.session.execute(stmt).scalar_one_or_none()

    if not student_user:
        return jsonify({
            "success": False,
            "message": "Student not found"
        }), 404

    # Check if assessment already submitted
    if submit_type == "assessment" and assesment_id:
        stmt = Select(StudentAssesmentResultTable).where(
            StudentAssesmentResultTable.student_id == student_id,
            StudentAssesmentResultTable.assesment_id == assesment_id
        )
        isSubmitted = db.session.execute(stmt).scalar_one_or_none()
        if isSubmitted:
            return jsonify({
                "success": True,
                "message": "Already submitted assessment"
            }), 409

    new_result = StudentAssesmentResultTable(
        student_id=student_id,
        school_id=school_id,
        assesment_id=assesment_id,
        concept_detail=concept_detail,
        subconcept_detail=subconcept_detail,
        concepts_with_subconcepts=concepts_with_subconcepts,
        grade=grade,
        section=section
    )

    db.session.add(new_result)

    student_user.coins += coins_earned
    student_user.gems += gems_earned

    db.session.commit()

    return jsonify({
        "success": True,
        "message": f"{submit_type.capitalize()} submitted successfully",
        "coins_earned": coins_earned,
        "gems_earned": gems_earned,
        "correct_count": correct_count,
        "total_questions": len(answers)
    }), 200


def practice_set_func():
    student = session.get("student")
    if not student:
        return jsonify({
            "success": False,
            "message": "Unauthorized user"
        }), 401

    student_id = student.get("id")
    stmt = Select(StudentAssesmentResultTable).where(
        StudentAssesmentResultTable.student_id == student_id
    )
    all_results = db.session.execute(stmt).scalars().all()

    if not all_results:
        return jsonify({
            "success": False,
            "message": "No assessment history found. Please complete an assessment first."
        }), 404

    concept_performance = {}  # {concept_name: {"total": x, "correct": y}}
    
    for result in all_results:
        for c in result.concept_detail:
            name = c.get("concept") or c.get("conceptname")
            total = c.get("total", 0)
            correct = c.get("correct", 0)

            if name not in concept_performance:
                concept_performance[name] = {"total": 0, "correct": 0}

            concept_performance[name]["total"] += total
            concept_performance[name]["correct"] += correct

    subconcept_performance = {}  # {concept_name: {subconcept_name: {"total": x, "correct": y, "subconcept_id": id}}}
    
    for result in all_results:
        if result.subconcept_detail:
            for sc in result.subconcept_detail:
                concept = sc.get("concept")
                subconcept = sc.get("subconcept")
                total = sc.get("total", 0)
                correct = sc.get("correct", 0)

                if concept not in subconcept_performance:
                    subconcept_performance[concept] = {}
                
                if subconcept not in subconcept_performance[concept]:
                    # SubConcept ko database se fetch karo
                    subconcept_obj = db.session.query(SubConceptTable).filter(
                        SubConceptTable.name == subconcept
                    ).first()
                    
                    subconcept_id = subconcept_obj.id if subconcept_obj else None
                    
                    subconcept_performance[concept][subconcept] = {
                        "total": 0, 
                        "correct": 0,
                        "subconcept_id": subconcept_id
                    }
                
                subconcept_performance[concept][subconcept]["total"] += total
                subconcept_performance[concept][subconcept]["correct"] += correct

    concept_accuracy = []
    for concept, stats in concept_performance.items():
        accuracy = (stats["correct"] / stats["total"]) * 100 if stats["total"] > 0 else 0
        concept_accuracy.append({
            "concept": concept,
            "accuracy": accuracy,
            "total": stats["total"],
            "correct": stats["correct"]
        })

    concept_accuracy.sort(key=lambda x: x["accuracy"])

    weakest_concepts = concept_accuracy[:10]

    if not weakest_concepts:
        return jsonify({
            "success": False,
            "message": "Not enough data to generate practice sets"
        }), 404

    practice_sets = []
    
    for idx, weak_concept in enumerate(weakest_concepts):
        concept_name = weak_concept["concept"]
        
        subconcept_accuracy = []
        if concept_name in subconcept_performance:
            for subconcept, stats in subconcept_performance[concept_name].items():
                accuracy = (stats["correct"] / stats["total"]) * 100 if stats["total"] > 0 else 0
                subconcept_accuracy.append({
                    "subconcept": subconcept,
                    "accuracy": accuracy,
                    "total": stats["total"],
                    "correct": stats["correct"],
                    "subconcept_id": stats.get("subconcept_id")  # ID add kiya
                })
            
            subconcept_accuracy.sort(key=lambda x: x["accuracy"])
        
        weakest_subconcepts = subconcept_accuracy
        
        practice_sets.append({
            "set_number": idx + 1,
            "main_concept": concept_name,
            "main_concept_accuracy": round(weak_concept["accuracy"], 2),
            "main_concept_total": weak_concept["total"],
            "main_concept_correct": weak_concept["correct"],
            "weakest_subconcepts": [
                {
                    "name": sub["subconcept"],
                    "accuracy": round(sub["accuracy"], 2),
                    "total": sub["total"],
                    "correct": sub["correct"],
                    "subconcept_id": sub.get("subconcept_id") 
                }
                for sub in weakest_subconcepts
            ]
        })

    return jsonify({
        "success": True,
        "message": "Practice sets generated successfully",
        "total_sets": len(practice_sets),
        "practice_sets": practice_sets
    }), 200
 

def login_func():
    body = request.get_json()
    username = body.get("username")
    password = body.get("password")

    if not username or not password:
        return error_response("Please fill the required field", 404)
    
    stmt = Select(StudentTable).where(StudentTable.username == username)
    user = db.session.execute(stmt).scalar_one_or_none()

    if not user:
        return error_response("Invalid username or password", 400)
    
    if user.isLoggedIn:
        if not user.check_password(password):
            return error_response("Invalid username or password", 400)
    else:
        user.set_password(password)
        user.isLoggedIn = True
    
    stmt2 = Select(SchoolTable).where(SchoolTable.id == user.school_id)
    school = db.session.execute(stmt2).scalar_one_or_none()

    if not school:
        return error_response("Something went wrong", 404)
    
    now = datetime.now(timezone.utc)
    last_login_date = user.last_login.date()

    if last_login_date:
        delta_days = (now.date() - last_login_date).days
        if delta_days == 1:
            user.streak += 1
        else:
            user.streak = 1
    
    user.last_login = now
    
    # Calculate and update rankings at login
    rankings = update_student_rankings(
        student_id=user.id,
        grade=user.grade,
        section=user.section,
        school_id=user.school_id
    )
    
    db.session.commit()

    session["student"] = {
        "id": user.id,
        "username": user.username,
        "school_id": school.id,
        "grade": user.grade,
        "section": user.section,
        "stream": school.stream,
    }

    return jsonify({
        "success": True,
        "role": "student",
        "message": "student login successfully",
        "users": session["student"],
        "avatar": user.avatar,
        "coins": user.coins,
        "gems": user.gems,
        "streak": user.streak,
        "rankings": {
            "class": rankings['class_rankings'],
            "school": rankings['school_rankings']
        }
    }), 200


def get_ass_func():
    student = session.get("student")
    if not student:
        return error_response("No active student found", 404)
    
    grade = student.get("grade")
    section = student.get("section")
    body = request.get_json()
    assesment_id = body.get("assesment_id")

    if not grade or not section or not assesment_id:
        return jsonify({
            "success": False,
            "message": "Something went wrong"
        }), 400

    assesment_stmt = (
        Select(TeacherAssessmentTable)
        .where(TeacherAssessmentTable.id == assesment_id)
    )

    selected_assessment = db.session.execute(assesment_stmt).scalar_one_or_none()
    
    # Build concepts_with_subconcepts from questions
    concepts_with_subconcepts = []
    seen_pairs = set()
    
    for question in selected_assessment.questions:
        concept = question.get("concept")
        subconcept = question.get("subconcept", "")
        pair = f"{concept}::{subconcept}"
        
        if pair not in seen_pairs:
            seen_pairs.add(pair)
            concepts_with_subconcepts.append({
                "concept": concept,
                "subconcept": subconcept
            })

    assesment_data = {
        "assesment_id": selected_assessment.id,
        "school_id": selected_assessment.school_id,
        "created_by": selected_assessment.created_by,
        "grade": selected_assessment.grade,
        "section": selected_assessment.section,
        "concepts": selected_assessment.concepts,
        "concepts_with_subconcepts": concepts_with_subconcepts,
        "assesment": selected_assessment.questions,  # Questions already have correct format
        "created_at": selected_assessment.created_at.strftime("%Y-%m-%d %H:%M:%S"),
    }
    
    return jsonify({
        "success": True,
        "message": "Got Assessment successfully",
        **assesment_data
    }), 200


def ai_func():
    body = request.get_json()
    question = body.get("question")
    user_prompt = body.get("user_prompt", "user_prompt is empty")

    if not question:
        return error_response("Question is required", 400)

    user_content = f"Question: {question}\nUser_Prompt: {user_prompt}"

    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": user_content}
            ]
        )

    ai_text = response.choices[0].message.content

    return jsonify({
            "success": True,
            "ai_response": ai_text
        })


def difficulty_func():
    student = session.get("student")
    body = request.get_json()
    subConcept_id = body.get("subConcept_id")
    level = body.get("level")
    pracAns = body.get("pracAns")
    stu_id = student.get("id")
    
    if not student or not stu_id:
        return error_response("No active student found", 404)
    
    if not subConcept_id or not level:
        return error_response("Missing the required fields", 400)
        
    per_ques_coin = 10
    if level == "medium":
        per_ques_coin = 40
    elif level == "hard":
        per_ques_coin = 80
        
    if pracAns == 0:
        pracAns = 1
        
    stu_stmt = Select(StudentTable).where(StudentTable.id == stu_id)
    stu = db.session.execute(stu_stmt).scalar_one_or_none()
    
    if not stu:
        return error_response("No Student record found", 400)
        
    stu.coins += per_ques_coin * pracAns
    db.session.commit()
    
    # Fetch questions (DIRECT FROM SQL - NO VALIDATION)
    stmt = Select(QuestionTable).where(
        QuestionTable.subconcept_id == subConcept_id, 
        QuestionTable.difficulty == level
    ).order_by(func.random()).limit(5)
    
    all_ques = db.session.execute(stmt).scalars().all()
    
    if not all_ques:
        return jsonify({
            "success": False,
            "message": "No such question available for your grade"
        }), 404
    
    # Shuffle options for all questions with smart positioning
    question_list = shuffle_questions_options_batch(all_ques)
    
    stmt_sub_id = Select(SubConceptTable).where(SubConceptTable.id == subConcept_id)
    sub_con = db.session.execute(stmt_sub_id).scalar_one_or_none()
    
    if not sub_con:
        return jsonify({
            "success": False,
            "message": "Network error"
        }), 500
    
    stmt_concept = Select(ConceptTable.name).where(ConceptTable.id == sub_con.concept_id)
    concept = db.session.execute(stmt_concept).scalar_one_or_none()
    
    if not concept:
        return jsonify({
            "success": False,
            "message": "Concept Not found"
        }), 404
    
    return jsonify({
        "success": True,
        "message": "fetched question successfully",
        "data": question_list,
        "sub_concept": sub_con.name,
        "concept": concept
    })


def submit_ans_func():
    student = session.get("student")
    body = request.get_json()
    ques_id = body.get("ques_id")
    is_correct = body.get("correct")
    time_taken = body.get("time")
    
    if not student:
        return jsonify({
            "success": False,
            "message": "No active student found"
        }), 404
    
    stu_id = student.get("id")
    
    if not ques_id or is_correct is None or time_taken is None:
        return jsonify({
            "success": False,
            "message": "Missing required fields"
        }), 400
    
    # Save to ranking table
    try:
        new_ranking = RankingTable(
            student_id=stu_id,
            question_id=ques_id,
            is_correct=is_correct,
            time_taken_sec=float(time_taken),
            attempted_at=datetime.now(timezone.utc)
        )
        db.session.add(new_ranking)
        db.session.commit()
        
        return jsonify({
            "success": True,
            "message": "Answer submitted successfully"
        })
    except Exception as e:
        return jsonify({
            "success": False,
            "message": "Failed to save answer"
        }), 500


def adaptive_func():
    student = session.get("student")
    body = request.get_json()
    sub_Concept = body.get("subConcept")
    subconcept_id = body.get("subconcept_id")
    level = body.get("level")
    prev_quest_id = body.get("ques_id")
    isCorrectAttempt = body.get("correct")
    time_taken_sec = body.get("time")
    
    if not student:
        return jsonify({
            "success": False,
            "message": "No active student found"
        }), 404
    
    stu_id = student.get("id")
    
    # Update ranking table if previous question was answered (not skipped)
    if prev_quest_id and isCorrectAttempt is not None and time_taken_sec is not None:
        try:
            new_ranking = RankingTable(
                student_id=stu_id,
                question_id=prev_quest_id,
                is_correct=isCorrectAttempt,
                time_taken_sec=float(time_taken_sec),
                attempted_at=datetime.now(timezone.utc)
            )
            db.session.add(new_ranking)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
    
    # Determine next difficulty level
    if level not in difficulty:
        level = "easy"
    
    idx = difficulty.index(level)
    
    if not level:
        level = "easy"
    else:
        if isCorrectAttempt:
            if idx < len(difficulty) - 1:
                level = difficulty[idx + 1]
        else:
            if idx > 0:
                level = difficulty[idx - 1]
    
    if not sub_Concept or not subconcept_id:
        return jsonify({
            "success": False,
            "message": "Missing the required field"
        }), 404       
    
    # Fetch next question (DIRECT FROM SQL - NO VALIDATION)
    stmt_ques = Select(QuestionTable).where(
        QuestionTable.difficulty == level, 
        QuestionTable.subconcept_id == subconcept_id
    ).order_by(func.random()).limit(1)

    data = db.session.execute(stmt_ques).scalars().first()
    
    if not data:
        return jsonify({
            "success": False,
            "message": "No question found",
        }), 500
    
    # Shuffle options to randomize correct answer position
    shuffled_options, shuffled_correct_key = shuffle_question_options(
        data.question,
        data.options,
        data.correct_answer
    )
    
    # Get subconcept details
    stmt_sub = Select(SubConceptTable).where(SubConceptTable.id == subconcept_id)
    sub_con = db.session.execute(stmt_sub).scalar_one_or_none()
    
    if not sub_con:
        return jsonify({
            "success": False,
            "message": "SubConcept not found"
        }), 404
    
    # Get concept name
    stmt_concept = Select(ConceptTable.name).where(ConceptTable.id == sub_con.concept_id)
    concept = db.session.execute(stmt_concept).scalar_one_or_none()
    
    if not concept:
        return jsonify({
            "success": False,
            "message": "Concept not found"
        }), 404
    
    # Return question with shuffled options
    return jsonify({
        "success": True,
        "message": "Fetched Question successfully",
        "question": data.question,
        "options": [{"key": k, "value": v} for k, v in shuffled_options.items()], 
        "level": data.difficulty,
        "correct_answer": shuffled_correct_key,
        "ques_id": data.id,
        "sub_concept": sub_con.name,
        "concept": concept
    })


def teacher_assignment_func():
    """
    Get top 10 teacher assignments with attempt status and marks
    Sorted: Not attempted first, then attempted ones
    """
    student = session.get("student")
    if not student:
        return error_response("No active student found", 401)
    
    student_id = student.get("id")
    school_id = student.get("school_id")
    grade = student.get("grade")
    section = student.get("section")

    if not grade or not section:
        return error_response("Invalid student data", 400)

    # Get top 10 recent teacher assessments for this student's class
    stmt_assessments = (
        Select(TeacherAssessmentTable)
        .where(
            TeacherAssessmentTable.school_id == school_id,
            TeacherAssessmentTable.grade == str(grade),
            TeacherAssessmentTable.section == section,
            TeacherAssessmentTable.is_verified == True  
        )
        .order_by(TeacherAssessmentTable.created_at.desc())
        .limit(10)
    )
    
    assessments = db.session.execute(stmt_assessments).scalars().all()

    if not assessments:
        return jsonify({
            "success": False,
            "message": "No assignments found for your class"
        }), 404

    # Get all student's attempted assessments
    stmt_results = Select(StudentAssesmentResultTable).where(
        StudentAssesmentResultTable.student_id == student_id,
        StudentAssesmentResultTable.school_id == school_id
    )
    attempted_results = {
        result.assesment_id: result 
        for result in db.session.execute(stmt_results).scalars().all()
    }

    # Build response with attempt status and marks
    not_attempted = []
    attempted = []
    
    for assessment in assessments:
        result = attempted_results.get(assessment.id)
        
        if result:
            # Calculate total and correct answers
            total_questions = sum(concept.get("total", 0) for concept in result.concept_detail)
            correct_answers = sum(concept.get("correct", 0) for concept in result.concept_detail)
            
            assignment_info = {
                "assignment_id": assessment.id,
                "concepts": assessment.concepts,
                "total_questions": len(assessment.questions),
                "created_at": assessment.created_at.strftime("%Y-%m-%d %H:%M:%S"),
                "is_attempted": True,
                "marks": {
                    "correct": correct_answers,
                    "total": total_questions,
                    "percentage": round((correct_answers / total_questions * 100), 2) if total_questions > 0 else 0
                },
                "submitted_at": result.submitted_at.strftime("%Y-%m-%d %H:%M:%S")
            }
            attempted.append(assignment_info)
        else:
            # Not attempted
            assignment_info = {
                "assignment_id": assessment.id,
                "concepts": assessment.concepts,
                "total_questions": len(assessment.questions),
                "created_at": assessment.created_at.strftime("%Y-%m-%d %H:%M:%S"),
                "is_attempted": False,
                "marks": None,
                "action": "attempt_now"  # Frontend will show button
            }
            not_attempted.append(assignment_info)
    
    # Combine: not attempted first, then attempted
    assignments_data = not_attempted + attempted

    return jsonify({
        "success": True,
        "message": "Teacher assignments fetched successfully",
        "total_assignments": len(assignments_data),
        "assignments": assignments_data
    }), 200


