import logging
import os
from abc import ABC, abstractmethod
from enum import Enum

import httpx

logger = logging.getLogger(__name__)


class KeyStatus(str, Enum):
    ACTIVE = "active"
    INVALID = "invalid"
    EXPIRED = "expired"
    RATE_LIMITED = "rate_limited"
    UNKNOWN = "unknown"

_VERIFY_TIMEOUT = 15.0


class KeyVerifier(ABC):
    @abstractmethod
    async def verify(self, api_key: str) -> KeyStatus:
        pass


class DefaultKeyVerifier(KeyVerifier):
    async def verify(self, api_key: str) -> KeyStatus:
        return KeyStatus.UNKNOWN


class ChatGPTKeyVerifier(KeyVerifier):
    _BASE_URL = "https://api.openai.com/v1"

    async def verify(self, api_key: str) -> KeyStatus:
        proxy = os.getenv("OPENAI_PROXY") or os.getenv("HTTPS_PROXY")
        try:
            async with httpx.AsyncClient(
                timeout=httpx.Timeout(connect=10.0, read=_VERIFY_TIMEOUT, write=10.0, pool=10.0),
                proxy=proxy,
            ) as client:
                response = await client.post(
                    f"{self._BASE_URL}/chat/completions",
                    headers={
                        "Authorization": f"Bearer {api_key}",
                        "Content-Type": "application/json",
                    },
                    json={
                        "model": "gpt-4o-mini",
                        "messages": [{"role": "user", "content": "hi"}],
                        "max_tokens": 5,
                    },
                )
                if response.status_code == 200:
                    return KeyStatus.ACTIVE
                elif response.status_code == 401:
                    return KeyStatus.INVALID
                elif response.status_code == 429:
                    return KeyStatus.RATE_LIMITED
                elif response.status_code == 403:
                    return KeyStatus.EXPIRED
                else:
                    logger.warning(f"[chatgpt] Unexpected status {response.status_code}")
                    return KeyStatus.UNKNOWN
        except httpx.TimeoutException:
            logger.warning("[chatgpt] Verification timeout")
            return KeyStatus.UNKNOWN
        except httpx.ConnectError as e:
            logger.warning(f"[chatgpt] Connection error: {e}")
            return KeyStatus.UNKNOWN
        except Exception as e:
            logger.error(f"[chatgpt] Verification error: {e}")
            return KeyStatus.UNKNOWN


class DeepSeekKeyVerifier(KeyVerifier):
    _BASE_URL = "https://api.deepseek.com/v1"

    async def verify(self, api_key: str) -> KeyStatus:
        proxy = os.getenv("DEEPSEEK_PROXY") or os.getenv("HTTPS_PROXY")
        try:
            async with httpx.AsyncClient(
                timeout=httpx.Timeout(connect=10.0, read=_VERIFY_TIMEOUT, write=10.0, pool=10.0),
                proxy=proxy,
            ) as client:
                response = await client.post(
                    f"{self._BASE_URL}/chat/completions",
                    headers={
                        "Authorization": f"Bearer {api_key}",
                        "Content-Type": "application/json",
                    },
                    json={
                        "model": "deepseek-chat",
                        "messages": [{"role": "user", "content": "hi"}],
                        "max_tokens": 5,
                    },
                )
                if response.status_code == 200:
                    return KeyStatus.ACTIVE
                elif response.status_code == 401:
                    return KeyStatus.INVALID
                elif response.status_code == 429:
                    return KeyStatus.RATE_LIMITED
                elif response.status_code == 403:
                    return KeyStatus.EXPIRED
                else:
                    logger.warning(f"[deepseek] Unexpected status {response.status_code}")
                    return KeyStatus.UNKNOWN
        except httpx.TimeoutException:
            logger.warning("[deepseek] Verification timeout")
            return KeyStatus.UNKNOWN
        except httpx.ConnectError as e:
            logger.warning(f"[deepseek] Connection error: {e}")
            return KeyStatus.UNKNOWN
        except Exception as e:
            logger.error(f"[deepseek] Verification error: {e}")
            return KeyStatus.UNKNOWN


