"""
Sentence Store Service - Supabase storage for TTS requests.

Stores all request text + metadata in Supabase for analytics and auditing.
Non-blocking writes (fire-and-forget) to avoid impacting TTFB.

Graceful degradation: if env vars missing, storage is skipped silently.
"""

from __future__ import annotations

import os
import logging
import asyncio
from datetime import datetime, timezone
from typing import Any, Dict, Optional

logger = logging.getLogger(__name__)

# Table name in Supabase
TABLE_NAME = "tts_requests"

# Lazy import supabase to avoid import errors if not installed
_supabase_client_class = None


def _get_supabase_client():
    """Lazy import supabase client."""
    global _supabase_client_class
    if _supabase_client_class is None:
        try:
            from supabase import create_client
            _supabase_client_class = create_client
        except ImportError:
            logger.warning("supabase package not installed, sentence storage disabled")
            return None
    return _supabase_client_class


def create_client(url: str, key: str):
    """Create Supabase client (wrapper for lazy import)."""
    client_func = _get_supabase_client()
    if client_func is None:
        return None
    return client_func(url, key)


def create_sentence_record(
    request_id: str,
    text: str,
    speaker: str,
    stream: bool = False,
    format: str = "wav",
    temperature: float = 0.8,
    top_k: int = 50,
    top_p: float = 1.0,
    max_tokens: int = 4096,
    repetition_penalty: float = 1.05,
    seed: Optional[int] = None,
    text_chunked: bool = False,
    ttfb_ms: Optional[int] = None,
    audio_duration_seconds: Optional[float] = None,
) -> Dict[str, Any]:
    """
    Create a sentence record dictionary for storage.
    
    Args:
        request_id: Unique request identifier (X-Request-ID)
        text: Input text for TTS
        speaker: Speaker name (resolved internal name)
        stream: Whether streaming was enabled
        format: Audio format (wav, opus, mp3, etc.)
        temperature: Sampling temperature
        top_k: Top-k sampling parameter
        top_p: Nucleus sampling parameter
        max_tokens: Maximum tokens to generate
        repetition_penalty: Repetition penalty
        seed: Random seed (if specified)
        text_chunked: Whether text was chunked for generation
        ttfb_ms: Time to first byte in milliseconds
        audio_duration_seconds: Duration of generated audio
    
    Returns:
        Dictionary ready for Supabase insertion
    """
    return {
        "request_id": request_id,
        "text": text,
        "text_length": len(text),
        "speaker": speaker,
        "stream": stream,
        "format": format,
        "temperature": temperature,
        "top_k": top_k,
        "top_p": top_p,
        "max_tokens": max_tokens,
        "repetition_penalty": repetition_penalty,
        "seed": seed,
        "text_chunked": text_chunked,
        "ttfb_ms": ttfb_ms,
        "audio_duration_seconds": audio_duration_seconds,
        "created_at": datetime.now(timezone.utc).isoformat(),
    }


class SentenceStore:
    """
    Service for storing TTS request text and metadata in Supabase.
    
    Graceful degradation: if env vars missing, all operations are no-ops.
    Non-blocking: use store_fire_and_forget() for async background writes.
    """
    
    def __init__(self):
        """Initialize Supabase client from environment variables."""
        # Get credentials from environment
        supabase_url = os.environ.get('SUPABASE_URL', '')
        supabase_key = (
            os.environ.get('SUPABASE_SERVICE_KEY') or 
            os.environ.get('SUPABASE_KEY') or 
            ''
        )
        
        self.client = None
        
        if not supabase_url or not supabase_key:
            logger.debug("Supabase credentials not configured, sentence storage disabled")
            return
        
        try:
            self.client = create_client(supabase_url, supabase_key)
            if self.client is not None:
                logger.info(f"SentenceStore initialized: {supabase_url[:30]}...")
        except Exception as e:
            logger.warning(f"Failed to initialize Supabase client: {e}")
            self.client = None
    
    def is_configured(self) -> bool:
        """Check if Supabase is configured and accessible."""
        return self.client is not None
    
    async def store(
        self,
        request_id: str,
        text: str,
        speaker: str,
        stream: bool = False,
        format: str = "wav",
        temperature: float = 0.8,
        top_k: int = 50,
        top_p: float = 1.0,
        max_tokens: int = 4096,
        repetition_penalty: float = 1.05,
        seed: Optional[int] = None,
        text_chunked: bool = False,
        ttfb_ms: Optional[int] = None,
        audio_duration_seconds: Optional[float] = None,
    ) -> bool:
        """
        Store a TTS request record in Supabase.
        
        Args:
            ... (see create_sentence_record for details)
        
        Returns:
            True if stored successfully, False otherwise
        """
        if not self.is_configured():
            logger.debug(f"Supabase not configured, skipping store for {request_id}")
            return False
        
        try:
            record = create_sentence_record(
                request_id=request_id,
                text=text,
                speaker=speaker,
                stream=stream,
                format=format,
                temperature=temperature,
                top_k=top_k,
                top_p=top_p,
                max_tokens=max_tokens,
                repetition_penalty=repetition_penalty,
                seed=seed,
                text_chunked=text_chunked,
                ttfb_ms=ttfb_ms,
                audio_duration_seconds=audio_duration_seconds,
            )
            
            # Insert into Supabase
            # Note: supabase-py is sync, so we run in executor for async context
            loop = asyncio.get_event_loop()
            await loop.run_in_executor(
                None,
                lambda: self.client.table(TABLE_NAME).insert(record).execute()
            )
            
            logger.debug(f"Stored sentence for request {request_id}")
            return True
            
        except Exception as e:
            logger.warning(f"Failed to store sentence for {request_id}: {e}")
            return False
    
    def store_fire_and_forget(
        self,
        request_id: str,
        text: str,
        speaker: str,
        **kwargs
    ) -> Optional[asyncio.Task]:
        """
        Store a TTS request record without blocking.
        
        Creates a background task that completes independently.
        Does not block the calling coroutine.
        
        Args:
            ... (see store() for details)
        
        Returns:
            asyncio.Task if storage was initiated, None if not configured
        """
        if not self.is_configured():
            return None
        
        async def _background_store():
            try:
                await self.store(
                    request_id=request_id,
                    text=text,
                    speaker=speaker,
                    **kwargs
                )
            except Exception as e:
                # Fire-and-forget: log and swallow errors
                logger.warning(f"Background store failed for {request_id}: {e}")
        
        # Create task that runs independently
        try:
            loop = asyncio.get_event_loop()
            task = loop.create_task(_background_store())
            return task
        except RuntimeError:
            # No event loop running - can't create task
            logger.debug("No event loop for fire-and-forget store")
            return None


# Module-level singleton
_sentence_store: Optional[SentenceStore] = None


def get_sentence_store() -> SentenceStore:
    """Get the singleton SentenceStore instance."""
    global _sentence_store
    if _sentence_store is None:
        _sentence_store = SentenceStore()
    return _sentence_store


def is_sentence_store_configured() -> bool:
    """Check if the singleton SentenceStore is configured."""
    global _sentence_store
    if _sentence_store is None:
        return False
    return _sentence_store.is_configured()


def _reset_singleton() -> None:
    """Reset singleton for testing. Do not use in production."""
    global _sentence_store
    _sentence_store = None

