"""Eden.ai service for AI operations - transcription, analysis, and more."""

import httpx
import time
from typing import Optional, List, Dict
import json
import base64
from pathlib import Path
from datetime import datetime

from .debug import log_request, log_response, is_debug_enabled
from ..config import get_models_config, get_system_prompt, DEFAULT_TRANSCRIPTION_MODELS, DEFAULT_ANALYSIS_MODELS, DEFAULT_RESOURCES_MODELS


EDEN_API_URL = "https://api.edenai.run/v2"


def get_transcription_models() -> Dict:
    """Get current transcription model configurations."""
    models = get_models_config()
    return models.get("transcription", DEFAULT_TRANSCRIPTION_MODELS)


def get_analysis_models() -> Dict:
    """Get current analysis model configurations."""
    models = get_models_config()
    return models.get("analysis", DEFAULT_ANALYSIS_MODELS)


def get_resources_models() -> Dict:
    """Get current resources model configurations."""
    models = get_models_config()
    return models.get("resources", DEFAULT_RESOURCES_MODELS)


def get_provider_model(provider: str, model_type: str = "analysis") -> str:
    """
    Get the model name for a provider.

    Args:
        provider: Provider name
        model_type: 'transcription', 'analysis', or 'resources'

    Returns:
        Model name string
    """
    if model_type == "transcription":
        models = get_transcription_models()
    elif model_type == "resources":
        models = get_resources_models()
    else:
        models = get_analysis_models()

    if provider in models:
        return models[provider].get("model", provider)
    return provider


# Keep these for backward compatibility (used by other modules)
TRANSCRIPTION_MODELS = DEFAULT_TRANSCRIPTION_MODELS
ANALYSIS_MODELS = DEFAULT_ANALYSIS_MODELS
RESOURCES_MODELS = DEFAULT_RESOURCES_MODELS

# Legacy mapping for backward compatibility (deprecated - use get_provider_model() instead)
# This is a static snapshot at module load time; actual runtime values come from config
PROVIDER_MODELS = {
    # Chat/LLM providers
    "openai": DEFAULT_ANALYSIS_MODELS["openai"]["model"],
    "anthropic": DEFAULT_ANALYSIS_MODELS["anthropic"]["model"],
    "google": DEFAULT_ANALYSIS_MODELS["google"]["model"],
    "mistral": DEFAULT_ANALYSIS_MODELS["mistral"]["model"],
    "meta": DEFAULT_ANALYSIS_MODELS["meta"]["model"],
    "cohere": DEFAULT_ANALYSIS_MODELS["cohere"]["model"],
    "perplexityai": "sonar-pro",
    # Speech-to-text providers
    "assemblyai": DEFAULT_TRANSCRIPTION_MODELS["assemblyai"]["model"],
    "deepgram": DEFAULT_TRANSCRIPTION_MODELS["deepgram"]["model"],
    "amazon": DEFAULT_TRANSCRIPTION_MODELS["amazon"]["model"],
    "microsoft": DEFAULT_TRANSCRIPTION_MODELS["microsoft"]["model"],
}


def calculate_transcription_cost(duration_seconds: float, provider: str = "openai") -> dict:
    """
    Calculate transcription cost based on audio duration.

    Args:
        duration_seconds: Audio duration in seconds
        provider: Transcription provider name

    Returns:
        Cost info dict with cost_usd, provider, model, duration
    """
    models = get_transcription_models()
    model_info = models.get(provider, models.get("openai", {"model": "whisper", "cost_per_min": 0.003}))
    duration_minutes = duration_seconds / 60
    cost_usd = duration_minutes * model_info.get("cost_per_min", 0.003)

    return {
        "operation": "transcription",
        "provider": provider,
        "model": model_info.get("model", provider),
        "cost_usd": round(cost_usd, 6),
        "duration_seconds": duration_seconds,
        "timestamp": datetime.now().isoformat()
    }


def calculate_chat_cost(input_tokens: int, output_tokens: int, provider: str = "openai") -> dict:
    """
    Calculate chat/analysis cost based on token usage.

    Args:
        input_tokens: Number of input tokens
        output_tokens: Number of output tokens
        provider: Analysis provider name

    Returns:
        Cost info dict with cost_usd, tokens, provider, model
    """
    models = get_analysis_models()
    model_info = models.get(provider, models.get("openai", {"model": "gpt-4o", "cost_per_1k_tokens": 0.002}))
    total_tokens = input_tokens + output_tokens
    cost_usd = (total_tokens / 1000) * model_info.get("cost_per_1k_tokens", 0.002)

    return {
        "operation": "analysis",
        "provider": provider,
        "model": model_info.get("model", provider),
        "cost_usd": round(cost_usd, 6),
        "input_tokens": input_tokens,
        "output_tokens": output_tokens,
        "total_tokens": total_tokens,
        "timestamp": datetime.now().isoformat()
    }


