"""
Model Sets quiz routes with advanced features
"""
import json
import uuid
import logging
import mysql.connector
from datetime import datetime
from flask import Blueprint, request, jsonify
from utils import (require_api_key, encrypt_response, format_api_response, 
                   create_error_response, get_db_connection, fetch_as_dict, convert_analytics_numbers)

logger = logging.getLogger(__name__)
modelset_bp = Blueprint('modelset', __name__)


@modelset_bp.route('/api/model-sets', methods=['GET'])
@require_api_key
def get_model_sets():
    """Get available model sets for a user"""
        
    try:
        user_id = request.args.get('user_id')
        category = request.args.get('category', 'all')
        difficulty = request.args.get('difficulty', 'all')
        
        if not user_id:
            return create_error_response("User ID is required", 400)
        
        with get_db_connection() as conn:
            cursor = conn.cursor(dictionary=True)
            
            # Build filter conditions
            where_conditions = ["m.is_active = TRUE"]
            params = []
            
            if category != 'all':
                where_conditions.append("m.category = %s")
                params.append(category)
                
            if difficulty != 'all':
                where_conditions.append("m.difficulty_level = %s")
                params.append(difficulty)
            
            where_clause = " AND ".join(where_conditions)
            
            # Get model sets with user attempt counts (only for courses user is enrolled AND paid for)
            query = f"""
            SELECT 
                m.*,
                c.title as course_title,
                c.description as course_description,
                COUNT(ma.id) as user_attempts
            FROM modelset m
            INNER JOIN courses c ON m.course_id = c.id
            INNER JOIN enrollments e ON c.id = e.course_id AND e.user_id = %s AND e.payment_status IN ('free', 'paid')
            LEFT JOIN modelset_attempts ma ON m.id = ma.modelset_id AND ma.user_id = %s
            WHERE {where_clause}
            GROUP BY m.id, c.title, c.description
            ORDER BY m.created_at DESC
            """
            
            cursor.execute(query, [user_id, user_id] + params)
            model_sets = cursor.fetchall()
            
            # Get available categories and difficulties for filters
            cursor.execute("SELECT DISTINCT category FROM modelset WHERE is_active = TRUE")
            categories = [row['category'] for row in cursor.fetchall()]
            
            cursor.execute("SELECT DISTINCT difficulty_level FROM modelset WHERE is_active = TRUE")
            difficulties = [row['difficulty_level'] for row in cursor.fetchall()]
            
            # Get all courses that user has enrolled and paid for (for course filter dropdown)
            cursor.execute("""
                SELECT DISTINCT c.id, c.title, c.description, c.image_url, c.price
                FROM courses c
                INNER JOIN enrollments e ON c.id = e.course_id AND e.user_id = %s AND e.payment_status IN ('free', 'paid')
                WHERE c.status = 'active'
                ORDER BY c.title
            """, (user_id,))
            enrolled_courses = cursor.fetchall()
            
            response_data = {
                'model_sets': convert_analytics_numbers(model_sets),
                'categories': categories,
                'difficulties': difficulties,
                'enrolled_courses': convert_analytics_numbers(enrolled_courses),
                'total_count': len(model_sets)
            }
            
            return format_api_response(response_data, include_legacy_fields=response_data)
            
    except Exception as e:
        logger.error(f"Error getting model sets: {str(e)}")
        return create_error_response(f"Failed to get model sets: {str(e)}")


