from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Form, HTTPException, Depends
from starlette.requests import Request
import json
import uuid
import logging
import os
import sys

# Ensure path is correct for imports
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from services import WebSocketManager, redis_client, get_room_key, get_room_channel
from utils import DateTimeEncoder

router = APIRouter(tags=["Live Quiz"])
logger = logging.getLogger("uvicorn.error")

@router.post("/quiz/room/create")
async def create_quiz_room(
    request: Request,
    curriculum: str = Form(...),
    grade: str = Form(...),
    subject: str = Form(...),
    unit: str = Form(...),
    concept: str = Form(...),
    is_arabic: bool = Form(...),
    count: int = Form(5),
    host_id: str = Form(...)
):
    if not redis_client:
        raise HTTPException(status_code=503, detail="Service unavailable: Redis connection is not configured.")
        
    container = request.app.state.container
    try:
        quiz_questions = container.mcq_service.get_dynamic_quiz(
            curriculum=curriculum, grade=grade, subject=subject,
            unit=unit, concept=concept, is_arabic=is_arabic, count=count
        )
        if not quiz_questions:
            raise HTTPException(status_code=404, detail="Could not generate questions for this topic.")

        room_id = str(uuid.uuid4())[:6].upper()
        room_key = get_room_key(room_id)
        
        logger.info(f"Creating room with ID: {room_id}")
        
        room_state = {
            "status": "lobby",
            "host_id": host_id,
            "quiz_questions": json.dumps(quiz_questions, cls=DateTimeEncoder), 
            "participants": json.dumps({}),
            "results": json.dumps([])
        }
        
        redis_client.hset(room_key, mapping=room_state)
        redis_client.expire(room_key, 7200)
        
        return {"status": "success", "room_id": room_id}
    except Exception as e:
        logger.error(f"Error creating quiz room: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))
    
@router.get("/quiz/room/{room_id}")
async def get_room_status(room_id: str):
    room_key = get_room_key(room_id)
    
    if not redis_client:
        raise HTTPException(status_code=503, detail="Redis connection is not configured.")
    
    if not redis_client.exists(room_key):
        raise HTTPException(status_code=404, detail="Room not found.")
    
    room_status = redis_client.hget(room_key, "status")
    return {"status": "exists", "room_status": room_status}


@router.websocket("/ws/quiz/room/{room_id}/{student_id}")
async def websocket_endpoint(websocket: WebSocket, room_id: str, student_id: str):
    # Retrieve manager from app state
    manager: WebSocketManager = websocket.app.state.websocket_manager
    room_key = get_room_key(room_id)
    room_channel = get_room_channel(room_id)

    logger.info(f"WebSocket connection attempt - Room: {room_id}, Student: {student_id}")

    # 1. Accept Connection
    await manager.connect(websocket, room_id)
    
    # 2. Validate Dependencies
    if not redis_client:
        logger.error("Redis client not available during WebSocket connection")
        await websocket.close(code=1003, reason="Redis not available")
        manager.disconnect(websocket, room_id)
        return
    
    if not redis_client.exists(room_key):
        logger.warning(f"Room {room_id} not found during WebSocket connection")
        await websocket.close(code=1008, reason="Room not found")
        manager.disconnect(websocket, room_id)
        return
    
    container = websocket.app.state.container
    pipe = redis_client.pipeline()
    
    try:
        # 3. Update Participants in DB
        logger.info(f"Fetching student info for {student_id}")
        student_info = container.mcq_service.db_service.get_student_info(student_id)
        student_name = student_info.student_name if student_info else "Unknown Student"
        
        room_data = redis_client.hgetall(room_key)
        participants = json.loads(room_data.get("participants", "{}"))
        participants[student_id] = {"name": student_name, "status": "connected"}
        
        pipe.hset(room_key, "participants", json.dumps(participants))
        pipe.execute()
        
        # 4. Broadcast Update
        logger.info(f"Student {student_id} joined room {room_id}. Publishing update to {room_channel}")
        
        redis_client.publish(room_channel, json.dumps({
            "type": "participant_update", 
            "participants": participants,
            "host_id": room_data.get("host_id")
        }))
        
        # 5. Message Loop
        while True:
            data = await websocket.receive_json()
            message_type = data.get("type")
            logger.info(f"Received {message_type} from {student_id} in room {room_id}")
            
            current_room_data = redis_client.hgetall(room_key)
            host_id = current_room_data.get("host_id")

            if message_type == "start_quiz" and student_id == host_id:
                pipe.hset(room_key, "status", "in_progress")
                pipe.execute()
                
                redis_client.publish(room_channel, json.dumps({
                    "type": "quiz_started",
                    "questions": json.loads(current_room_data.get("quiz_questions", "[]"))
                }))

            elif message_type == "submit_answers":
                user_answers = data.get("answers", {})
                time_taken = data.get("time_seconds", 0)
                
                questions = json.loads(current_room_data.get("quiz_questions", "[]"))
                results = json.loads(current_room_data.get("results", "[]"))
                participants = json.loads(current_room_data.get("participants", "{}"))

                score = 0
                correct_answers = {q['question_text']: q['correct_answer'] for q in questions}
                for q_text, u_answer in user_answers.items():
                    if correct_answers.get(q_text) == u_answer:
                        score += 1
                
                results.append({"student_id": student_id, "name": student_name, "score": score, "time_seconds": time_taken})
                results.sort(key=lambda x: (-x['score'], x['time_seconds']))
                participants[student_id]["status"] = "finished"

                all_finished = all(p["status"] == "finished" for p in participants.values())
                if all_finished:
                    pipe.hset(room_key, "status", "finished")

                pipe.hset(room_key, "results", json.dumps(results))
                pipe.hset(room_key, "participants", json.dumps(participants))
                pipe.execute()

                redis_client.publish(room_channel, json.dumps({
                    "type": "results_update", "results": results, "is_final": all_finished
                }))

    except WebSocketDisconnect:
        logger.info(f"Student {student_id} disconnected from room {room_id}")
        current_participants = json.loads(redis_client.hget(room_key, "participants") or "{}")
        if student_id in current_participants:
            del current_participants[student_id]
            redis_client.hset(room_key, "participants", json.dumps(current_participants))
            
            room_data = redis_client.hgetall(room_key)
            redis_client.publish(room_channel, json.dumps({
                "type": "participant_update", 
                "participants": current_participants,
                "host_id": room_data.get("host_id")
            }))
    except Exception as e:
        logger.error(f"WebSocket error for {student_id} in room {room_id}: {e}", exc_info=True)
    finally:
        manager.disconnect(websocket, room_id)
        logger.info(f"Cleaned up connection for {student_id} in room {room_id}")