"""Configuration management for Whisper Scribe."""

import os
import json
from pathlib import Path
from typing import Optional, List, Dict
from pydantic import BaseModel


# Default model configurations (can be overridden by user)
DEFAULT_TRANSCRIPTION_MODELS = {
    "deepgram": {"model": "nova-3", "cost_per_min": 0.006},
    "openai": {"model": "whisper", "cost_per_min": 0.003},
    "assemblyai": {"model": "assembly_ai", "cost_per_min": 0.002},
    "amazon": {"model": "amazon", "cost_per_min": 0.004},
    "microsoft": {"model": "microsoft", "cost_per_min": 0.004},
}

DEFAULT_ANALYSIS_MODELS = {
    "openai": {"model": "gpt-4o", "cost_per_1k_tokens": 0.002},
    "anthropic": {"model": "claude-opus-4-5", "cost_per_1k_tokens": 0.002},
    "mistral": {"model": "mistral-large-24.11", "cost_per_1k_tokens": 0.001},
    "cohere": {"model": "command-r-plus", "cost_per_1k_tokens": 0.001},
    "google": {"model": "gemini-2.0-flash", "cost_per_1k_tokens": 0.001},
    "meta": {"model": "llama3-1-8b-instruct-v1:0", "cost_per_1k_tokens": 0.0005},
}

DEFAULT_RESOURCES_MODELS = {
    "perplexityai": {"model": "sonar-pro", "cost_per_request": 0.005},
}

# Default system prompts (can be overridden by user)
DEFAULT_SYSTEM_PROMPTS = {
    "analysis_summary": {
        "name": "Summary",
        "category": "analysis",
        "prompt": "You are a helpful assistant that creates concise summaries. Provide a clear, well-structured summary in 2-3 paragraphs. Focus on the main message and key information. IMPORTANT: Respond in the SAME LANGUAGE as the transcription text."
    },
    "analysis_takeaways": {
        "name": "Key Takeaways",
        "category": "analysis",
        "prompt": "You are a helpful assistant that extracts key takeaways. Provide 3-7 key points as a numbered list. Each point should be a clear, actionable or informative insight. Return ONLY the numbered list, no introduction or conclusion. IMPORTANT: Respond in the SAME LANGUAGE as the transcription text."
    },
    "analysis_topics": {
        "name": "Topics",
        "category": "analysis",
        "prompt": "You are a helpful assistant that identifies topics. List 3-5 main topics or themes discussed. Return ONLY the topics as short phrases (2-4 words each), one per line, no numbering or bullets. IMPORTANT: Respond in the SAME LANGUAGE as the transcription text."
    },
    "analysis_full": {
        "name": "Full Analysis",
        "category": "analysis",
        "prompt": "Analyze this transcription comprehensively. Provide: 1. A concise summary 2. Key points 3. Notable quotes 4. Overall tone 5. Actionable items. IMPORTANT: Respond in the SAME LANGUAGE as the transcription text."
    },
    "critique_main": {
        "name": "Critique",
        "category": "critique",
        "prompt": "Please critique this analysis. Provide: 1. A critique of the analysis identifying any gaps or issues 2. An improved, more comprehensive version 3. Key claims that may need fact-checking. Be constructive and thorough."
    },
    "resources_search": {
        "name": "Find Resources",
        "category": "resources",
        "prompt": "Find authoritative resources, books, and academic references about the given topic. Provide: 1. Recommended Books (with authors) 2. Academic Papers or Studies 3. Reputable Articles 4. Online Resources and Courses. Focus on high-quality, credible sources."
    },
    "qa_answer": {
        "name": "Q&A",
        "category": "qa",
        "prompt": "You are a helpful assistant that answers questions about transcriptions. Base your answers ONLY on the content provided in the transcription. If the answer cannot be found in the transcription, say so clearly. Be concise but thorough. Respond in the same language as the question."
    },
    "format_structure": {
        "name": "Format & Structure",
        "category": "format",
        "prompt": """You are a professional editor that formats transcriptions for better readability.

Your task:
1. Add clear section headers (using ## for main sections, ### for subsections) to organize the content logically
2. Group related content under appropriate headers
3. Add paragraph breaks where appropriate for better readability
4. Keep ALL the original text - do not remove or summarize any content
5. Fix obvious transcription errors if you spot them
6. Add bullet points for lists if appropriate

IMPORTANT:
- Preserve ALL original content - this is a formatting task, not summarization
- Use markdown headers (##, ###) for sections
- Respond in the SAME LANGUAGE as the transcription
- Make the content scannable with clear structure"""
    },
    "translate_prompt": {
        "name": "Translate",
        "category": "translate",
        "prompt": "You are a professional translator. Translate the following text to the target language. Maintain the original meaning, tone, and formatting. Only output the translation, nothing else."
    },
}