@modelset_bp.route('/api/model-sets/<int:modelset_id>/generate', methods=['POST'])
@require_api_key
@encrypt_response
def generate_model_set_quiz(modelset_id):
    """Generate a quiz from a model set"""
        
    try:
        data = request.get_json() or {}
        user_id = data.get('user_id')
        
        if not user_id:
            return create_error_response("User ID is required", 400)
        
        with get_db_connection() as conn:
            cursor = conn.cursor(dictionary=True)
            
            # Get model set details and verify user has access to the course
            cursor.execute("""
                SELECT m.* FROM modelset m
                INNER JOIN courses c ON m.course_id = c.id
                INNER JOIN enrollments e ON c.id = e.course_id AND e.user_id = %s AND e.payment_status IN ('free', 'paid')
                WHERE m.id = %s AND m.is_active = TRUE
            """, (user_id, modelset_id))
            
            model_set = cursor.fetchone()
            if not model_set:
                return create_error_response("Model set not found or access denied", 404)
            
            # Check if user has exceeded max attempts
            cursor.execute("""
                SELECT COUNT(*) as attempt_count 
                FROM modelset_attempts 
                WHERE modelset_id = %s AND user_id = %s AND is_completed = TRUE
            """, (modelset_id, user_id))
            
            attempt_result = cursor.fetchone()
            if attempt_result['attempt_count'] >= model_set['max_attempts']:
                return create_error_response(f"Maximum attempts ({model_set['max_attempts']}) exceeded", 403)
            
            # Get questions from the model set
            question_ids = json.loads(model_set['question_ids']) if isinstance(model_set['question_ids'], str) else model_set['question_ids']
            
            if not question_ids:
                return create_error_response("No questions found in model set", 404)
            
            placeholders = ','.join(['%s'] * len(question_ids))
            cursor.execute(f"""
                SELECT 
                    q.id as question_id,
                    q.question_text,
                    q.options,
                    q.correct_answer_index,
                    q.difficulty,
                    q.explanation,
                    q.marks,
                    t.title as topic_title,
                    t.id as topic_id,
                    t.parent_topic_id,
                    t.level,
                    t.full_path,
                    c.title as course_title,
                    c.id as course_id
                FROM questions q
                JOIN topics t ON q.topic_id = t.id
                JOIN courses c ON t.course_id = c.id
                WHERE q.id IN ({placeholders})
                ORDER BY {"RAND()" if model_set['shuffle_questions'] else "q.id"}
            """, question_ids)
            
            questions = cursor.fetchall()
            
            if not questions:
                return create_error_response("No questions found", 404)
            
            # Format questions for frontend
            formatted_questions = []
            for q in questions:
                try:
                    if isinstance(q['options'], str):
                        options = json.loads(q['options'])
                    else:
                        options = q['options']
                except:
                    options = ['Option 1', 'Option 2', 'Option 3', 'Option 4']
                
                formatted_options = []
                for i, option_text in enumerate(options):
                    # Handle both string and dictionary option formats
                    if isinstance(option_text, dict):
                        # If option is a dictionary, extract the text field
                        text = option_text.get('text', option_text.get('option_text', str(option_text)))
                    else:
                        # If option is a string, use it directly
                        text = str(option_text)
                    
                    formatted_options.append({
                        'option_id': str(i),
                        'option_text': text.strip() if isinstance(text, str) else str(text),
                        'is_correct': i == int(q['correct_answer_index'])
                    })
                
                formatted_questions.append({
                    'question_id': str(q['question_id']),
                    'question_text': q['question_text'],
                    'options': formatted_options,
                    'difficulty': q['difficulty'],
                    'explanation': q.get('explanation', ''),
                    'marks': q['marks'],
                    'topic_title': q['topic_title'],
                    'topic_id': q['topic_id'],
                    'parent_topic_id': q.get('parent_topic_id'),
                    'topic_level': q.get('level', 0),
                    'topic_full_path': q.get('full_path'),
                    'course_title': q['course_title'],
                    'course_id': q['course_id']
                })
            
            # Generate quiz data
            quiz_data = {
                'quiz_id': str(uuid.uuid4()),
                'title': model_set['title'],
                'description': model_set['description'],
                'questions': formatted_questions,
                'total_questions': len(formatted_questions),
                'total_marks': model_set['total_marks'],
                'time_limit': model_set['time_limit'],
                'difficulty_level': model_set['difficulty_level'],
                'category': model_set['category'],
                'instructions': model_set['instructions'],
                'passing_marks': model_set['passing_marks'],
                'negative_marking': model_set['negative_marking'],
                'negative_marks_per_wrong': float(model_set['negative_marks_per_wrong']),
                'shuffle_questions': model_set['shuffle_questions'],
                'show_result_immediately': model_set['show_result_immediately'],
                'allow_review': model_set['allow_review'],
                'created_at': datetime.now().isoformat()
            }
            
            return format_api_response(quiz_data, include_legacy_fields=quiz_data)
            
    except Exception as e:
        logger.error(f"Error generating model set quiz: {str(e)}")
        return create_error_response(f"Failed to generate quiz: {str(e)}")


