"""
用户 API Key 服务

提供用户 API Key 的创建、查询、更新、删除和验证功能。
API Key 使用加密存储，查询时脱敏显示。
"""

import logging
from typing import Optional, List, Dict, Any
from datetime import datetime

from sqlmodel import Session, select, update
from src.config.database import engine
from src.models.entities import UserApiKeyDB
from src.utils.crypto import crypto

logger = logging.getLogger(__name__)


class UserApiKeyService:
    """用户 API Key 服务"""

    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def create_api_key(
        self,
        user_id: str,
        provider: str,
        api_key: str,
        name: Optional[str] = None,
        extra_config: Optional[Dict[str, Any]] = None
    ) -> UserApiKeyDB:
        """
        创建新的 API Key

        Args:
            user_id: 用户ID
            provider: 提供商（如 openai, dashscope）
            api_key: 原始 API Key
            name: 自定义名称
            extra_config: 额外配置

        Returns:
            创建的 API Key 记录
        """
        with Session(engine) as session:
            # 加密 API Key
            encrypted_key = crypto.encrypt(api_key)

            now = datetime.now().timestamp()
            api_key_db = UserApiKeyDB(
                user_id=user_id,
                provider=provider,
                encrypted_key=encrypted_key,
                name=name or f"{provider} Key",
                is_active=True,
                created_at=now,
                updated_at=now,
                last_used_at=None,
                usage_count=0,
                extra_config=extra_config or {}
            )

            session.add(api_key_db)
            session.commit()
            session.refresh(api_key_db)

            logger.info(f"API Key created for user {user_id}, provider {provider}")
            return api_key_db

    def get_user_api_keys(
        self,
        user_id: str,
        include_inactive: bool = False
    ) -> List[Dict[str, Any]]:
        """
        获取用户的所有 API Key（脱敏显示）

        Args:
            user_id: 用户ID
            include_inactive: 是否包含已禁用的 Key

        Returns:
            API Key 列表（脱敏）
        """
        with Session(engine) as session:
            query = select(UserApiKeyDB).where(UserApiKeyDB.user_id == user_id)
            if not include_inactive:
                query = query.where(UserApiKeyDB.is_active == True)

            results = session.exec(query).all()

            # 脱敏显示
            return [self._mask_api_key(key) for key in results]

    def get_api_key_by_id(self, key_id: str, user_id: str) -> Optional[Dict[str, Any]]:
        """
        根据 ID 获取 API Key（脱敏）

        Args:
            key_id: Key ID
            user_id: 用户ID（用于权限验证）

        Returns:
            API Key 信息（脱敏）或 None
        """
        with Session(engine) as session:
            key_db = session.exec(
                select(UserApiKeyDB).where(
                    UserApiKeyDB.id == key_id,
                    UserApiKeyDB.user_id == user_id
                )
            ).first()

            if not key_db:
                return None

            return self._mask_api_key(key_db)

    def get_decrypted_key(self, key_id: str, user_id: str) -> Optional[str]:
        """
        获取解密后的 API Key（用于调用第三方 API）

        Args:
            key_id: Key ID
            user_id: 用户ID（用于权限验证）

        Returns:
            解密后的 API Key 或 None
        """
        with Session(engine) as session:
            key_db = session.exec(
                select(UserApiKeyDB).where(
                    UserApiKeyDB.id == key_id,
                    UserApiKeyDB.user_id == user_id,
                    UserApiKeyDB.is_active == True
                )
            ).first()

            if not key_db:
                return None

            try:
                decrypted = crypto.decrypt(key_db.encrypted_key)
                # 更新使用统计
                key_db.last_used_at = datetime.now().timestamp()
                key_db.usage_count += 1
                session.add(key_db)
                session.commit()
                return decrypted
            except Exception as e:
                logger.error(f"Failed to decrypt API key {key_id}: {e}")
                return None

    def get_user_provider_key(self, user_id: str, provider: str) -> Optional[str]:
        """
        获取用户指定 provider 的活跃 API Key（解密）

        Args:
            user_id: 用户ID
            provider: 提供商

        Returns:
            解密后的 API Key 或 None
        """
        logger.info(f"[get_user_provider_key] Querying for user_id={user_id}, provider={provider}")
        with Session(engine) as session:
            key_db = session.exec(
                select(UserApiKeyDB).where(
                    UserApiKeyDB.user_id == user_id,
                    UserApiKeyDB.provider == provider,
                    UserApiKeyDB.is_active == True
                )
            ).first()

            if not key_db:
                logger.warning(f"[get_user_provider_key] No active API key found for user={user_id}, provider={provider}")
                return None

            logger.info(f"[get_user_provider_key] Found API key id={key_db.id} for provider={provider}")
            try:
                decrypted = crypto.decrypt(key_db.encrypted_key)
                logger.info(f"[get_user_provider_key] Successfully decrypted API key for provider={provider}")
                # 更新使用统计
                key_db.last_used_at = datetime.now().timestamp()
                key_db.usage_count += 1
                session.add(key_db)
                session.commit()
                return decrypted
            except Exception as e:
                logger.error(f"[get_user_provider_key] Failed to decrypt API key for provider {provider}: {e}")
                return None

    def get_user_provider_key_with_config(self, user_id: str, provider: str) -> Optional[Dict[str, Any]]:
        """
        获取用户指定 provider 的活跃 API Key（解密）及额外配置
        用于多 key 提供商（如 Kling、Midjourney）

        Args:
            user_id: 用户ID
            provider: 提供商

        Returns:
            包含 api_key 和 extra_config 的字典，或 None
            格式: {"api_key": "...", "extra_config": {...}}
        """
        with Session(engine) as session:
            key_db = session.exec(
                select(UserApiKeyDB).where(
                    UserApiKeyDB.user_id == user_id,
                    UserApiKeyDB.provider == provider,
                    UserApiKeyDB.is_active == True
                )
            ).first()

            if not key_db:
                return None

            try:
                decrypted = crypto.decrypt(key_db.encrypted_key)
                # 更新使用统计
                key_db.last_used_at = datetime.now().timestamp()
                key_db.usage_count += 1
                session.add(key_db)
                session.commit()
                return {
                    "api_key": decrypted,
                    "extra_config": key_db.extra_config or {}
                }
            except Exception as e:
                logger.error(f"Failed to decrypt API key for provider {provider}: {e}")
                return None

    def update_api_key(
        self,
        key_id: str,
        user_id: str,
        name: Optional[str] = None,
        api_key: Optional[str] = None,
        is_active: Optional[bool] = None,
        extra_config: Optional[Dict[str, Any]] = None
    ) -> Optional[Dict[str, Any]]:
        """
        更新 API Key

        Args:
            key_id: Key ID
            user_id: 用户ID（用于权限验证）
            name: 新名称
            api_key: 新 API Key（如需更新）
            is_active: 是否启用
            extra_config: 额外配置

        Returns:
            更新后的 API Key（脱敏）或 None
        """
        with Session(engine) as session:
            key_db = session.exec(
                select(UserApiKeyDB).where(
                    UserApiKeyDB.id == key_id,
                    UserApiKeyDB.user_id == user_id
                )
            ).first()

            if not key_db:
                return None

            # 更新字段
            if name is not None:
                key_db.name = name
            if api_key is not None:
                key_db.encrypted_key = crypto.encrypt(api_key)
            if is_active is not None:
                key_db.is_active = is_active
            if extra_config is not None:
                key_db.extra_config = extra_config

            key_db.updated_at = datetime.now().timestamp()
            session.add(key_db)
            session.commit()
            session.refresh(key_db)

            logger.info(f"API Key {key_id} updated")
            return self._mask_api_key(key_db)

    def delete_api_key(self, key_id: str, user_id: str) -> bool:
        """
        删除 API Key

        Args:
            key_id: Key ID
            user_id: 用户ID（用于权限验证）

        Returns:
            是否成功删除
        """
        with Session(engine) as session:
            key_db = session.exec(
                select(UserApiKeyDB).where(
                    UserApiKeyDB.id == key_id,
                    UserApiKeyDB.user_id == user_id
                )
            ).first()

            if not key_db:
                return False

            session.delete(key_db)
            session.commit()

            logger.info(f"API Key {key_id} deleted")
            return True

    async def verify_api_key(self, key_id: str, user_id: str) -> Dict[str, Any]:
        """
        验证 API Key 是否有效（调用 provider 测试）

        Args:
            key_id: Key ID
            user_id: 用户ID（用于权限验证）

        Returns:
            验证结果
        """
        with Session(engine) as session:
            key_db = session.exec(
                select(UserApiKeyDB).where(
                    UserApiKeyDB.id == key_id,
                    UserApiKeyDB.user_id == user_id
                )
            ).first()

            if not key_db:
                return {"valid": False, "error": "API Key not found"}

            try:
                decrypted = crypto.decrypt(key_db.encrypted_key)
            except Exception as e:
                return {"valid": False, "error": f"Decryption failed: {e}"}

            # 根据 provider 调用相应的验证接口
            provider = key_db.provider.lower()
            extra_config = key_db.extra_config or {}

            try:
                if provider == "openai":
                    return await self._verify_openai(decrypted)
                elif provider == "dashscope":
                    return await self._verify_dashscope(decrypted)
                elif provider == "minimax":
                    return await self._verify_minimax(decrypted)
                elif provider == "kling":
                    secret_key = extra_config.get("secret_key", "")
                    return await self._verify_kling(decrypted, secret_key)
                elif provider == "midjourney":
                    return await self._verify_midproxy(decrypted, extra_config)
                elif provider == "volcengine":
                    return await self._verify_volcengine(decrypted)
                elif provider == "modelscope":
                    return await self._verify_modelscope(decrypted)
                else:
                    # 未知 provider，仅验证格式
                    return {
                        "valid": True,
                        "provider": provider,
                        "message": f"API Key format is valid (provider: {provider})"
                    }
            except Exception as e:
                logger.error(f"Failed to verify API key for provider {provider}: {e}")
                return {
                    "valid": False,
                    "provider": provider,
                    "error": f"Verification failed: {str(e)}"
                }

    async def _verify_openai(self, api_key: str) -> Dict[str, Any]:
        """验证 OpenAI API Key"""
        import aiohttp

        async with aiohttp.ClientSession() as session:
            async with session.get(
                "https://api.openai.com/v1/models",
                headers={"Authorization": f"Bearer {api_key}"},
                timeout=aiohttp.ClientTimeout(total=10)
            ) as response:
                if response.status == 200:
                    data = await response.json()
                    models = data.get("data", [])
                    return {
                        "valid": True,
                        "provider": "openai",
                        "message": "API Key is valid",
                        "details": {
                            "available_models": len(models)
                        }
                    }
                elif response.status == 401:
                    return {
                        "valid": False,
                        "provider": "openai",
                        "error": "Invalid API Key"
                    }
                else:
                    text = await response.text()
                    return {
                        "valid": False,
                        "provider": "openai",
                        "error": f"Verification failed (HTTP {response.status}): {text}"
                    }

    async def _verify_dashscope(self, api_key: str) -> Dict[str, Any]:
        """验证 DashScope API Key"""
        import aiohttp

        async with aiohttp.ClientSession() as session:
            async with session.get(
                "https://dashscope.aliyuncs.com/api/v1/models",
                headers={"Authorization": f"Bearer {api_key}"},
                timeout=aiohttp.ClientTimeout(total=10)
            ) as response:
                if response.status == 200:
                    return {
                        "valid": True,
                        "provider": "dashscope",
                        "message": "API Key is valid"
                    }
                elif response.status == 401:
                    return {
                        "valid": False,
                        "provider": "dashscope",
                        "error": "Invalid API Key"
                    }
                else:
                    text = await response.text()
                    return {
                        "valid": False,
                        "provider": "dashscope",
                        "error": f"Verification failed (HTTP {response.status})"
                    }

    async def _verify_minimax(self, api_key: str) -> Dict[str, Any]:
        """验证 MiniMax API Key"""
        import aiohttp

        # MiniMax 使用简单的模型列表接口验证
        async with aiohttp.ClientSession() as session:
            async with session.get(
                "https://api.minimax.chat/v1/models",
                headers={"Authorization": f"Bearer {api_key}"},
                timeout=aiohttp.ClientTimeout(total=10)
            ) as response:
                if response.status == 200:
                    return {
                        "valid": True,
                        "provider": "minimax",
                        "message": "API Key is valid"
                    }
                elif response.status in [401, 403]:
                    return {
                        "valid": False,
                        "provider": "minimax",
                        "error": "Invalid API Key"
                    }
                else:
                    # MiniMax 可能返回其他状态码，尝试解析响应
                    try:
                        data = await response.json()
                        if data.get("status_code") == 0 or response.status == 200:
                            return {
                                "valid": True,
                                "provider": "minimax",
                                "message": "API Key is valid"
                            }
                    except:
                        pass
                    return {
                        "valid": False,
                        "provider": "minimax",
                        "error": f"Verification failed (HTTP {response.status})"
                    }

    async def _verify_kling(self, access_key: str, secret_key: str) -> Dict[str, Any]:
        """验证 Kling API Key"""
        import aiohttp
        import hashlib
        import time

        if not secret_key:
            return {
                "valid": False,
                "provider": "kling",
                "error": "Secret Key is required for Kling"
            }

        # Kling 使用 HMAC-SHA256 签名验证
        api_base = "https://api-beijing.klingai.com"
        timestamp = str(int(time.time()))

        # 生成签名
        signature_string = f"{timestamp}{access_key}"
        signature = hashlib.sha256(
            f"{signature_string}{secret_key}".encode()
        ).hexdigest()

        async with aiohttp.ClientSession() as session:
            async with session.get(
                f"{api_base}/v1/account",
                headers={
                    "Authorization": f"Bearer {access_key}",
                    "X-Timestamp": timestamp,
                    "X-Signature": signature
                },
                timeout=aiohttp.ClientTimeout(total=10)
            ) as response:
                if response.status == 200:
                    data = await response.json()
                    if data.get("code") == 0:
                        return {
                            "valid": True,
                            "provider": "kling",
                            "message": "API Key is valid",
                            "details": data.get("data", {})
                        }
                    else:
                        return {
                            "valid": False,
                            "provider": "kling",
                            "error": data.get("message", "Unknown error")
                        }
                elif response.status in [401, 403]:
                    return {
                        "valid": False,
                        "provider": "kling",
                        "error": "Invalid API Key or Secret"
                    }
                else:
                    return {
                        "valid": False,
                        "provider": "kling",
                        "error": f"Verification failed (HTTP {response.status})"
                    }

    async def _verify_midproxy(self, api_key: str, extra_config: Dict[str, Any]) -> Dict[str, Any]:
        """验证 Midjourney Proxy API Key"""
        import aiohttp

        proxy_url = extra_config.get("proxy_url", "")
        if not proxy_url:
            return {
                "valid": False,
                "provider": "midjourney",
                "error": "Proxy URL is required in extra_config"
            }

        async with aiohttp.ClientSession() as session:
            async with session.get(
                f"{proxy_url}/account",
                headers={"Authorization": f"Bearer {api_key}"},
                timeout=aiohttp.ClientTimeout(total=10)
            ) as response:
                if response.status == 200:
                    return {
                        "valid": True,
                        "provider": "midjourney",
                        "message": "API Key is valid"
                    }
                elif response.status == 401:
                    return {
                        "valid": False,
                        "provider": "midjourney",
                        "error": "Invalid API Key"
                    }
                else:
                    return {
                        "valid": False,
                        "provider": "midjourney",
                        "error": f"Verification failed (HTTP {response.status})"
                    }

    async def _verify_volcengine(self, api_key: str) -> Dict[str, Any]:
        """验证 Volcengine (火山方舟) API Key"""
        import aiohttp

        # 火山方舟使用模型列表接口验证
        async with aiohttp.ClientSession() as session:
            async with session.get(
                "https://ark.cn-beijing.volces.com/api/v3/models",
                headers={"Authorization": f"Bearer {api_key}"},
                timeout=aiohttp.ClientTimeout(total=10)
            ) as response:
                if response.status == 200:
                    data = await response.json()
                    models = data.get("data", [])
                    return {
                        "valid": True,
                        "provider": "volcengine",
                        "message": "API Key is valid",
                        "details": {
                            "available_models": len(models)
                        }
                    }
                elif response.status == 401:
                    return {
                        "valid": False,
                        "provider": "volcengine",
                        "error": "Invalid API Key"
                    }
                else:
                    return {
                        "valid": False,
                        "provider": "volcengine",
                        "error": f"Verification failed (HTTP {response.status})"
                    }

    async def _verify_modelscope(self, api_token: str) -> Dict[str, Any]:
        """验证 ModelScope API Token"""
        import aiohttp

        async with aiohttp.ClientSession() as session:
            async with session.get(
                "https://modelscope.cn/api/v1/user",
                headers={"Authorization": f"Bearer {api_token}"},
                timeout=aiohttp.ClientTimeout(total=10)
            ) as response:
                if response.status == 200:
                    data = await response.json()
                    if data.get("Data"):
                        return {
                            "valid": True,
                            "provider": "modelscope",
                            "message": "API Token is valid",
                            "details": {
                                "username": data.get("Data", {}).get("UserName", "")
                            }
                        }
                    else:
                        return {
                            "valid": False,
                            "provider": "modelscope",
                            "error": "Invalid API Token"
                        }
                elif response.status == 401:
                    return {
                        "valid": False,
                        "provider": "modelscope",
                        "error": "Invalid API Token"
                    }
                else:
                    return {
                        "valid": False,
                        "provider": "modelscope",
                        "error": f"Verification failed (HTTP {response.status})"
                    }

    def _mask_api_key(self, key_db: UserApiKeyDB) -> Dict[str, Any]:
        """
        将 API Key 脱敏显示

        Args:
            key_db: API Key 数据库记录

        Returns:
            脱敏后的 API Key 信息
        """
        # 解密后脱敏显示
        try:
            decrypted = crypto.decrypt(key_db.encrypted_key)
            masked_key = crypto.mask_key(decrypted)
        except Exception:
            masked_key = "***invalid***"

        # 脱敏 extra_config 中的敏感字段
        masked_extra_config = None
        if key_db.extra_config:
            masked_extra_config = {}
            for field_name, value in key_db.extra_config.items():
                if value and self._is_sensitive_field(field_name):
                    masked_extra_config[field_name] = crypto.mask_key(str(value))
                else:
                    masked_extra_config[field_name] = value

        return {
            "id": key_db.id,
            "user_id": key_db.user_id,
            "provider": key_db.provider,
            "name": key_db.name,
            "masked_key": masked_key,
            "is_active": key_db.is_active,
            "created_at": key_db.created_at,
            "updated_at": key_db.updated_at,
            "last_used_at": key_db.last_used_at,
            "usage_count": key_db.usage_count,
            "extra_config": masked_extra_config
        }

    def _is_sensitive_field(self, field_name: str) -> bool:
        """
        判断字段是否为敏感字段（需要脱敏）

        Args:
            field_name: 字段名称

        Returns:
            是否为敏感字段
        """
        sensitive_keywords = ['secret', 'key', 'token', 'password', 'api_key', 'apikey', 'access_key', 'secret_key']
        field_lower = field_name.lower()
        return any(keyword in field_lower for keyword in sensitive_keywords)

    def get_decrypted_key_by_id(self, key_id: str, user_id: str) -> Optional[Dict[str, Any]]:
        """
        获取解密后的完整 API Key 信息（用于用户查看自己的 Key）

        Args:
            key_id: Key ID
            user_id: 用户ID（用于权限验证）

        Returns:
            包含完整 API Key 的字典，或 None（未找到或无权限）
            格式: {
                "id": str,
                "provider": str,
                "name": str,
                "api_key": str,  # 完整的 API Key
                "extra_config": Dict[str, str],  # 完整的额外配置
                "is_active": bool
            }
        """
        with Session(engine) as session:
            key_db = session.exec(
                select(UserApiKeyDB).where(
                    UserApiKeyDB.id == key_id,
                    UserApiKeyDB.user_id == user_id
                )
            ).first()

            if not key_db:
                return None

            try:
                decrypted_key = crypto.decrypt(key_db.encrypted_key)

                # 解密 extra_config 中的敏感字段
                decrypted_extra_config = None
                if key_db.extra_config:
                    decrypted_extra_config = {}
                    for field_name, value in key_db.extra_config.items():
                        # extra_config 中的值可能是加密的，尝试解密
                        if value and isinstance(value, str):
                            try:
                                decrypted_extra_config[field_name] = crypto.decrypt(value)
                            except Exception:
                                # 解密失败，使用原值
                                decrypted_extra_config[field_name] = value
                        else:
                            decrypted_extra_config[field_name] = value

                return {
                    "id": key_db.id,
                    "provider": key_db.provider,
                    "name": key_db.name,
                    "api_key": decrypted_key,
                    "extra_config": decrypted_extra_config,
                    "is_active": key_db.is_active
                }
            except Exception as e:
                logger.error(f"Failed to decrypt API key {key_id}: {e}")
                return None

    def is_user_superuser(self, user_id: str) -> bool:
        """
        检查用户是否为超级用户（管理员）

        Args:
            user_id: 用户ID

        Returns:
            是否为超级用户
        """
        from src.models.entities import UserDB
        with Session(engine) as session:
            user = session.exec(
                select(UserDB).where(UserDB.id == user_id)
            ).first()
            if user:
                return user.is_superuser
            return False


# 全局服务实例
user_api_key_service = UserApiKeyService()