class KimiKeyVerifier(KeyVerifier):
    _BASE_URL = "https://api.moonshot.cn/v1"

    async def verify(self, api_key: str) -> KeyStatus:
        proxy = os.getenv("HTTPS_PROXY")
        try:
            async with httpx.AsyncClient(
                timeout=httpx.Timeout(connect=10.0, read=_VERIFY_TIMEOUT, write=10.0, pool=10.0),
                proxy=proxy,
            ) as client:
                response = await client.post(
                    f"{self._BASE_URL}/chat/completions",
                    headers={
                        "Authorization": f"Bearer {api_key}",
                        "Content-Type": "application/json",
                    },
                    json={
                        "model": "moonshot-v1-8k",
                        "messages": [{"role": "user", "content": "hi"}],
                        "max_tokens": 5,
                    },
                )
                if response.status_code == 200:
                    return KeyStatus.ACTIVE
                elif response.status_code == 401:
                    return KeyStatus.INVALID
                elif response.status_code == 429:
                    return KeyStatus.RATE_LIMITED
                elif response.status_code == 403:
                    return KeyStatus.EXPIRED
                else:
                    logger.warning(f"[kimi] Unexpected status {response.status_code}")
                    return KeyStatus.UNKNOWN
        except httpx.TimeoutException:
            logger.warning("[kimi] Verification timeout")
            return KeyStatus.UNKNOWN
        except httpx.ConnectError as e:
            logger.warning(f"[kimi] Connection error: {e}")
            return KeyStatus.UNKNOWN
        except Exception as e:
            logger.error(f"[kimi] Verification error: {e}")
            return KeyStatus.UNKNOWN


class QwenKeyVerifier(KeyVerifier):
    _BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"

    async def verify(self, api_key: str) -> KeyStatus:
        proxy = os.getenv("HTTPS_PROXY")
        try:
            async with httpx.AsyncClient(
                timeout=httpx.Timeout(connect=10.0, read=_VERIFY_TIMEOUT, write=10.0, pool=10.0),
                proxy=proxy,
            ) as client:
                response = await client.post(
                    f"{self._BASE_URL}/chat/completions",
                    headers={
                        "Authorization": f"Bearer {api_key}",
                        "Content-Type": "application/json",
                    },
                    json={
                        "model": "qwen-plus",
                        "messages": [{"role": "user", "content": "hi"}],
                        "max_tokens": 5,
                    },
                )
                if response.status_code == 200:
                    return KeyStatus.ACTIVE
                elif response.status_code == 401:
                    return KeyStatus.INVALID
                elif response.status_code == 429:
                    return KeyStatus.RATE_LIMITED
                elif response.status_code == 403:
                    return KeyStatus.EXPIRED
                else:
                    logger.warning(f"[qwen] Unexpected status {response.status_code}")
                    return KeyStatus.UNKNOWN
        except httpx.TimeoutException:
            logger.warning("[qwen] Verification timeout")
            return KeyStatus.UNKNOWN
        except httpx.ConnectError as e:
            logger.warning(f"[qwen] Connection error: {e}")
            return KeyStatus.UNKNOWN
        except Exception as e:
            logger.error(f"[qwen] Verification error: {e}")
            return KeyStatus.UNKNOWN