@modelset_bp.route('/api/model-sets/submit', methods=['POST'])
@require_api_key
@encrypt_response
def submit_model_set_quiz():
    """Submit model set quiz results with advanced scoring"""
        
    try:
        data = request.get_json() or {}
        user_id = data.get('user_id')
        quiz_id = data.get('quiz_id')
        model_set_id = data.get('model_set_id')
        answers = data.get('answers', {})
        time_taken = data.get('time_taken', 0)
        
        if not all([user_id, quiz_id, model_set_id, answers]):
            return create_error_response("Missing required fields", 400)
        
        with get_db_connection() as conn:
            cursor = conn.cursor(dictionary=True)
            
            # Get model set details and verify user has access to the course
            cursor.execute("""
                SELECT m.* FROM modelset m
                INNER JOIN courses c ON m.course_id = c.id
                INNER JOIN enrollments e ON c.id = e.course_id AND e.user_id = %s AND e.payment_status IN ('free', 'paid')
                WHERE m.id = %s AND m.is_active = TRUE
            """, (user_id, model_set_id))
            
            model_set = cursor.fetchone()
            if not model_set:
                return create_error_response("Model set not found or access denied", 404)
            
            # Get questions with marks
            question_ids = json.loads(model_set['question_ids']) if isinstance(model_set['question_ids'], str) else model_set['question_ids']
            placeholders = ','.join(['%s'] * len(question_ids))
            
            cursor.execute(f"""
                SELECT id, correct_answer_index, marks, difficulty, topic_id
                FROM questions 
                WHERE id IN ({placeholders})
            """, question_ids)
            
            questions_data = {str(q['id']): q for q in cursor.fetchall()}
            
            # Extract unique topic IDs from questions (for analytics)
            topic_ids = list(set(q['topic_id'] for q in questions_data.values() if q.get('topic_id')))
            
            # Debug logging
            logger.info(f"Model set {model_set_id}: Retrieved {len(questions_data)} questions")
            logger.info(f"Model set {model_set_id}: Extracted {len(topic_ids)} unique topic IDs: {topic_ids}")
            
            # If no topic_ids found, try to get topics from the course
            if not topic_ids:
                logger.warning(f"Model set {model_set_id}: No topic IDs found in questions. Attempting to fetch from course topics.")
                try:
                    course_id = model_set.get('course_id')
                    if course_id:
                        cursor.execute("""
                            SELECT DISTINCT id FROM topics 
                            WHERE course_id = %s AND is_active = TRUE
                            LIMIT 10
                        """, (course_id,))
                        topic_ids = [row['id'] for row in cursor.fetchall()]
                        logger.info(f"Model set {model_set_id}: Fallback - Retrieved {len(topic_ids)} topics from course {course_id}")
                except Exception as topic_fallback_error:
                    logger.error(f"Model set {model_set_id}: Failed to get fallback topics: {topic_fallback_error}")
                    # Continue with empty topic_ids
                    topic_ids = []
            
            # Calculate scores with advanced features
            total_questions = len(question_ids)
            correct_answers = 0
            wrong_answers = 0
            unanswered = 0
            total_marks_obtained = 0.0
            question_results = {}
            
            for question_id in question_ids:
                question_id_str = str(question_id)
                user_answer = answers.get(question_id_str)
                
                if question_id_str in questions_data:
                    question = questions_data[question_id_str]
                    correct_answer = str(question['correct_answer_index'])
                    marks_possible = question['marks']
                    
                    if user_answer is None or user_answer == '':
                        # Unanswered
                        unanswered += 1
                        marks_awarded = 0.0
                        is_correct = False
                    elif user_answer == correct_answer:
                        # Correct answer
                        correct_answers += 1
                        marks_awarded = float(marks_possible)
                        is_correct = True
                    else:
                        # Wrong answer
                        wrong_answers += 1
                        is_correct = False
                        # Apply negative marking if enabled
                        if model_set['negative_marking']:
                            marks_awarded = -float(model_set['negative_marks_per_wrong'])
                        else:
                            marks_awarded = 0.0
                    
                    total_marks_obtained += marks_awarded
                    
                    question_results[question_id_str] = {
                        'is_correct': is_correct,
                        'marks_awarded': marks_awarded,
                        'marks_possible': marks_possible,
                        'user_answer': user_answer,
                        'correct_answer': correct_answer
                    }
            
            # Ensure total marks doesn't go below zero
            total_marks_obtained = max(0.0, total_marks_obtained)
            
            # Calculate percentage
            score_percentage = (total_marks_obtained / model_set['total_marks'] * 100) if model_set['total_marks'] > 0 else 0
            
            # Get next attempt number
            cursor.execute("""
                SELECT COALESCE(MAX(attempt_number), 0) + 1 as next_attempt
                FROM modelset_attempts 
                WHERE modelset_id = %s AND user_id = %s
            """, (model_set_id, user_id))
            
            attempt_result = cursor.fetchone()
            attempt_number = attempt_result['next_attempt']
            
            # Store attempt record
            session_id = f"modelset_{model_set_id}_{user_id}_{int(datetime.now().timestamp())}"
            
            cursor.execute("""
                INSERT INTO modelset_attempts (
                    user_id, modelset_id, session_id, score_percentage, 
                    total_marks_obtained, total_marks_possible, total_questions,
                    correct_answers, wrong_answers, unanswered, time_taken,
                    time_limit, attempt_number, started_at, completed_at,
                    is_completed, answers_data
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
            """, (
                user_id, model_set_id, session_id, score_percentage,
                total_marks_obtained, model_set['total_marks'], total_questions,
                correct_answers, wrong_answers, unanswered, time_taken,
                model_set['time_limit'] * 60, attempt_number,
                datetime.now(), datetime.now(), True, json.dumps(answers)
            ))
            
            attempt_id = cursor.lastrowid
            
            # ALSO store in quiz_sessions table for analytics integration
            # This makes model set quizzes appear in analytics alongside regular quizzes
            # Match quiz_routes.py schema exactly (lines 711-738)
            cursor.execute("""
                INSERT INTO quiz_sessions (
                    user_id, quiz_type, quiz_id, course_id, topic_ids, modelset_id,
                    total_questions, correct_answers, score_percentage,
                    time_taken, marks_obtained, total_marks_possible,
                    negative_marking, negative_marking_percentage,
                    is_ai_generated, ai_quiz_metadata,
                    completed_at, created_at
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())
            """, (
                user_id, 
                'practice',  # Model sets are practice quizzes
                quiz_id,
                model_set.get('course_id'),  # Get course_id from model set
                json.dumps(topic_ids),  # Store topic_ids as JSON (for topic-wise analytics)
                model_set_id,  # Store modelset_id for linking
                total_questions,
                correct_answers,
                score_percentage,
                time_taken,
                total_marks_obtained,
                model_set['total_marks'],
                model_set.get('negative_marking', False),  # Negative marking flag
                model_set.get('negative_marks_per_wrong', 0),  # Negative marking percentage
                False,  # Model sets are not AI generated
                json.dumps({
                    'model_set_id': model_set_id,
                    'model_set_title': model_set.get('title', ''),
                    'difficulty_level': model_set.get('difficulty_level', ''),
                    'category': model_set.get('category', '')
                }),  # Store model set metadata
                datetime.now()
            ))
            
            quiz_session_id = cursor.lastrowid
            logger.info(f"Model set quiz stored in quiz_sessions (id: {quiz_session_id}) for analytics")
            
            # Update user analytics summary for overall stats
            try:
                from routes.analytics_routes import update_user_analytics_summary
                quiz_data = {
                    'total_questions': total_questions,
                    'correct_answers': correct_answers,
                    'time_taken': time_taken,
                    'score_percentage': score_percentage
                }
                update_user_analytics_summary(cursor, user_id, quiz_data)
                logger.info(f"Updated analytics summary for user {user_id}")
            except Exception as analytics_error:
                logger.warning(f"Failed to update analytics summary: {analytics_error}")
                # Don't fail the whole request if analytics update fails
            
            # Store model set attempt record (for model-set specific features like attempts tracking)
            for question_id in question_ids:
                question_id_str = str(question_id)
                if question_id_str in questions_data and question_id_str in question_results:
                    result = question_results[question_id_str]
                    
                    cursor.execute("""
                        INSERT INTO modelset_question_responses (
                            attempt_id, question_id, selected_option, correct_option,
                            is_correct, marks_awarded, marks_possible, time_taken
                        ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
                    """, (
                        attempt_id, question_id, result['user_answer'], result['correct_answer'],
                        result['is_correct'], result['marks_awarded'], result['marks_possible'],
                        time_taken // total_questions  # Average time per question
                    ))
            
          
            conn.commit()
            
            # Prepare response
            response_data = {
                'session_id': session_id,
                'attempt_id': attempt_id,
                'score_percentage': round(score_percentage, 2),
                'total_marks_obtained': round(total_marks_obtained, 2),
                'total_marks_possible': model_set['total_marks'],
                'correct_answers': correct_answers,
                'wrong_answers': wrong_answers,
                'unanswered': unanswered,
                'total_questions': total_questions,
                'time_taken': time_taken,
                'attempt_number': attempt_number,
                'passing_marks': model_set['passing_marks'],
                'is_passed': total_marks_obtained >= model_set['passing_marks'],
                'question_results': question_results,
                'completed_at': datetime.now().isoformat()
            }
            
            return format_api_response(response_data, include_legacy_fields=response_data)
            
    except Exception as e:
        logger.error(f"Error submitting model set quiz: {str(e)}")
        return create_error_response(f"Failed to submit quiz: {str(e)}")


