"""
租户配置加载器

功能：
1. 从数据库 tenant_configs 表加载租户配置
2. 支持 Redis 缓存
3. 数据库不可用时回退到环境变量
4. 支持配置热更新
"""

import os
import json
import logging
from typing import Optional, Dict, Any
from functools import lru_cache

import aiomysql
import redis.asyncio as redis

logger = logging.getLogger(__name__)


# ============================================
# 平台管理库连接配置
# 
# 注意：敏感信息必须通过环境变量传递，禁止硬编码
# 参考：瑞小美系统技术栈标准与字符标准.md - 敏感信息管理
# ============================================
ADMIN_DB_CONFIG = {
    "host": os.getenv("ADMIN_DB_HOST", "prod-mysql"),
    "port": int(os.getenv("ADMIN_DB_PORT", "3306")),
    "user": os.getenv("ADMIN_DB_USER", "root"),
    "password": os.getenv("ADMIN_DB_PASSWORD"),  # 必须从环境变量获取
    "db": os.getenv("ADMIN_DB_NAME", "kaopeilian_admin"),
    "charset": "utf8mb4",
}

# 校验必填环境变量
if not ADMIN_DB_CONFIG["password"]:
    logger.warning(
        "ADMIN_DB_PASSWORD 环境变量未设置，租户配置加载功能将不可用。"
        "请在 .env.admin 文件中配置此变量。"
    )

# Redis 缓存配置
CACHE_PREFIX = "tenant_config:"
CACHE_TTL = 300  # 5分钟缓存