def calculate_resources_cost(provider: str = "perplexityai") -> dict:
    """
    Calculate resources/citation lookup cost.

    Args:
        provider: Resources provider (default perplexityai)

    Returns:
        Cost info dict with cost_usd, provider, model
    """
    models = get_resources_models()
    model_info = models.get(provider, models.get("perplexityai", {"model": "sonar-pro", "cost_per_request": 0.005}))

    return {
        "operation": "resources",
        "provider": provider,
        "model": model_info.get("model", provider),
        "cost_usd": model_info.get("cost_per_request", 0.005),
        "timestamp": datetime.now().isoformat()
    }


def estimate_tokens(text: str) -> int:
    """Estimate token count from text (roughly 4 chars per token)."""
    return max(1, len(text) // 4)


def extract_usage_from_response(result: dict, provider: str) -> tuple:
    """
    Extract token usage from Eden.ai response.

    Returns:
        Tuple of (input_tokens, output_tokens)
    """
    if provider in result and isinstance(result[provider], dict):
        usage = result[provider].get("usage", {})
        input_tokens = usage.get("prompt_tokens", 0) or usage.get("input_tokens", 0)
        output_tokens = usage.get("completion_tokens", 0) or usage.get("output_tokens", 0)

        # If no usage data, estimate from text
        if input_tokens == 0 and output_tokens == 0:
            generated = result[provider].get("generated_text", "")
            output_tokens = estimate_tokens(generated)

        return input_tokens, output_tokens

    return 0, 0


async def transcribe_with_eden(
    file_path: str,
    api_key: str,
    language: str = "en",
    providers: List[str] = None
) -> dict:
    """
    Transcribe audio using Eden.ai speech-to-text async.

    Args:
        file_path: Path to audio file
        api_key: Eden.ai API key
        language: Language code (e.g., 'en', 'es', 'fr')
        providers: List of providers (e.g., ['openai', 'google', 'assemblyai'])

    Returns:
        Dict with transcription results from each provider
    """
    if providers is None:
        providers = ["openai"]  # Default to OpenAI Whisper

    url = f"{EDEN_API_URL}/audio/speech_to_text_async"

    headers = {
        "Authorization": f"Bearer {api_key}"
    }

    # Read file
    with open(file_path, 'rb') as f:
        file_content = f.read()

    file_name = Path(file_path).name

    async with httpx.AsyncClient(timeout=300.0) as client:
        files = {
            'file': (file_name, file_content, 'audio/mpeg')
        }
        data = {
            'providers': ','.join(providers),
            'language': language,
        }

        response = await client.post(url, headers=headers, files=files, data=data)
        response.raise_for_status()
        result = response.json()

        # Eden returns async job, poll for result
        if 'public_id' in result:
            job_id = result['public_id']
            return await _poll_eden_job(client, api_key, job_id, 'audio/speech_to_text_async')

        return result


async def _poll_eden_job(client: httpx.AsyncClient, api_key: str, job_id: str, endpoint: str) -> dict:
    """Poll Eden.ai async job until complete."""
    import asyncio

    url = f"{EDEN_API_URL}/{endpoint}/{job_id}"
    headers = {"Authorization": f"Bearer {api_key}"}

    for _ in range(60):  # Max 5 minutes
        response = await client.get(url, headers=headers)
        result = response.json()

        if result.get('status') == 'finished':
            return result.get('results', result)
        elif result.get('status') == 'failed':
            raise Exception(f"Eden.ai job failed: {result.get('error', 'Unknown error')}")

        await asyncio.sleep(5)

    raise Exception("Eden.ai job timed out")


async def chat_with_eden(
    messages: List[Dict],
    api_key: str,
    providers: List[str] = None,
    model: str = None,
    temperature: float = 0.7,
    max_tokens: int = 2000
) -> dict:
    """
    Chat completion using Eden.ai text/chat endpoint.

    Args:
        messages: List of message dicts with 'role' and 'content'
        api_key: Eden.ai API key
        providers: List of providers (e.g., ['openai', 'anthropic', 'perplexity'])
        model: Specific model to use (optional)
        temperature: Sampling temperature
        max_tokens: Max response tokens

    Returns:
        Chat completion response
    """
    if providers is None:
        providers = ["openai"]

    url = f"{EDEN_API_URL}/text/chat"

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    # Convert messages to Eden format
    eden_messages = []
    for msg in messages:
        eden_messages.append({
            "role": msg.get("role", "user"),
            "message": msg.get("content", "")
        })

    # Build payload
    payload = {
        "providers": ','.join(providers),
        "text": eden_messages[-1]["message"] if eden_messages else "",
        "previous_history": eden_messages[:-1] if len(eden_messages) > 1 else [],
        "temperature": temperature,
        "max_tokens": max_tokens
    }

    # Add model settings - use provided model or get from config
    provider = providers[0]
    if model:
        payload["settings"] = {provider: model}
    else:
        # Get model from user config (merges defaults with overrides)
        provider_model = get_provider_model(provider, "analysis")
        if provider_model and provider_model != provider:
            payload["settings"] = {provider: provider_model}

    # Log request for debugging
    request_id = log_request(
        service="eden_ai",
        endpoint="text/chat",
        method="POST",
        url=url,
        headers=headers,
        payload=payload,
        provider=provider
    )

    start_time = time.time()
    async with httpx.AsyncClient(timeout=120.0) as client:
        try:
            response = await client.post(url, headers=headers, json=payload)
            duration_ms = (time.time() - start_time) * 1000
            response.raise_for_status()
            result = response.json()

            # Log response for debugging
            log_response(request_id, response.status_code, result, duration_ms=duration_ms)

            # Extract usage and calculate cost
            input_tokens, output_tokens = extract_usage_from_response(result, provider)
            # If no tokens from API, estimate from input text
            if input_tokens == 0:
                input_tokens = estimate_tokens(eden_messages[-1]["message"]) if eden_messages else 0
            cost_info = calculate_chat_cost(input_tokens, output_tokens, provider)

            # Add cost_info to result
            result["cost_info"] = cost_info
            return result
        except Exception as e:
            duration_ms = (time.time() - start_time) * 1000
            log_response(request_id, getattr(e, 'status_code', 500), None, error=str(e), duration_ms=duration_ms)
            raise


async def generate_questions(
    text: str,
    api_key: str,
    num_questions: int = 8,
    provider: str = "openai"
) -> List[str]:
    """
    Generate suggested questions about a text using Eden.ai.

    Args:
        text: The transcription text
        api_key: Eden.ai API key
        num_questions: Number of questions to generate (default 8)
        provider: Provider to use

    Returns:
        List of suggested questions
    """
    url = f"{EDEN_API_URL}/text/chat"

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    # Get the system prompt from config (user-configurable)
    system_prompt = get_system_prompt("questions_generate")

    prompt = f"""{system_prompt}

Text:
{text[:6000]}

Generate exactly {num_questions} questions."""

    payload = {
        "providers": provider,
        "text": prompt,
        "previous_history": [],
        "temperature": 0.7,
        "max_tokens": 1000
    }

    # Get model from user config (merges defaults with overrides)
    provider_model = get_provider_model(provider, "analysis")
    if provider_model and provider_model != provider:
        payload["settings"] = {provider: provider_model}

    # Log request for debugging
    request_id = log_request(
        service="eden_ai",
        endpoint="text/chat (questions)",
        method="POST",
        url=url,
        headers=headers,
        payload=payload,
        provider=provider
    )

    start_time = time.time()
    async with httpx.AsyncClient(timeout=60.0) as client:
        try:
            response = await client.post(url, headers=headers, json=payload)
            duration_ms = (time.time() - start_time) * 1000
            response.raise_for_status()
            result = response.json()

            # Log response for debugging
            log_response(request_id, response.status_code, result, duration_ms=duration_ms)
        except Exception as e:
            duration_ms = (time.time() - start_time) * 1000
            log_response(request_id, getattr(e, 'status_code', 500), None, error=str(e), duration_ms=duration_ms)
            raise

    # Extract questions from response
    response_text = extract_eden_response(result, provider)

    # Parse numbered questions - handle both Arabic and English question marks
    questions = []
    lines = response_text.strip().split('\n')
    for line in lines:
        line = line.strip()
        # Match lines starting with number and period
        if line and (line[0].isdigit() or line.startswith('-')):
            # Remove numbering
            question = line.lstrip('0123456789.-) ').strip()
            # Check for question mark (both English '?' and Arabic '؟')
            if question and ('?' in question or '؟' in question):
                questions.append(question)

    return questions[:num_questions]


async def search_with_perplexity(
    query: str,
    api_key: str,
    context: str = None
) -> dict:
    """
    Search for information with citations using Perplexity via Eden.ai.

    Perplexity's online models search the web and provide cited answers.

    Args:
        query: The search query or question
        api_key: Eden.ai API key
        context: Optional context to include

    Returns:
        Dict with answer and sources
    """
    url = f"{EDEN_API_URL}/text/chat"

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    # Get the system prompt from config (user-configurable)
    search_instructions = get_system_prompt("perplexity_search")

    # Build the prompt to maximize citations
    if context:
        prompt = f"""Based on the following context and your web search capabilities, please answer:

Context:
{context[:2000]}

Question: {query}

{search_instructions}"""
    else:
        prompt = f"""{query}

{search_instructions}"""

    payload = {
        "providers": "perplexityai",  # Note: Eden.ai uses "perplexityai" not "perplexity"
        "text": prompt,
        "previous_history": [],
        "temperature": 0.3,  # Lower temperature for more factual responses
        "max_tokens": 2000,
        "settings": {
            "perplexityai": "sonar-pro"  # Use Sonar Pro for better search results
        }
    }

    # Log request for debugging
    request_id = log_request(
        service="eden_ai",
        endpoint="text/chat (perplexity)",
        method="POST",
        url=url,
        headers=headers,
        payload=payload,
        provider="perplexity"
    )

    start_time = time.time()
    async with httpx.AsyncClient(timeout=120.0) as client:
        try:
            response = await client.post(url, headers=headers, json=payload)
            duration_ms = (time.time() - start_time) * 1000
            response.raise_for_status()
            result = response.json()

            # Log response for debugging
            log_response(request_id, response.status_code, result, duration_ms=duration_ms)

            # Extract response
            answer = ""
            citations = []
            if "perplexityai" in result:
                perplexity_result = result["perplexityai"]
                if isinstance(perplexity_result, dict):
                    answer = perplexity_result.get("generated_text", "")
                    # Check for citations in the response
                    citations = perplexity_result.get("citations", [])
                else:
                    answer = str(perplexity_result)
            elif "perplexity" in result:
                # Fallback to old provider name
                perplexity_result = result["perplexity"]
                if isinstance(perplexity_result, dict):
                    answer = perplexity_result.get("generated_text", "")
                    citations = perplexity_result.get("citations", [])
                else:
                    answer = str(perplexity_result)

            # Calculate cost for Perplexity request
            cost_info = calculate_resources_cost("perplexityai")

            return {
                "answer": answer,
                "citations": citations,
                "provider": "perplexity",
                "cost_info": cost_info,
                "raw_response": result
            }
        except Exception as e:
            duration_ms = (time.time() - start_time) * 1000
            log_response(request_id, getattr(e, 'status_code', 500), None, error=str(e), duration_ms=duration_ms)
            raise


async def analyze_with_eden(
    text: str,
    api_key: str,
    analysis_type: str = "summarize",
    providers: List[str] = None
) -> dict:
    """
    Analyze text using Eden.ai specialized endpoints.

    Args:
        text: Text to analyze
        api_key: Eden.ai API key
        analysis_type: Type of analysis ('summarize', 'sentiment', 'keyword', 'topic')
        providers: List of providers

    Returns:
        Analysis results
    """
    if providers is None:
        providers = ["openai"]

    endpoints = {
        'summarize': 'text/summarize',
        'sentiment': 'text/sentiment_analysis',
        'keyword': 'text/keyword_extraction',
        'topic': 'text/topic_extraction',
    }

    endpoint = endpoints.get(analysis_type, 'text/summarize')
    url = f"{EDEN_API_URL}/{endpoint}"

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    # Truncate if too long
    max_chars = 10000
    if len(text) > max_chars:
        text = text[:max_chars]

    payload = {
        "providers": ','.join(providers),
        "text": text,
        "language": "en"
    }

    async with httpx.AsyncClient(timeout=60.0) as client:
        response = await client.post(url, headers=headers, json=payload)
        response.raise_for_status()
        return response.json()


async def translate_with_eden(
    text: str,
    api_key: str,
    target_language: str,
    source_language: str = "en",
    providers: List[str] = None
) -> dict:
    """
    Translate text using Eden.ai.

    Args:
        text: Text to translate
        api_key: Eden.ai API key
        target_language: Target language code
        source_language: Source language code
        providers: List of providers

    Returns:
        Translation results
    """
    if providers is None:
        providers = ["google", "amazon"]

    url = f"{EDEN_API_URL}/translation/automatic_translation"

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    payload = {
        "providers": ','.join(providers),
        "text": text,
        "source_language": source_language,
        "target_language": target_language
    }

    async with httpx.AsyncClient(timeout=60.0) as client:
        response = await client.post(url, headers=headers, json=payload)
        response.raise_for_status()
        return response.json()


def extract_eden_response(result: dict, provider: str = None) -> str:
    """
    Extract text response from Eden.ai result format.

    Args:
        result: Eden.ai API response
        provider: Specific provider to extract from (optional)

    Returns:
        Extracted text response
    """
    if not result:
        return "No response received"

    # If specific provider requested
    if provider and provider in result:
        provider_result = result[provider]
        if isinstance(provider_result, dict):
            return (provider_result.get("generated_text") or
                    provider_result.get("message") or
                    provider_result.get("text") or
                    str(provider_result))
        return str(provider_result)

    # Try to find response from any provider
    for provider_name, provider_result in result.items():
        if isinstance(provider_result, dict):
            if 'generated_text' in provider_result:
                return provider_result['generated_text']
            if 'message' in provider_result:
                return provider_result['message']
            if 'text' in provider_result:
                return provider_result['text']

    return str(result)


def transcribe_with_eden_sync(
    file_path: str,
    api_key: str,
    language: str = "en",
    providers: List[str] = None,
    progress_callback=None
) -> str:
    """
    Synchronous wrapper for Eden.ai transcription.
    Compatible with existing transcriber interface.
    """
    import asyncio
    import concurrent.futures

    if progress_callback:
        progress_callback(10, "Uploading to Eden.ai...")

    def run_async():
        return asyncio.run(transcribe_with_eden(file_path, api_key, language, providers))

    try:
        # Run in thread to avoid event loop conflicts
        with concurrent.futures.ThreadPoolExecutor() as executor:
            future = executor.submit(run_async)
            result = future.result(timeout=300)
    except Exception as e:
        raise Exception(f"Transcription failed: {str(e)}")

    if progress_callback:
        progress_callback(90, "Processing response...")

    # Extract text from Eden response
    text = ""
    if isinstance(result, dict):
        for provider, data in result.items():
            if isinstance(data, dict) and 'text' in data:
                text = data['text']
                break
            elif isinstance(data, dict) and 'results' in data:
                for r in data.get('results', []):
                    if 'text' in r:
                        text = r['text']
                        break

    if progress_callback:
        progress_callback(100, "Complete!")

    return text


async def comprehensive_analysis_eden(
    text: str,
    api_key: str,
    providers: List[str] = None
) -> dict:
    """
    Comprehensive analysis using Eden.ai - summary, keywords, topics.

    Args:
        text: Text to analyze
        api_key: Eden.ai API key
        providers: Providers to use

    Returns:
        Dict with summary, keywords, topics
    """
    if providers is None:
        providers = ["openai"]

    results = {}

    # Get summary
    try:
        summary_result = await analyze_with_eden(text, api_key, "summarize", providers)
        for provider, data in summary_result.items():
            if isinstance(data, dict) and 'result' in data:
                results['summary'] = data['result']
                break
    except Exception as e:
        results['summary_error'] = str(e)

    # Get keywords
    try:
        keyword_result = await analyze_with_eden(text, api_key, "keyword", providers)
        keywords = []
        for provider, data in keyword_result.items():
            if isinstance(data, dict) and 'items' in data:
                keywords = [item.get('keyword', '') for item in data['items'][:10]]
                break
        results['keywords'] = keywords
    except Exception as e:
        results['keywords_error'] = str(e)

    # Get topics
    try:
        topic_result = await analyze_with_eden(text, api_key, "topic", providers)
        topics = []
        for provider, data in topic_result.items():
            if isinstance(data, dict) and 'items' in data:
                topics = [item.get('category', '') for item in data['items'][:5]]
                break
        results['topics'] = topics
    except Exception as e:
        results['topics_error'] = str(e)

    return results