@modelset_bp.route('/api/model-sets/<int:modelset_id>/attempts', methods=['GET'])
@require_api_key
@encrypt_response
def get_user_attempts(modelset_id):
    """Get user's attempts for a specific model set"""
        
    try:
        user_id = request.args.get('user_id')
        
        if not user_id:
            return create_error_response("User ID is required", 400)
        
        with get_db_connection() as conn:
            cursor = conn.cursor(dictionary=True)
            
            # First verify user has access to this model set's course
            cursor.execute("""
                SELECT m.id FROM modelset m
                INNER JOIN courses c ON m.course_id = c.id
                INNER JOIN enrollments e ON c.id = e.course_id AND e.user_id = %s AND e.payment_status IN ('free', 'paid')
                WHERE m.id = %s AND m.is_active = TRUE
            """, (user_id, modelset_id))
            
            if not cursor.fetchone():
                return create_error_response("Model set not found or access denied", 404)
            
            # Get user attempts
            cursor.execute("""
                SELECT 
                    attempt_number, score_percentage, total_marks_obtained,
                    total_marks_possible, correct_answers, wrong_answers,
                    unanswered, time_taken, completed_at, is_completed
                FROM modelset_attempts 
                WHERE modelset_id = %s AND user_id = %s
                ORDER BY attempt_number DESC
            """, (modelset_id, user_id))
            
            attempts = cursor.fetchall()
            
            # Get model set info
            cursor.execute("""
                SELECT title, max_attempts, passing_marks, total_marks
                FROM modelset 
                WHERE id = %s
            """, (modelset_id,))
            
            model_set_info = cursor.fetchone()
            
            response_data = {
                'attempts': convert_analytics_numbers(attempts),
                'model_set_info': model_set_info,
                'total_attempts': len(attempts),
                'attempts_remaining': max(0, model_set_info['max_attempts'] - len(attempts)) if model_set_info else 0
            }
            
            return format_api_response(response_data, include_legacy_fields=response_data)
            
    except Exception as e:
        logger.error(f"Error getting user attempts: {str(e)}")
        return create_error_response(f"Failed to get attempts: {str(e)}")