def get_config_dir() -> Path:
    """Get the configuration directory."""
    config_dir = Path.home() / ".whisper-scribe"
    config_dir.mkdir(parents=True, exist_ok=True)
    return config_dir


def get_config_file() -> Path:
    """Get the configuration file path."""
    return get_config_dir() / "config.json"


def get_default_output_dir() -> Path:
    """Get the default output directory."""
    output_dir = get_config_dir() / "transcriptions"
    output_dir.mkdir(parents=True, exist_ok=True)
    return output_dir


def get_temp_dir() -> Path:
    """Get the temporary directory for downloads."""
    temp_dir = get_config_dir() / "temp"
    temp_dir.mkdir(parents=True, exist_ok=True)
    return temp_dir


class CustomPrompt(BaseModel):
    """A custom analysis prompt."""
    id: str
    name: str
    prompt: str


class AppConfig(BaseModel):
    """Application configuration."""
    # API Keys
    openai_api_key: str = ""
    perplexity_api_key: str = ""
    anthropic_api_key: str = ""
    eden_api_key: str = ""

    # Provider selection (all through Eden.ai)
    transcription_provider: str = "openai"  # openai, google, amazon, microsoft, assemblyai, deepgram
    analysis_provider: str = "openai"  # openai, anthropic, google, cohere, meta
    critique_provider: str = "anthropic"  # anthropic, openai, google
    resources_provider: str = "perplexity"  # perplexity (best for citations), openai, anthropic, google

    # Output settings
    output_directory: str = ""
    custom_prompts: List[Dict] = []

    # Webhooks
    webhook_url: str = ""
    webhook_enabled: bool = False

    # Model configuration overrides (empty = use defaults)
    transcription_models: Dict[str, Dict] = {}
    analysis_models: Dict[str, Dict] = {}
    resources_models: Dict[str, Dict] = {}

    # System prompt overrides (empty = use defaults)
    system_prompts: Dict[str, str] = {}

    def __init__(self, **data):
        super().__init__(**data)
        if not self.output_directory:
            self.output_directory = str(get_default_output_dir())


def load_config() -> AppConfig:
    """Load configuration from file or environment."""
    config = AppConfig()
    config_file = get_config_file()

    # Try to load from config file
    if config_file.exists():
        try:
            with open(config_file, 'r') as f:
                data = json.load(f)
                config = AppConfig(**data)
        except (json.JSONDecodeError, Exception):  # pragma: no cover
            pass  # Invalid config file, use defaults

    # Environment variables override file config
    if os.environ.get("OPENAI_API_KEY"):
        config.openai_api_key = os.environ["OPENAI_API_KEY"]

    if os.environ.get("PERPLEXITY_API_KEY"):
        config.perplexity_api_key = os.environ["PERPLEXITY_API_KEY"]

    if os.environ.get("ANTHROPIC_API_KEY"):
        config.anthropic_api_key = os.environ["ANTHROPIC_API_KEY"]

    if os.environ.get("EDEN_API_KEY"):
        config.eden_api_key = os.environ["EDEN_API_KEY"]

    if os.environ.get("WHISPER_SCRIBE_OUTPUT_DIR"):
        config.output_directory = os.environ["WHISPER_SCRIBE_OUTPUT_DIR"]

    return config


def save_config(config: AppConfig) -> None:
    """Save configuration to file."""
    config_file = get_config_file()
    with open(config_file, 'w') as f:
        json.dump(config.model_dump(), f, indent=2)


def get_output_directory() -> Path:
    """Get the output directory, creating it if needed."""
    config = load_config()
    output_dir = Path(config.output_directory)
    output_dir.mkdir(parents=True, exist_ok=True)
    return output_dir


def get_api_key() -> str:
    """Get the OpenAI API key."""
    return load_config().openai_api_key