class TenantConfigLoader:
    """租户配置加载器"""
    
    def __init__(self, tenant_code: str, redis_client: Optional[redis.Redis] = None):
        """
        初始化租户配置加载器
        
        Args:
            tenant_code: 租户编码（如 hua, yy, hl）
            redis_client: Redis 客户端（可选）
        """
        self.tenant_code = tenant_code
        self.redis_client = redis_client
        self._config_cache: Dict[str, Any] = {}
        self._tenant_id: Optional[int] = None
    
    async def get_config(self, config_group: str, config_key: str, default: Any = None) -> Any:
        """
        获取配置项
        
        优先级：
        1. 内存缓存
        2. Redis 缓存
        3. 数据库
        4. 环境变量
        5. 默认值
        
        Args:
            config_group: 配置分组（database, redis, coze, ai, yanji, security）
            config_key: 配置键
            default: 默认值
        
        Returns:
            配置值
        """
        cache_key = f"{config_group}.{config_key}"
        
        # 1. 内存缓存
        if cache_key in self._config_cache:
            return self._config_cache[cache_key]
        
        # 2. Redis 缓存
        if self.redis_client:
            try:
                redis_key = f"{CACHE_PREFIX}{self.tenant_code}:{cache_key}"
                cached_value = await self.redis_client.get(redis_key)
                if cached_value:
                    value = json.loads(cached_value)
                    self._config_cache[cache_key] = value
                    return value
            except Exception as e:
                logger.warning(f"Redis 缓存读取失败: {e}")
        
        # 3. 数据库
        try:
            value = await self._get_from_database(config_group, config_key)
            if value is not None:
                self._config_cache[cache_key] = value
                # 写入 Redis 缓存
                if self.redis_client:
                    try:
                        redis_key = f"{CACHE_PREFIX}{self.tenant_code}:{cache_key}"
                        await self.redis_client.setex(
                            redis_key, 
                            CACHE_TTL, 
                            json.dumps(value)
                        )
                    except Exception as e:
                        logger.warning(f"Redis 缓存写入失败: {e}")
                return value
        except Exception as e:
            logger.warning(f"数据库配置读取失败: {e}")
        
        # 4. 环境变量
        env_value = os.getenv(config_key)
        if env_value is not None:
            return env_value
        
        # 5. 默认值
        return default
    
    async def _get_from_database(self, config_group: str, config_key: str) -> Optional[Any]:
        """从数据库获取配置"""
        conn = None
        try:
            conn = await aiomysql.connect(**ADMIN_DB_CONFIG)
            async with conn.cursor(aiomysql.DictCursor) as cursor:
                # 获取租户 ID
                if self._tenant_id is None:
                    await cursor.execute(
                        "SELECT id FROM tenants WHERE code = %s AND status = 'active'",
                        (self.tenant_code,)
                    )
                    row = await cursor.fetchone()
                    if row:
                        self._tenant_id = row['id']
                    else:
                        return None
                
                # 获取配置值
                await cursor.execute(
                    """
                    SELECT config_value, value_type, is_encrypted 
                    FROM tenant_configs 
                    WHERE tenant_id = %s AND config_group = %s AND config_key = %s
                    """,
                    (self._tenant_id, config_group, config_key)
                )
                row = await cursor.fetchone()
                
                if row:
                    return self._parse_value(row['config_value'], row['value_type'], row['is_encrypted'])
                
                # 如果租户没有配置，获取默认值
                await cursor.execute(
                    """
                    SELECT default_value, value_type 
                    FROM config_templates 
                    WHERE config_group = %s AND config_key = %s
                    """,
                    (config_group, config_key)
                )
                row = await cursor.fetchone()
                if row and row['default_value']:
                    return self._parse_value(row['default_value'], row['value_type'], False)
                
                return None
        finally:
            if conn:
                conn.close()
    
    def _parse_value(self, value: str, value_type: str, is_encrypted: bool) -> Any:
        """解析配置值"""
        if value is None:
            return None
        
        # TODO: 如果是加密值，先解密
        if is_encrypted:
            # 这里可以实现解密逻辑
            pass
        
        if value_type == 'int':
            return int(value)
        elif value_type == 'bool':
            return value.lower() in ('true', '1', 'yes')
        elif value_type == 'json':
            return json.loads(value)
        elif value_type == 'float':
            return float(value)
        else:
            return value
    
    async def get_all_configs(self) -> Dict[str, Any]:
        """获取租户的所有配置"""
        configs = {}
        conn = None
        try:
            conn = await aiomysql.connect(**ADMIN_DB_CONFIG)
            async with conn.cursor(aiomysql.DictCursor) as cursor:
                # 获取租户 ID
                await cursor.execute(
                    "SELECT id FROM tenants WHERE code = %s AND status = 'active'",
                    (self.tenant_code,)
                )
                row = await cursor.fetchone()
                if not row:
                    return configs
                
                tenant_id = row['id']
                
                # 获取所有配置
                await cursor.execute(
                    """
                    SELECT config_group, config_key, config_value, value_type, is_encrypted
                    FROM tenant_configs
                    WHERE tenant_id = %s
                    """,
                    (tenant_id,)
                )
                rows = await cursor.fetchall()
                
                for row in rows:
                    key = f"{row['config_group']}.{row['config_key']}"
                    configs[key] = self._parse_value(
                        row['config_value'], 
                        row['value_type'], 
                        row['is_encrypted']
                    )
                
                return configs
        finally:
            if conn:
                conn.close()
    
    async def refresh_cache(self):
        """刷新缓存"""
        self._config_cache.clear()
        
        if self.redis_client:
            try:
                # 删除该租户的所有缓存
                pattern = f"{CACHE_PREFIX}{self.tenant_code}:*"
                cursor = 0
                while True:
                    cursor, keys = await self.redis_client.scan(cursor, match=pattern, count=100)
                    if keys:
                        await self.redis_client.delete(*keys)
                    if cursor == 0:
                        break
            except Exception as e:
                logger.warning(f"Redis 缓存刷新失败: {e}")
    
    async def is_feature_enabled(self, feature_code: str) -> bool:
        """
        检查功能是否启用
        
        Args:
            feature_code: 功能编码
        
        Returns:
            是否启用
        """
        conn = None
        try:
            conn = await aiomysql.connect(**ADMIN_DB_CONFIG)
            async with conn.cursor(aiomysql.DictCursor) as cursor:
                # 获取租户 ID
                if self._tenant_id is None:
                    await cursor.execute(
                        "SELECT id FROM tenants WHERE code = %s AND status = 'active'",
                        (self.tenant_code,)
                    )
                    row = await cursor.fetchone()
                    if row:
                        self._tenant_id = row['id']
                
                # 先查租户级别的配置
                if self._tenant_id:
                    await cursor.execute(
                        """
                        SELECT is_enabled FROM feature_switches 
                        WHERE tenant_id = %s AND feature_code = %s
                        """,
                        (self._tenant_id, feature_code)
                    )
                    row = await cursor.fetchone()
                    if row:
                        return bool(row['is_enabled'])
                
                # 再查全局默认配置
                await cursor.execute(
                    """
                    SELECT is_enabled FROM feature_switches 
                    WHERE tenant_id IS NULL AND feature_code = %s
                    """,
                    (feature_code,)
                )
                row = await cursor.fetchone()
                if row:
                    return bool(row['is_enabled'])
                
                return True  # 默认启用
        except Exception as e:
            logger.warning(f"功能开关查询失败: {e}, 默认启用")
            return True
        finally:
            if conn:
                conn.close()