@modelset_bp.route('/api/model-sets/<int:modelset_id>/leaderboard', methods=['GET'])
@require_api_key
@encrypt_response
def get_model_set_leaderboard(modelset_id):
    """Get leaderboard for a specific model set"""
        
    try:
        limit = min(int(request.args.get('limit', 20)), 100)
        user_id = request.args.get('user_id')  # Optional - for access verification
        
        with get_db_connection() as conn:
            cursor = conn.cursor(dictionary=True)
            
            # If user_id is provided, verify they have access to this model set's course
            if user_id:
                cursor.execute("""
                    SELECT m.id FROM modelset m
                    INNER JOIN courses c ON m.course_id = c.id
                    INNER JOIN enrollments e ON c.id = e.course_id AND e.user_id = %s AND e.payment_status IN ('free', 'paid')
                    WHERE m.id = %s AND m.is_active = TRUE
                """, (user_id, modelset_id))
                
                if not cursor.fetchone():
                    return create_error_response("Model set not found or access denied", 404)
            
            # Get top performers for this model set
            cursor.execute("""
                SELECT 
                    u.id as user_id,
                    u.fullname as name,
                    u.profile_img_url,
                    MAX(ma.score_percentage) as best_score,
                    MAX(ma.total_marks_obtained) as best_marks,
                    MIN(ma.time_taken) as best_time,
                    COUNT(ma.id) as total_attempts,
                    MAX(ma.completed_at) as last_attempt
                FROM modelset_attempts ma
                JOIN user u ON ma.user_id = u.id
                WHERE ma.modelset_id = %s AND ma.is_completed = TRUE
                GROUP BY u.id, u.fullname, u.profile_img_url
                ORDER BY best_score DESC, best_marks DESC, best_time ASC
                LIMIT %s
            """, (modelset_id, limit))
            
            leaderboard_data = cursor.fetchall()
            
            # Add rank and badge
            for i, user in enumerate(leaderboard_data):
                user['rank'] = i + 1
                if user['rank'] == 1:
                    user['badge'] = '🥇'
                elif user['rank'] == 2:
                    user['badge'] = '🥈'
                elif user['rank'] == 3:
                    user['badge'] = '🥉'
                else:
                    user['badge'] = f"#{user['rank']}"
            
            # Get model set info
            cursor.execute("""
                SELECT title, total_marks, passing_marks, difficulty_level
                FROM modelset 
                WHERE id = %s
            """, (modelset_id,))
            
            model_set_info = cursor.fetchone()
            
            response_data = {
                'leaderboard': convert_analytics_numbers(leaderboard_data),
                'model_set_info': model_set_info,
                'showing_top': len(leaderboard_data),
                'generated_at': datetime.now().isoformat()
            }
            
            return format_api_response(response_data, include_legacy_fields=response_data)
            
    except Exception as e:
        logger.error(f"Error getting model set leaderboard: {str(e)}")
        return create_error_response(f"Failed to get leaderboard: {str(e)}")


@modelset_bp.route('/health/modelset', methods=['GET'])
def modelset_health_check():
    """Health check for model set system"""
    try:
        with get_db_connection() as conn:
            cursor = conn.cursor()
            
            # Check if tables exist and have data
            cursor.execute("SELECT COUNT(*) FROM modelset WHERE is_active = TRUE")
            active_count = cursor.fetchone()[0]
            
            cursor.execute("SELECT COUNT(*) FROM modelset_attempts WHERE created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)")
            recent_attempts = cursor.fetchone()[0]
            
            health_data = {
                'status': 'healthy',
                'active_model_sets': active_count,
                'recent_attempts_24h': recent_attempts,
                'timestamp': datetime.now().isoformat()
            }
            
            return format_api_response(health_data, include_legacy_fields=health_data)
            
    except Exception as e:
        error_data = {
            'status': 'error',
            'message': f'Health check failed: {str(e)}',
            'timestamp': datetime.now().isoformat()
        }
        return create_error_response(f'Health check failed: {str(e)}', 500)