"""
Egrobots SA Client

A Python client for the Egrobots Speech Analysis service.
Supports conversation analysis via batch processing.
"""
import time
from pathlib import Path
from typing import Dict, Optional, Callable, Union
from dotenv import load_dotenv
import os

# Load environment variables from .env file
# Try multiple locations to support both local and Docker deployments
dotenv_paths = [
    Path(__file__).resolve().parents[2] / '.env',  # Project root (local dev)
    Path(__file__).resolve().parent / '.env',      # Same dir as client (Docker)
    Path.cwd() / '.env',                           # Current working directory
]

for dotenv_path in dotenv_paths:
    if dotenv_path.exists():
        load_dotenv(dotenv_path=dotenv_path)
        break


class EgrobotsSSAClient:
    """
    Client for Egrobots SA service.

    Supports batch processing for conversation analysis.
    """

    def __init__(self):
        """
        Initialize the Egrobots SA client.
        Reads the http_url from environment variables.
        """
        self.http_url = os.getenv("BASE_URL")
        if not self.http_url:
            raise ValueError("BASE_URL must be set in the .env file.")

    def _process_conversation_analysis(
        self,
        audio: Union[str, bytes],
        file_name: str = "audio.wav",
        enable_translation: bool = False,
        progress_callback: Optional[Callable] = None,
        max_retries: int = 3,
        retry_delay: int = 2
    ) -> Dict:
        """
        Internal method to process conversation analysis with retry logic.
        
        Args:
            audio: Path to the audio file or audio bytes.
            file_name: The name of the file (used when audio is bytes).
            enable_translation: Enable bilingual response (EN + AR). Default: False for faster processing.
            progress_callback: Optional callback for progress updates.
            max_retries: Maximum number of retry attempts for failed requests. Default: 3.
            retry_delay: Delay in seconds between retry attempts. Default: 2.
        Returns:
            A dictionary containing the conversation analysis results.
        """
        import requests
        from requests.adapters import HTTPAdapter
        from urllib3.util.retry import Retry

        file_size_mb = 0
        mode = 'batch_conversation'

        if isinstance(audio, str):
            audio_file_path = Path(audio)
            if not audio_file_path.exists():
                error = {'error': f'File not found: {audio}'}
                if progress_callback:
                    progress_callback('error', error)
                return error
            file_size_mb = audio_file_path.stat().st_size / (1024 * 1024)
            if progress_callback:
                progress_callback('loading', {'audio_path': audio, 'file_size_mb': file_size_mb, 'mode': mode})
        elif isinstance(audio, bytes):
            file_size_mb = len(audio) / (1024 * 1024)
            if progress_callback:
                progress_callback('loading', {'audio_path': file_name, 'file_size_mb': file_size_mb, 'mode': mode})

        # Configure retry strategy
        retry_strategy = Retry(
            total=max_retries,
            backoff_factor=retry_delay,
            status_forcelist=[429, 500, 502, 503, 504],
            allowed_methods=["POST"]
        )
        
        adapter = HTTPAdapter(max_retries=retry_strategy)
        session = requests.Session()
        session.mount("https://", adapter)
        session.mount("http://", adapter)

        for attempt in range(max_retries + 1):
            try:
                upload_start = time.time()
                endpoint = f"{self.http_url}/analyze-conversation"

                if progress_callback:
                    retry_msg = f" (attempt {attempt + 1}/{max_retries + 1})" if attempt > 0 else ""
                    progress_callback('uploading', {
                        'url': endpoint, 
                        'file_size_mb': file_size_mb,
                        'attempt': attempt + 1,
                        'message': f'Uploading{retry_msg}...'
                    })

                if isinstance(audio, str):
                    with open(audio, 'rb') as f:
                        files = {'audio_file': f}
                        data = {'enable_translation': str(enable_translation).lower()}
                        response = session.post(
                            endpoint,
                            files=files,
                            data=data,
                            timeout=3600
                        )
                else:
                    files = {'audio_file': (file_name, audio, 'audio/wav')}
                    data = {'enable_translation': str(enable_translation).lower()}
                    response = session.post(
                        endpoint,
                        files=files,
                        data=data,
                        timeout=3600
                    )

                upload_time = time.time() - upload_start

                if response.status_code == 200:
                    result = response.json()
                    result['upload_time_seconds'] = upload_time
                    result['file_size_mb'] = file_size_mb

                    if progress_callback:
                        progress_callback('complete', result)

                    return result
                else:
                    error = {'error': f'HTTP {response.status_code}', 'message': response.text}
                    if progress_callback:
                        progress_callback('error', error)
                    return error

            except requests.exceptions.SSLError as e:
                error_msg = str(e)
                if attempt < max_retries:
                    if progress_callback:
                        progress_callback('retrying', {
                            'attempt': attempt + 1,
                            'max_retries': max_retries,
                            'error': 'SSL connection error',
                            'retry_delay': retry_delay
                        })
                    time.sleep(retry_delay)
                    continue
                else:
                    error = {
                        'error': 'SSL Connection Error',
                        'message': 'Failed to establish secure connection with the server. Please check your internet connection and try again.',
                        'technical_details': error_msg
                    }
                    if progress_callback:
                        progress_callback('error', error)
                    return error
                    
            except requests.exceptions.ConnectionError as e:
                error_msg = str(e)
                if attempt < max_retries:
                    if progress_callback:
                        progress_callback('retrying', {
                            'attempt': attempt + 1,
                            'max_retries': max_retries,
                            'error': 'Connection error',
                            'retry_delay': retry_delay
                        })
                    time.sleep(retry_delay)
                    continue
                else:
                    error = {
                        'error': 'Connection Error',
                        'message': 'Unable to connect to the server. Please check your internet connection and try again.',
                        'technical_details': error_msg
                    }
                    if progress_callback:
                        progress_callback('error', error)
                    return error
                    
            except requests.exceptions.Timeout as e:
                error = {
                    'error': 'Request Timeout',
                    'message': 'The request took too long to complete. The audio file may be too large.',
                    'technical_details': str(e)
                }
                if progress_callback:
                    progress_callback('error', error)
                return error
                
            except Exception as e:
                error_msg = str(e)
                if attempt < max_retries and ('SSL' in error_msg or 'Connection' in error_msg):
                    if progress_callback:
                        progress_callback('retrying', {
                            'attempt': attempt + 1,
                            'max_retries': max_retries,
                            'error': error_msg,
                            'retry_delay': retry_delay
                        })
                    time.sleep(retry_delay)
                    continue
                else:
                    error = {
                        'error': 'Unexpected Error',
                        'message': error_msg
                    }
                    if progress_callback:
                        progress_callback('error', error)
                    return error
        
        # This should never be reached, but just in case
        return {
            'error': 'Max retries exceeded',
            'message': 'Failed to complete request after multiple attempts'
        }

    def analyze(
        self,
        audio: Union[str, bytes],
        file_name: str = "audio.wav",
        enable_translation: bool = False,
        progress_callback: Optional[Callable] = None,
        max_retries: int = 3,
        retry_delay: int = 2
    ) -> Dict:
        """
        Analyze an audio file for conversation analysis.

        Args:
            audio: Path to the audio file or audio bytes.
            file_name: The name of the file (used when audio is bytes).
            enable_translation: Enable bilingual response (EN + AR). Default: False for faster processing.
            progress_callback: Optional callback function for progress updates.
            max_retries: Maximum number of retry attempts for failed requests. Default: 3.
            retry_delay: Delay in seconds between retry attempts. Default: 2.

        Returns:
            Dict containing conversation analysis results.
        """
        return self._process_conversation_analysis(
            audio=audio,
            file_name=file_name,
            enable_translation=enable_translation,
            progress_callback=progress_callback,
            max_retries=max_retries,
            retry_delay=retry_delay
        )

    @staticmethod
    def extract_language_version(result: Dict, language: str = 'EN') -> Dict:
        """
        Extract a specific language version from a bilingual response.
        
        Args:
            result: Analysis result (may be bilingual with EN/AR keys)
            language: Language to extract ('EN' or 'AR')
            
        Returns:
            Dictionary with the specified language version plus any metadata
        """
        if language.upper() not in result:
            # Not a bilingual response, return as-is
            return result
        
        # Extract the language version
        lang_data = result[language.upper()].copy()
        
        # Add back any metadata or technical fields
        for key, value in result.items():
            if key not in ['EN', 'AR']:
                lang_data[key] = value
        
        return lang_data

    @staticmethod
    def is_bilingual_response(result: Dict) -> bool:
        """
        Check if a response is in bilingual format.
        
        Args:
            result: Analysis result
            
        Returns:
            True if result has EN and AR keys
        """
        return 'EN' in result and 'AR' in result