def get_custom_prompts() -> List[Dict]:
    """Get all custom prompts."""
    return load_config().custom_prompts


def add_custom_prompt(prompt_id: str, name: str, prompt: str) -> Dict:
    """Add a new custom prompt."""
    config = load_config()
    new_prompt = {"id": prompt_id, "name": name, "prompt": prompt}
    config.custom_prompts.append(new_prompt)
    save_config(config)
    return new_prompt


def update_custom_prompt(prompt_id: str, name: str = None, prompt: str = None) -> Optional[Dict]:
    """Update an existing custom prompt."""
    config = load_config()
    for p in config.custom_prompts:
        if p["id"] == prompt_id:
            if name is not None:
                p["name"] = name
            if prompt is not None:
                p["prompt"] = prompt
            save_config(config)
            return p
    return None


def delete_custom_prompt(prompt_id: str) -> bool:
    """Delete a custom prompt."""
    config = load_config()
    original_len = len(config.custom_prompts)
    config.custom_prompts = [p for p in config.custom_prompts if p["id"] != prompt_id]
    if len(config.custom_prompts) < original_len:
        save_config(config)
        return True
    return False


def get_webhook_config() -> tuple:
    """Get webhook configuration."""
    config = load_config()
    return config.webhook_url, config.webhook_enabled


def set_webhook_config(url: str = None, enabled: bool = None) -> None:
    """Set webhook configuration."""
    config = load_config()
    if url is not None:
        config.webhook_url = url
    if enabled is not None:
        config.webhook_enabled = enabled
    save_config(config)


def get_anthropic_api_key() -> str:
    """Get the Anthropic API key."""
    return load_config().anthropic_api_key


def get_eden_api_key() -> str:
    """Get the Eden.ai API key."""
    return load_config().eden_api_key


def get_perplexity_api_key() -> str:
    """Get the Perplexity API key."""
    return load_config().perplexity_api_key


def get_provider_settings() -> Dict:
    """Get provider selection settings."""
    config = load_config()
    return {
        "transcription_provider": config.transcription_provider,
        "analysis_provider": config.analysis_provider,
        "critique_provider": config.critique_provider,
        "resources_provider": config.resources_provider
    }


def set_provider_settings(
    transcription_provider: str = None,
    analysis_provider: str = None,
    critique_provider: str = None,
    resources_provider: str = None
) -> None:
    """Set provider selection settings."""
    config = load_config()
    if transcription_provider is not None:
        config.transcription_provider = transcription_provider
    if analysis_provider is not None:
        config.analysis_provider = analysis_provider
    if critique_provider is not None:
        config.critique_provider = critique_provider
    if resources_provider is not None:
        config.resources_provider = resources_provider
    save_config(config)


# ============================================================================
# Model Configuration Functions
# ============================================================================

def get_models_config() -> Dict:
    """
    Get all model configurations (defaults merged with overrides).

    Returns:
        Dict with transcription, analysis, and resources models
    """
    config = load_config()

    # Merge defaults with overrides
    transcription = {**DEFAULT_TRANSCRIPTION_MODELS}
    for provider, settings in config.transcription_models.items():
        if provider in transcription:
            transcription[provider] = {**transcription[provider], **settings}
        else:
            transcription[provider] = settings

    analysis = {**DEFAULT_ANALYSIS_MODELS}
    for provider, settings in config.analysis_models.items():
        if provider in analysis:
            analysis[provider] = {**analysis[provider], **settings}
        else:
            analysis[provider] = settings

    resources = {**DEFAULT_RESOURCES_MODELS}
    for provider, settings in config.resources_models.items():
        if provider in resources:
            resources[provider] = {**resources[provider], **settings}
        else:
            resources[provider] = settings

    return {
        "transcription": transcription,
        "analysis": analysis,
        "resources": resources
    }


def get_model_for_provider(model_type: str, provider: str) -> Dict:
    """
    Get model config for a specific provider.

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

    Returns:
        Model configuration dict
    """
    models = get_models_config()
    type_models = models.get(model_type, {})
    return type_models.get(provider, {})


