# services/response_manager.py
import json
import base64
from typing import Optional, Dict, Union
from .redis_client import redis_client

class ResponseManager:
    """
    Manages response state in a central Redis store using a FIFO Queue (List)
    for each student_id. This is the definitive, race-condition-safe solution
    for a stateless client.
    """

    def __init__(self):
        if redis_client is None:
            raise ConnectionError("ResponseManager requires a valid Redis connection.")
        self.redis = redis_client
        self.ttl_seconds = 600  # A student's queue will expire 10 mins after the last item is added

    def _get_key(self, student_id: str) -> str:
        """Creates a consistent key for the student's queue."""
        return f"student_queue:{student_id}"

    
    def store_response(self, student_id: str, text: Union[str, Dict], audio_filepath: Optional[str] = None, audio_bytes: Optional[bytes] = None) -> None:
        """
        Adds a new response to the queue. The 'text' can be a string or a dictionary.
        """
        key = self._get_key(student_id)
        encoded_audio = base64.b64encode(audio_bytes).decode('utf-8') if audio_bytes else None
        
        # This payload now flexibly stores either a string or a dict in the 'text' field.
        payload = {
            "text": text,
            "audio_filepath": audio_filepath,
            "audio_bytes_b64": encoded_audio
        }
        self.redis.rpush(key, json.dumps(payload))
        self.redis.expire(key, self.ttl_seconds)


    def get_response(self, student_id: str) -> Dict:
        """Atomically retrieves and removes the OLDEST response from the front of the queue."""
        key = self._get_key(student_id)
        # LPOP atomically retrieves and removes the item from the left (start) of the list.
        json_value = self.redis.lpop(key)

        if not json_value:
            return {"text": None, "audio_filepath": None, "audio_bytes": None}

        payload = json.loads(json_value)
        if payload.get("audio_bytes_b64"):
            payload["audio_bytes"] = base64.b64decode(payload["audio_bytes_b64"])
        else:
            payload["audio_bytes"] = None
        del payload["audio_bytes_b64"]
        return payload

    def clear_response(self, student_id: str) -> None:
        """Completely deletes the entire queue for a student."""
        key = self._get_key(student_id)
        self.redis.delete(key)

    def is_response_fresh(self, student_id: str) -> bool:
        """Checks if there are any items in the student's queue."""
        key = self._get_key(student_id)
        # LLEN gets the length of the list. If it's > 0, a response is ready.
        return self.redis.llen(key) > 0