"""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, 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
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 using verified model names
    provider = providers[0]
    if provider in PROVIDER_MODELS:
        payload["settings"] = {provider: PROVIDER_MODELS[provider]}
    elif model:
        payload["settings"] = {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"
    }

    prompt = f"""Based on the following text, generate {num_questions} insightful questions that someone might want to ask about it.

IMPORTANT: Generate questions in the SAME LANGUAGE as the text.

Text:
{text[:6000]}

Generate exactly {num_questions} questions. Format your response as a numbered list like:
1. Question one?
2. Question two?
...

The questions should:
- Cover different aspects of the content
- Be specific to the actual content
- Include both factual and analytical questions
- Be useful for understanding the topic better
- Be in the SAME LANGUAGE as the text"""

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

    if provider in PROVIDER_MODELS:
        payload["settings"] = {provider: PROVIDER_MODELS[provider]}

    # 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"
    }

    # 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}

IMPORTANT: Provide your answer with:
1. Direct citations and links to real sources (URLs)
2. Book references with author, title, and year
3. Academic papers with DOI links if available
4. Only cite real, verifiable sources"""
    else:
        prompt = f"""{query}

IMPORTANT: Provide your answer with:
1. Direct citations and links to real sources (URLs)
2. Book references with author, title, and year
3. Academic papers with DOI links if available
4. Only cite real, verifiable sources"""

    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