class PerplexityKeyVerifier(KeyVerifier):
    _BASE_URL = "https://api.perplexity.ai"

    async def verify(self, api_key: str) -> KeyStatus:
        proxy = os.getenv("HTTPS_PROXY")
        try:
            async with httpx.AsyncClient(
                timeout=httpx.Timeout(connect=10.0, read=_VERIFY_TIMEOUT, write=10.0, pool=10.0),
                proxy=proxy,
            ) as client:
                response = await client.post(
                    f"{self._BASE_URL}/chat/completions",
                    headers={
                        "Authorization": f"Bearer {api_key}",
                        "Content-Type": "application/json",
                    },
                    json={
                        "model": "llama-3.1-sonar-small-128k-online",
                        "messages": [{"role": "user", "content": "hi"}],
                        "max_tokens": 5,
                    },
                )
                if response.status_code == 200:
                    return KeyStatus.ACTIVE
                elif response.status_code == 401:
                    return KeyStatus.INVALID
                elif response.status_code == 429:
                    return KeyStatus.RATE_LIMITED
                elif response.status_code == 403:
                    return KeyStatus.EXPIRED
                else:
                    logger.warning(f"[perplexity] Unexpected status {response.status_code}")
                    return KeyStatus.UNKNOWN
        except httpx.TimeoutException:
            logger.warning("[perplexity] Verification timeout")
            return KeyStatus.UNKNOWN
        except httpx.ConnectError as e:
            logger.warning(f"[perplexity] Connection error: {e}")
            return KeyStatus.UNKNOWN
        except Exception as e:
            logger.error(f"[perplexity] Verification error: {e}")
            return KeyStatus.UNKNOWN


class GeminiKeyVerifier(KeyVerifier):
    _BASE_URL = "https://generativelanguage.googleapis.com/v1beta"

    async def verify(self, api_key: str) -> KeyStatus:
        proxy = os.getenv("HTTPS_PROXY")
        try:
            async with httpx.AsyncClient(
                timeout=httpx.Timeout(connect=10.0, read=_VERIFY_TIMEOUT, write=10.0, pool=10.0),
                proxy=proxy,
            ) as client:
                response = await client.get(
                    f"{self._BASE_URL}/models",
                    headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
                    params={"key": api_key},
                )
                if response.status_code == 200:
                    return KeyStatus.ACTIVE
                elif response.status_code == 403:
                    return KeyStatus.INVALID
                elif response.status_code == 429:
                    return KeyStatus.RATE_LIMITED
                else:
                    logger.warning(f"[gemini] Unexpected status {response.status_code}")
                    return KeyStatus.UNKNOWN
        except httpx.TimeoutException:
            logger.warning("[gemini] Verification timeout")
            return KeyStatus.UNKNOWN
        except httpx.ConnectError as e:
            logger.warning(f"[gemini] Connection error: {e}")
            return KeyStatus.UNKNOWN
        except Exception as e:
            logger.error(f"[gemini] Verification error: {e}")
            return KeyStatus.UNKNOWN


class WenxinKeyVerifier(KeyVerifier):
    async def verify(self, api_key: str) -> KeyStatus:
        return KeyStatus.UNKNOWN


class DoubaoKeyVerifier(KeyVerifier):
    async def verify(self, api_key: str) -> KeyStatus:
        return KeyStatus.UNKNOWN


class YuanbaoKeyVerifier(KeyVerifier):
    async def verify(self, api_key: str) -> KeyStatus:
        return KeyStatus.UNKNOWN


class KeyVerifierFactory:
    _VERIFIERS = {
        "chatgpt": ChatGPTKeyVerifier,
        "perplexity": PerplexityKeyVerifier,
        "kimi": KimiKeyVerifier,
        "wenxin": WenxinKeyVerifier,
        "doubao": DoubaoKeyVerifier,
        "deepseek": DeepSeekKeyVerifier,
        "qwen": QwenKeyVerifier,
        "gemini": GeminiKeyVerifier,
        "yuanbao": YuanbaoKeyVerifier,
    }

    @classmethod
    def get_verifier(cls, engine_type: str) -> KeyVerifier:
        verifier_class = cls._VERIFIERS.get(engine_type)
        if not verifier_class:
            return DefaultKeyVerifier()
        return verifier_class()

    @classmethod
    async def verify(cls, engine_type: str, api_key: str) -> KeyStatus:
        verifier = cls.get_verifier(engine_type)
        return await verifier.verify(api_key)
