import asyncio
from abc import ABC, abstractmethod
from flask import current_app


class LLMProvider(ABC):
    @abstractmethod
    async def chat(self, messages: list, model: str, temperature: float = 0.7) -> str:
        pass


class OpenAIProvider(LLMProvider):
    def __init__(self, api_key: str):
        from openai import AsyncOpenAI
        self.client = AsyncOpenAI(api_key=api_key)

    async def chat(self, messages, model, temperature=0.7, max_tokens=16384):
        resp = await self.client.chat.completions.create(
            model=model, messages=messages, temperature=temperature,
            max_tokens=max_tokens,
        )
        return resp.choices[0].message.content


class AnthropicProvider(LLMProvider):
    def __init__(self, api_key: str):
        from anthropic import AsyncAnthropic
        self.client = AsyncAnthropic(api_key=api_key)

    async def chat(self, messages, model, temperature=0.7, max_tokens=8192):
        system_msg = ""
        user_msgs = []
        for m in messages:
            if m["role"] == "system":
                system_msg = m["content"]
            else:
                user_msgs.append(m)
        resp = await self.client.messages.create(
            model=model, max_tokens=max_tokens, temperature=temperature,
            system=system_msg, messages=user_msgs,
        )
        return resp.content[0].text


def get_provider(provider_name=None, api_key=None) -> LLMProvider:
    provider_name = provider_name or current_app.config["AI_PROVIDER"]
    if provider_name == "openai":
        key = api_key or current_app.config["OPENAI_API_KEY"]
        return OpenAIProvider(key)
    elif provider_name == "anthropic":
        key = api_key or current_app.config["ANTHROPIC_API_KEY"]
        return AnthropicProvider(key)
    raise ValueError(f"Unknown AI provider: {provider_name}")


def get_fast_model() -> str:
    return current_app.config["FAST_MODEL"]


def get_deep_model() -> str:
    return current_app.config["DEEP_MODEL"]


def get_screen_config(screen_name: str, plan_name: str = None):
    """Get AI model config for a specific screen and plan. Returns dict with provider, model, api_key, max_tokens, temperature."""
    from flask_login import current_user
    if plan_name is None:
        try:
            plan = current_user.active_plan
            plan_name = plan.name if plan else "free"
        except Exception:
            plan_name = "free"

    from app.models.features import AIModelConfig
    config = AIModelConfig.query.filter_by(
        screen_name=screen_name, plan_name=plan_name, is_active=True
    ).first()

    if config:
        return {
            "provider": config.provider,
            "model": config.model_name,
            "api_key": config.api_key_override or None,
            "max_tokens": config.max_tokens,
            "temperature": config.temperature,
        }

    return {
        "provider": current_app.config["AI_PROVIDER"],
        "model": current_app.config["DEEP_MODEL"],
        "api_key": None,
        "max_tokens": 16384,
        "temperature": 0.7,
    }


async def call_ai_for_screen(messages: list, screen_name: str, plan_name: str = None) -> str:
    """Call AI using screen-specific config."""
    cfg = get_screen_config(screen_name, plan_name)
    provider = get_provider(cfg["provider"], cfg["api_key"])
    return await provider.chat(messages, cfg["model"], temperature=cfg["temperature"], max_tokens=cfg["max_tokens"])