def update_model_config(model_type: str, provider: str, model: str = None, cost: float = None) -> Dict:
    """
    Update model configuration for a provider.

    Args:
        model_type: 'transcription', 'analysis', or 'resources'
        provider: Provider name
        model: New model name (optional)
        cost: New cost value (optional)

    Returns:
        Updated model configuration
    """
    config = load_config()

    # Get the right config dict
    if model_type == "transcription":
        if provider not in config.transcription_models:
            config.transcription_models[provider] = {}
        if model is not None:
            config.transcription_models[provider]["model"] = model
        if cost is not None:
            config.transcription_models[provider]["cost_per_min"] = cost
        result = {**DEFAULT_TRANSCRIPTION_MODELS.get(provider, {}), **config.transcription_models[provider]}

    elif model_type == "analysis":
        if provider not in config.analysis_models:
            config.analysis_models[provider] = {}
        if model is not None:
            config.analysis_models[provider]["model"] = model
        if cost is not None:
            config.analysis_models[provider]["cost_per_1k_tokens"] = cost
        result = {**DEFAULT_ANALYSIS_MODELS.get(provider, {}), **config.analysis_models[provider]}

    elif model_type == "resources":
        if provider not in config.resources_models:
            config.resources_models[provider] = {}
        if model is not None:
            config.resources_models[provider]["model"] = model
        if cost is not None:
            config.resources_models[provider]["cost_per_request"] = cost
        result = {**DEFAULT_RESOURCES_MODELS.get(provider, {}), **config.resources_models[provider]}

    else:
        return {}

    save_config(config)
    return result


def reset_models_to_defaults(model_type: str = None) -> None:
    """
    Reset model configurations to defaults.

    Args:
        model_type: 'transcription', 'analysis', 'resources', or None for all
    """
    config = load_config()

    if model_type is None or model_type == "transcription":
        config.transcription_models = {}
    if model_type is None or model_type == "analysis":
        config.analysis_models = {}
    if model_type is None or model_type == "resources":
        config.resources_models = {}

    save_config(config)


# ============================================================================
# System Prompt Functions
# ============================================================================

def get_all_system_prompts() -> Dict:
    """
    Get all system prompts (defaults merged with overrides).

    Returns:
        Dict of prompt_id -> {name, category, prompt, is_default}
    """
    config = load_config()
    result = {}

    for prompt_id, default_data in DEFAULT_SYSTEM_PROMPTS.items():
        # Check for override
        if prompt_id in config.system_prompts:
            result[prompt_id] = {
                "name": default_data["name"],
                "category": default_data["category"],
                "prompt": config.system_prompts[prompt_id],
                "is_default": False,
                "default_prompt": default_data["prompt"]
            }
        else:
            result[prompt_id] = {
                "name": default_data["name"],
                "category": default_data["category"],
                "prompt": default_data["prompt"],
                "is_default": True,
                "default_prompt": default_data["prompt"]
            }

    return result


def get_system_prompt(prompt_id: str) -> Optional[str]:
    """
    Get a system prompt by ID (with fallback to default).

    Args:
        prompt_id: The prompt identifier

    Returns:
        The prompt text, or None if not found
    """
    config = load_config()

    # Check for override first
    if prompt_id in config.system_prompts:
        return config.system_prompts[prompt_id]

    # Fall back to default
    if prompt_id in DEFAULT_SYSTEM_PROMPTS:
        return DEFAULT_SYSTEM_PROMPTS[prompt_id]["prompt"]

    return None


def update_system_prompt(prompt_id: str, prompt_text: str) -> bool:
    """
    Update a system prompt (creates an override).

    Args:
        prompt_id: The prompt identifier
        prompt_text: The new prompt text

    Returns:
        True if successful, False if prompt_id not valid
    """
    if prompt_id not in DEFAULT_SYSTEM_PROMPTS:
        return False

    config = load_config()
    config.system_prompts[prompt_id] = prompt_text
    save_config(config)
    return True


def reset_system_prompt(prompt_id: str) -> bool:
    """
    Reset a system prompt to its default.

    Args:
        prompt_id: The prompt identifier

    Returns:
        True if reset, False if not found or already default
    """
    config = load_config()

    if prompt_id in config.system_prompts:
        del config.system_prompts[prompt_id]
        save_config(config)
        return True

    return False


def reset_all_system_prompts() -> None:
    """Reset all system prompts to defaults."""
    config = load_config()
    config.system_prompts = {}
    save_config(config)