class TenantConfigManager:
    """租户配置管理器（单例）"""
    
    _instances: Dict[str, TenantConfigLoader] = {}
    _redis_client: Optional[redis.Redis] = None
    
    @classmethod
    async def init_redis(cls, redis_url: str):
        """初始化 Redis 连接"""
        try:
            cls._redis_client = redis.from_url(redis_url)
            await cls._redis_client.ping()
            logger.info("TenantConfigManager Redis 连接成功")
        except Exception as e:
            logger.warning(f"TenantConfigManager Redis 连接失败: {e}")
            cls._redis_client = None
    
    @classmethod
    def get_loader(cls, tenant_code: str) -> TenantConfigLoader:
        """获取租户配置加载器"""
        if tenant_code not in cls._instances:
            cls._instances[tenant_code] = TenantConfigLoader(
                tenant_code, 
                cls._redis_client
            )
        return cls._instances[tenant_code]
    
    @classmethod
    async def refresh_tenant_cache(cls, tenant_code: str):
        """刷新指定租户的缓存"""
        if tenant_code in cls._instances:
            await cls._instances[tenant_code].refresh_cache()
    
    @classmethod
    async def refresh_all_cache(cls):
        """刷新所有租户的缓存"""
        for loader in cls._instances.values():
            await loader.refresh_cache()


# ============================================
# 辅助函数
# ============================================

def get_tenant_code_from_domain(domain: str) -> str:
    """
    从域名提取租户编码
    
    Examples:
        hua.ireborn.com.cn -> hua
        yy.ireborn.com.cn -> yy
        aiedu.ireborn.com.cn -> demo
    """
    if not domain:
        return "demo"
    
    # 移除 https:// 或 http://
    domain = domain.replace("https://", "").replace("http://", "")
    
    # 获取子域名
    parts = domain.split(".")
    if len(parts) >= 3:
        subdomain = parts[0]
        # 特殊处理
        if subdomain == "aiedu":
            return "demo"
        return subdomain
    
    return "demo"


async def get_tenant_config(tenant_code: str, config_group: str, config_key: str, default: Any = None) -> Any:
    """
    快捷函数：获取租户配置
    
    Args:
        tenant_code: 租户编码
        config_group: 配置分组
        config_key: 配置键
        default: 默认值
    
    Returns:
        配置值
    """
    loader = TenantConfigManager.get_loader(tenant_code)
    return await loader.get_config(config_group, config_key, default)


async def is_tenant_feature_enabled(tenant_code: str, feature_code: str) -> bool:
    """
    快捷函数：检查租户功能是否启用
    
    Args:
        tenant_code: 租户编码
        feature_code: 功能编码
    
    Returns:
        是否启用
    """
    loader = TenantConfigManager.get_loader(tenant_code)
    return await loader.is_feature_enabled(feature_code)

