#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
数据库信息收集器（异步版本）
"""
import logging
import time
from datetime import datetime, timedelta, timezone
from typing import Dict, List, Any, Optional

import asyncpg

from core.database_manager.service import aiomysql_connect, log_database_connect_failure
from core.database_manager.handlers.pools import build_mssql_dsn, build_oracle_dsn

logger = logging.getLogger(__name__)

# MySQL异步驱动
try:
    import aiomysql
    AIOMYSQL_AVAILABLE = True
except ImportError:
    AIOMYSQL_AVAILABLE = False

try:
    import aioodbc
    AIOODBC_AVAILABLE = True
except ImportError:
    AIOODBC_AVAILABLE = False

try:
    import oracledb
    ORACLEDB_AVAILABLE = True
except ImportError:
    ORACLEDB_AVAILABLE = False


def _normalize_db_type(db_type: str) -> str:
    upper = (db_type or "").upper()
    if upper in ("MSSQL", "SQL SERVER"):
        return "SQLSERVER"
    return upper


def serialize_data(data: Any) -> Any:
    """递归地序列化数据，处理datetime、decimal等类型"""
    import decimal

    if isinstance(data, (datetime,)):
        return data.isoformat()
    elif isinstance(data, decimal.Decimal):
        return float(data)
    elif isinstance(data, (bytes,)):
        try:
            return data.decode('utf-8')
        except UnicodeDecodeError:
            return str(data)
    elif isinstance(data, dict):
        return {serialize_data(k): serialize_data(v) for k, v in data.items()}
    elif isinstance(data, list):
        return [serialize_data(item) for item in data]
    elif isinstance(data, tuple):
        return tuple(serialize_data(item) for item in data)
    else:
        return data


class AsyncDatabaseCollector:
    """异步数据库信息收集器"""

    def __init__(self, db_type: str, host: str, port: int,
                 user: str, password: str, database: str, **kwargs):
        self.db_type = _normalize_db_type(db_type)
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        self.database = database
        self.kwargs = kwargs
        self.connection = None
        self._last_connect_error: Optional[str] = None

    async def connect(self) -> bool:
        """连接数据库"""
        try:
            if self.db_type == 'POSTGRESQL':
                result = await self._connect_postgresql()
            elif self.db_type == 'MYSQL':
                result = await self._connect_mysql()
            elif self.db_type == 'SQLSERVER':
                result = await self._connect_sqlserver()
            elif self.db_type == 'ORACLE':
                result = await self._connect_oracle()
            else:
                self._last_connect_error = f"Unsupported database type: {self.db_type}"
                logger.error(self._last_connect_error)
                return False
            if result:
                self._last_connect_error = None
            return result
        except Exception as e:
            self._last_connect_error = str(e).strip() or e.__class__.__name__
            log_database_connect_failure(
                db_type=self.db_type.lower(),
                host=self.host,
                port=self.port,
                user=self.user,
                database=self.database,
                detail=self._last_connect_error,
            )
            return False

    async def _connect_postgresql(self) -> bool:
        """连接PostgreSQL"""
        self.connection = await asyncpg.connect(
            host=self.host,
            port=self.port,
            user=self.user,
            password=self.password,
            database=self.database,
            timeout=5
        )
        return True

    async def _connect_mysql(self) -> bool:
        """连接MySQL"""
        if not AIOMYSQL_AVAILABLE:
            self._last_connect_error = "aiomysql 未安装，无法连接 MySQL"
            logger.error(self._last_connect_error)
            return False

        self.connection = await aiomysql_connect(
            host=self.host,
            port=self.port,
            user=self.user,
            password=self.password,
            db=self.database,
            charset='utf8mb4',
            connect_timeout=5,
        )
        return True

    async def _connect_sqlserver(self) -> bool:
        """连接 SQL Server"""
        if not AIOODBC_AVAILABLE:
            self._last_connect_error = "aioodbc 未安装，无法连接 SQL Server"
            logger.error(self._last_connect_error)
            return False

        dsn = build_mssql_dsn(
            self.host,
            self.port,
            self.user,
            self.password,
            self.database or "master",
            self.kwargs.get("extra_options"),
        )
        self.connection = await aioodbc.connect(dsn=dsn, autocommit=True, timeout=5)
        return True

    async def _connect_oracle(self) -> bool:
        """连接 Oracle"""
        if not ORACLEDB_AVAILABLE:
            self._last_connect_error = "oracledb 未安装，无法连接 Oracle"
            logger.error(self._last_connect_error)
            return False

        service = self.database or self.kwargs.get("service_name") or "ORCL"
        dsn = build_oracle_dsn(self.host, self.port, service)
        self.connection = await oracledb.connect_async(
            user=self.user,
            password=self.password,
            dsn=dsn,
        )
        return True

    async def _execute_odbc_query(
        self, query: str, params: tuple = ()
    ) -> List[Dict[str, Any]]:
        async with self.connection.cursor() as cursor:
            await cursor.execute(query, params)
            if not cursor.description:
                return []
            columns = [col[0] for col in cursor.description]
            rows = await cursor.fetchall()
            return [dict(zip(columns, row)) for row in rows]

    async def _fetch_odbc_value(self, query: str, params: tuple = ()) -> Any:
        rows = await self._execute_odbc_query(query, params)
        if not rows:
            return None
        return next(iter(rows[0].values()))

    async def _execute_oracle_query(
        self, query: str, params: Optional[Dict[str, Any]] = None
    ) -> List[Dict[str, Any]]:
        cursor = self.connection.cursor()
        try:
            await cursor.execute(query, params or {})
            if not cursor.description:
                return []
            columns = [col[0].lower() for col in cursor.description]
            rows = await cursor.fetchall()
            return [dict(zip(columns, row)) for row in rows]
        finally:
            await cursor.close()

    async def _fetch_oracle_value(
        self, query: str, params: Optional[Dict[str, Any]] = None
    ) -> Any:
        rows = await self._execute_oracle_query(query, params)
        if not rows:
            return None
        return next(iter(rows[0].values()))

    async def disconnect(self):
        """断开连接"""
        if self.connection:
            try:
                await self.connection.close()
            except Exception as e:
                logger.error(f"Error disconnecting from database: {e}")
            finally:
                self.connection = None

    async def test_connection(self) -> Dict[str, Any]:
        """测试数据库连接"""
        start_time = time.time()
        try:
            if await self.connect():
                response_time = (time.time() - start_time) * 1000
                version = await self._get_version()
                return {
                    'success': True,
                    'message': '连接成功',
                    'response_time': round(response_time, 2),
                    'version': version,
                    'db_type': self.db_type
                }
            else:
                target = f"{self.host}:{self.port}, db={self.database}"
                detail = self._last_connect_error or "未知错误"
                message = f'连接失败 ({target}): {detail}'
                log_database_connect_failure(
                    db_type=self.db_type.lower(),
                    host=self.host,
                    port=self.port,
                    user=self.user,
                    database=self.database,
                    detail=detail,
                    action="monitor_test",
                )
                return {
                    'success': False,
                    'message': message,
                    'response_time': None,
                    'version': None,
                    'db_type': self.db_type
                }
        except Exception as e:
            return {
                'success': False,
                'message': f'连接错误: {str(e)}',
                'response_time': None,
                'version': None,
                'db_type': self.db_type
            }
        finally:
            await self.disconnect()

    async def _get_version(self) -> str:
        """获取数据库版本"""
        try:
            if self.db_type == 'POSTGRESQL':
                result = await self.connection.fetchval("SELECT version()")
                return result
            elif self.db_type == 'MYSQL':
                async with self.connection.cursor() as cursor:
                    await cursor.execute("SELECT VERSION()")
                    result = await cursor.fetchone()
                    return result[0]
            elif self.db_type == 'SQLSERVER':
                return await self._fetch_odbc_value("SELECT @@VERSION")
            elif self.db_type == 'ORACLE':
                return await self._fetch_oracle_value(
                    "SELECT banner FROM v$version WHERE ROWNUM = 1"
                )
            return 'Unknown'
        except Exception as e:
            logger.error(f"Error getting database version: {e}")
            return 'Unknown'

    async def get_basic_info(self) -> Dict[str, Any]:
        """获取数据库基本信息"""
        if not self.connection:
            if not await self.connect():
                return {}

        try:
            info = {
                'db_type': self.db_type,
                'host': self.host,
                'port': self.port,
                'database': self.database,
                'version': await self._get_version(),
                'uptime': await self._get_uptime(),
                'timezone': await self._get_timezone(),
                'charset': await self._get_charset(),
            }
            return serialize_data(info)
        except Exception as e:
            logger.error(f"Error getting basic info: {e}")
            return {}

    async def _get_uptime(self) -> str:
        """获取数据库运行时间"""
        try:
            if self.db_type == 'POSTGRESQL':
                start_time = await self.connection.fetchval("SELECT pg_postmaster_start_time()")
                current_time = datetime.now(timezone.utc)
                if start_time.tzinfo is None:
                    start_time = start_time.replace(tzinfo=timezone.utc)
                uptime = current_time - start_time
                return str(uptime)
            elif self.db_type == 'MYSQL':
                async with self.connection.cursor() as cursor:
                    await cursor.execute("SHOW GLOBAL STATUS LIKE 'Uptime'")
                    result = await cursor.fetchone()
                    if result:
                        uptime_seconds = int(result[1])
                        uptime = timedelta(seconds=uptime_seconds)
                        return str(uptime)
            elif self.db_type == 'SQLSERVER':
                start_time = await self._fetch_odbc_value(
                    "SELECT sqlserver_start_time FROM sys.dm_os_sys_info"
                )
                if start_time:
                    current_time = datetime.now(timezone.utc)
                    if getattr(start_time, "tzinfo", None) is None:
                        start_time = start_time.replace(tzinfo=timezone.utc)
                    return str(current_time - start_time)
            elif self.db_type == 'ORACLE':
                start_time = await self._fetch_oracle_value(
                    "SELECT startup_time FROM v$instance"
                )
                if start_time:
                    current_time = datetime.now(timezone.utc)
                    if getattr(start_time, "tzinfo", None) is None:
                        start_time = start_time.replace(tzinfo=timezone.utc)
                    return str(current_time - start_time)
            return 'Unknown'
        except Exception as e:
            logger.error(f"Error getting uptime: {e}")
            return 'Unknown'

    async def _get_timezone(self) -> str:
        """获取数据库时区"""
        try:
            if self.db_type == 'POSTGRESQL':
                result = await self.connection.fetchval("SHOW timezone")
                return result
            elif self.db_type == 'MYSQL':
                async with self.connection.cursor() as cursor:
                    await cursor.execute("SELECT @@global.time_zone")
                    result = await cursor.fetchone()
                    return result[0]
            elif self.db_type == 'SQLSERVER':
                return await self._fetch_odbc_value(
                    "SELECT CAST(SYSDATETIMEOFFSET() AS NVARCHAR(50))"
                ) or "Unknown"
            elif self.db_type == 'ORACLE':
                return await self._fetch_oracle_value(
                    "SELECT DBTIMEZONE FROM dual"
                ) or "Unknown"
            return 'Unknown'
        except Exception as e:
            logger.error(f"Error getting timezone: {e}")
            return 'Unknown'

    async def _get_charset(self) -> str:
        """获取数据库字符集"""
        try:
            if self.db_type == 'POSTGRESQL':
                result = await self.connection.fetchval(
                    "SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = $1",
                    self.database
                )
                return result
            elif self.db_type == 'MYSQL':
                async with self.connection.cursor() as cursor:
                    await cursor.execute("SELECT @@character_set_database")
                    result = await cursor.fetchone()
                    return result[0]
            elif self.db_type == 'SQLSERVER':
                return await self._fetch_odbc_value(
                    "SELECT DATABASEPROPERTYEX(DB_NAME(), 'Collation')"
                ) or "Unknown"
            elif self.db_type == 'ORACLE':
                return await self._fetch_oracle_value(
                    """
                    SELECT value
                    FROM nls_database_parameters
                    WHERE parameter = 'NLS_CHARACTERSET'
                    """
                ) or "Unknown"
            return 'Unknown'
        except Exception as e:
            logger.error(f"Error getting charset: {e}")
            return 'Unknown'

    async def get_connection_info(self) -> Dict[str, Any]:
        """获取连接信息"""
        if not self.connection:
            if not await self.connect():
                return {}

        try:
            if self.db_type == 'POSTGRESQL':
                return await self._get_postgresql_connections()
            elif self.db_type == 'MYSQL':
                return await self._get_mysql_connections()
            elif self.db_type == 'SQLSERVER':
                return await self._get_sqlserver_connections()
            elif self.db_type == 'ORACLE':
                return await self._get_oracle_connections()
            return {}
        except Exception as e:
            logger.error(f"Error getting connection info: {e}")
            return {}

    async def _get_postgresql_connections(self) -> Dict[str, Any]:
        """获取PostgreSQL连接信息"""
        total_connections = await self.connection.fetchval(
            "SELECT COUNT(*) FROM pg_stat_activity"
        )
        
        max_connections = await self.connection.fetchval("SHOW max_connections")
        max_connections = int(max_connections)
        
        active_connections = await self.connection.fetchval(
            "SELECT COUNT(*) FROM pg_stat_activity WHERE state = 'active'"
        )
        
        idle_connections = await self.connection.fetchval(
            "SELECT COUNT(*) FROM pg_stat_activity WHERE state = 'idle'"
        )

        return {
            'total_connections': total_connections,
            'max_connections': max_connections,
            'active_connections': active_connections,
            'idle_connections': idle_connections,
            'connection_usage_percent': round((total_connections / max_connections) * 100, 2) if max_connections > 0 else 0.0
        }

    async def _get_mysql_connections(self) -> Dict[str, Any]:
        """获取MySQL连接信息"""
        async with self.connection.cursor() as cursor:
            await cursor.execute("SHOW STATUS LIKE 'Threads_connected'")
            result = await cursor.fetchone()
            total_connections = int(result[1])

            await cursor.execute("SHOW VARIABLES LIKE 'max_connections'")
            result = await cursor.fetchone()
            max_connections = int(result[1])

            await cursor.execute("SHOW STATUS LIKE 'Threads_running'")
            result = await cursor.fetchone()
            active_connections = int(result[1])

        idle_connections = total_connections - active_connections

        return {
            'total_connections': total_connections,
            'max_connections': max_connections,
            'active_connections': active_connections,
            'idle_connections': idle_connections,
            'connection_usage_percent': round((total_connections / max_connections) * 100, 2) if max_connections > 0 else 0.0
        }

    async def get_database_size(self) -> Dict[str, Any]:
        """获取数据库大小信息"""
        if not self.connection:
            if not await self.connect():
                return {}

        try:
            if self.db_type == 'POSTGRESQL':
                return await self._get_postgresql_size()
            elif self.db_type == 'MYSQL':
                return await self._get_mysql_size()
            elif self.db_type == 'SQLSERVER':
                return await self._get_sqlserver_size()
            elif self.db_type == 'ORACLE':
                return await self._get_oracle_size()
            return {}
        except Exception as e:
            logger.error(f"Error getting database size: {e}")
            return {}

    async def _get_postgresql_size(self) -> Dict[str, Any]:
        """获取PostgreSQL数据库大小"""
        size_bytes = await self.connection.fetchval(
            "SELECT pg_database_size($1)", self.database
        )

        return {
            'database_size_bytes': size_bytes,
            'database_size_mb': round(size_bytes / 1024 / 1024, 2),
            'database_size_gb': round(size_bytes / 1024 / 1024 / 1024, 2)
        }

    async def _get_mysql_size(self) -> Dict[str, Any]:
        """获取MySQL数据库大小"""
        async with self.connection.cursor() as cursor:
            await cursor.execute("""
                SELECT SUM(data_length + index_length) AS size_bytes
                FROM information_schema.tables
                WHERE table_schema = %s
            """, (self.database,))
            result = await cursor.fetchone()
            size_bytes = result[0] if result[0] else 0

        return {
            'database_size_bytes': size_bytes,
            'database_size_mb': round(size_bytes / 1024 / 1024, 2),
            'database_size_gb': round(size_bytes / 1024 / 1024 / 1024, 2)
        }

    async def get_performance_stats(self) -> Dict[str, Any]:
        """获取性能统计信息"""
        if not self.connection:
            if not await self.connect():
                return {'cache_hit_ratio': 0.0}

        try:
            if self.db_type == 'POSTGRESQL':
                return await self._get_postgresql_performance()
            elif self.db_type == 'MYSQL':
                return await self._get_mysql_performance()
            elif self.db_type == 'SQLSERVER':
                return await self._get_sqlserver_performance()
            elif self.db_type == 'ORACLE':
                return await self._get_oracle_performance()
            return {'cache_hit_ratio': 0.0}
        except Exception as e:
            logger.error(f"Error getting performance stats: {e}")
            return {'cache_hit_ratio': 0.0}

    async def _get_postgresql_performance(self) -> Dict[str, Any]:
        """获取PostgreSQL性能统计"""
        stats = await self.connection.fetchrow("""
            SELECT SUM(numbackends) AS total_backends,
                   SUM(xact_commit) AS transactions_commit,
                   SUM(xact_rollback) AS transactions_rollback,
                   SUM(blks_read) AS blocks_read,
                   SUM(blks_hit) AS blocks_hit,
                   SUM(tup_returned) AS tuples_returned,
                   SUM(tup_fetched) AS tuples_fetched,
                   SUM(tup_inserted) AS tuples_inserted,
                   SUM(tup_updated) AS tuples_updated,
                   SUM(tup_deleted) AS tuples_deleted,
                   SUM(temp_files) AS temp_files,
                   SUM(temp_bytes) AS temp_bytes,
                   SUM(deadlocks) AS deadlocks
            FROM pg_stat_database
            WHERE datname = $1
        """, self.database)

        blocks_read = stats['blocks_read'] or 0
        blocks_hit = stats['blocks_hit'] or 0
        total_reads = blocks_read + blocks_hit
        cache_hit_ratio = (blocks_hit / total_reads * 100) if total_reads > 0 else 0

        return {
            'total_backends': stats['total_backends'] or 0,
            'transactions_commit': stats['transactions_commit'] or 0,
            'transactions_rollback': stats['transactions_rollback'] or 0,
            'blocks_read': blocks_read,
            'blocks_hit': blocks_hit,
            'cache_hit_ratio': round(cache_hit_ratio, 2),
            'tuples_returned': stats['tuples_returned'] or 0,
            'tuples_fetched': stats['tuples_fetched'] or 0,
            'tuples_inserted': stats['tuples_inserted'] or 0,
            'tuples_updated': stats['tuples_updated'] or 0,
            'tuples_deleted': stats['tuples_deleted'] or 0,
            'temp_files': stats['temp_files'] or 0,
            'temp_bytes': stats['temp_bytes'] or 0,
            'deadlocks': stats['deadlocks'] or 0,
        }

    async def _get_mysql_performance(self) -> Dict[str, Any]:
        """获取MySQL性能统计"""
        stats = {}
        status_queries = [
            ('queries', 'Queries'),
            ('connections', 'Connections'),
            ('slow_queries', 'Slow_queries'),
            ('bytes_received', 'Bytes_received'),
            ('bytes_sent', 'Bytes_sent'),
            ('innodb_buffer_pool_reads', 'Innodb_buffer_pool_reads'),
            ('innodb_buffer_pool_read_requests', 'Innodb_buffer_pool_read_requests')
        ]

        async with self.connection.cursor() as cursor:
            for stat_name, mysql_var in status_queries:
                await cursor.execute(f"SHOW GLOBAL STATUS LIKE '{mysql_var}'")
                result = await cursor.fetchone()
                stats[stat_name] = int(result[1]) if result else 0

        read_requests = stats['innodb_buffer_pool_read_requests']
        reads = stats['innodb_buffer_pool_reads']
        cache_hit_ratio = ((read_requests - reads) / read_requests * 100) if read_requests > 0 else 0

        return {
            'total_queries': stats['queries'],
            'total_connections': stats['connections'],
            'slow_queries': stats['slow_queries'],
            'bytes_received': stats['bytes_received'],
            'bytes_sent': stats['bytes_sent'],
            'cache_hit_ratio': round(cache_hit_ratio, 2)
        }

    async def get_table_stats(self) -> List[Dict[str, Any]]:
        """获取表统计信息"""
        if not self.connection:
            if not await self.connect():
                return []

        try:
            if self.db_type == 'POSTGRESQL':
                return await self._get_postgresql_tables()
            elif self.db_type == 'MYSQL':
                return await self._get_mysql_tables()
            elif self.db_type == 'SQLSERVER':
                return await self._get_sqlserver_tables()
            elif self.db_type == 'ORACLE':
                return await self._get_oracle_tables()
            return []
        except Exception as e:
            logger.error(f"Error getting table stats: {e}")
            return []

    async def _get_postgresql_tables(self) -> List[Dict[str, Any]]:
        """获取PostgreSQL表统计"""
        rows = await self.connection.fetch("""
            SELECT st.schemaname,
                   st.relname AS tablename,
                   st.n_tup_ins AS inserts,
                   st.n_tup_upd AS updates,
                   st.n_tup_del AS deletes,
                   st.n_live_tup AS live_tuples,
                   st.n_dead_tup AS dead_tuples,
                   st.seq_scan AS sequential_scans,
                   st.idx_scan AS index_scans,
                   COALESCE(PG_SIZE_PRETTY(PG_RELATION_SIZE(c.oid)), '0 bytes') AS size,
                   COALESCE(PG_RELATION_SIZE(c.oid), 0) AS size_bytes,
                   COALESCE(PG_SIZE_PRETTY(PG_TOTAL_RELATION_SIZE(c.oid)), '0 bytes') AS total_size,
                   COALESCE(PG_TOTAL_RELATION_SIZE(c.oid), 0) AS total_size_bytes
            FROM pg_stat_user_tables st
            JOIN pg_class c ON c.relname = st.relname 
                AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = st.schemaname)
            WHERE c.relkind = 'r'
            ORDER BY COALESCE(PG_TOTAL_RELATION_SIZE(c.oid), 0) DESC
            LIMIT 20
        """)

        return [dict(row) for row in rows]

    async def _get_mysql_tables(self) -> List[Dict[str, Any]]:
        """获取MySQL表统计"""
        async with self.connection.cursor() as cursor:
            await cursor.execute("""
                SELECT table_name,
                       table_rows,
                       data_length,
                       index_length,
                       (data_length + index_length) AS total_size,
                       auto_increment
                FROM information_schema.tables
                WHERE table_schema = %s
                ORDER BY (data_length + index_length) DESC
                LIMIT 20
            """, (self.database,))

            tables = []
            rows = await cursor.fetchall()
            for row in rows:
                tables.append({
                    'table_name': row[0],
                    'table_rows': row[1] or 0,
                    'data_length': row[2] or 0,
                    'index_length': row[3] or 0,
                    'total_size': row[4] or 0,
                    'auto_increment': row[5] or 0
                })
        return tables

    async def _get_sqlserver_connections(self) -> Dict[str, Any]:
        """获取 SQL Server 连接信息"""
        total_connections = int(
            await self._fetch_odbc_value(
                "SELECT COUNT(*) FROM sys.dm_exec_sessions WHERE is_user_process = 1"
            )
            or 0
        )
        max_connections = int(await self._fetch_odbc_value("SELECT @@MAX_CONNECTIONS") or 0)
        active_connections = int(
            await self._fetch_odbc_value(
                """
                SELECT COUNT(*)
                FROM sys.dm_exec_sessions
                WHERE is_user_process = 1
                  AND status = 'running'
                """
            )
            or 0
        )
        idle_connections = max(total_connections - active_connections, 0)
        return {
            "total_connections": total_connections,
            "max_connections": max_connections,
            "active_connections": active_connections,
            "idle_connections": idle_connections,
            "connection_usage_percent": round(
                (total_connections / max_connections) * 100, 2
            )
            if max_connections > 0
            else 0.0,
        }

    async def _get_oracle_connections(self) -> Dict[str, Any]:
        """获取 Oracle 连接信息"""
        total_connections = int(
            await self._fetch_oracle_value(
                "SELECT COUNT(*) FROM v$session WHERE type != 'BACKGROUND'"
            )
            or 0
        )
        max_connections = int(
            await self._fetch_oracle_value(
                "SELECT value FROM v$parameter WHERE name = 'processes'"
            )
            or 0
        )
        active_connections = int(
            await self._fetch_oracle_value(
                """
                SELECT COUNT(*)
                FROM v$session
                WHERE type != 'BACKGROUND'
                  AND status = 'ACTIVE'
                """
            )
            or 0
        )
        idle_connections = max(total_connections - active_connections, 0)
        return {
            "total_connections": total_connections,
            "max_connections": max_connections,
            "active_connections": active_connections,
            "idle_connections": idle_connections,
            "connection_usage_percent": round(
                (total_connections / max_connections) * 100, 2
            )
            if max_connections > 0
            else 0.0,
        }

    async def _get_sqlserver_size(self) -> Dict[str, Any]:
        """获取 SQL Server 数据库大小"""
        size_bytes = int(
            await self._fetch_odbc_value(
                "SELECT SUM(size) * 8192 FROM sys.database_files"
            )
            or 0
        )
        return {
            "database_size_bytes": size_bytes,
            "database_size_mb": round(size_bytes / 1024 / 1024, 2),
            "database_size_gb": round(size_bytes / 1024 / 1024 / 1024, 2),
        }

    async def _get_oracle_size(self) -> Dict[str, Any]:
        """获取 Oracle 用户 Schema 占用空间"""
        size_bytes = int(
            await self._fetch_oracle_value(
                "SELECT NVL(SUM(bytes), 0) FROM user_segments"
            )
            or 0
        )
        return {
            "database_size_bytes": size_bytes,
            "database_size_mb": round(size_bytes / 1024 / 1024, 2),
            "database_size_gb": round(size_bytes / 1024 / 1024 / 1024, 2),
        }

    async def _get_sqlserver_performance(self) -> Dict[str, Any]:
        """获取 SQL Server 性能统计"""
        counters = await self._execute_odbc_query(
            """
            SELECT RTRIM(counter_name) AS counter_name, cntr_value
            FROM sys.dm_os_performance_counters
            WHERE (counter_name = 'Batch Requests/sec' AND instance_name = '')
               OR (counter_name = 'Page life expectancy'
                   AND object_name LIKE '%Buffer Manager%'
                   AND instance_name = '')
               OR (counter_name = 'Buffer cache hit ratio'
                   AND object_name LIKE '%Buffer Manager%'
                   AND instance_name = '')
            """
        )
        stats = {row["counter_name"]: row["cntr_value"] for row in counters}
        buffer_cache_hit_ratio = float(stats.get("Buffer cache hit ratio", 0) or 0)
        return {
            "batch_requests_per_sec": float(stats.get("Batch Requests/sec", 0) or 0),
            "page_life_expectancy": int(stats.get("Page life expectancy", 0) or 0),
            "buffer_cache_hit_ratio": round(buffer_cache_hit_ratio, 2),
            "cache_hit_ratio": round(buffer_cache_hit_ratio, 2),
        }

    async def _get_oracle_performance(self) -> Dict[str, Any]:
        """获取 Oracle 性能统计"""
        rows = await self._execute_oracle_query(
            """
            SELECT name, value
            FROM v$sysstat
            WHERE name IN (
                'user commits',
                'user rollbacks',
                'physical reads',
                'db block gets',
                'consistent gets'
            )
            """
        )
        stats = {row["name"]: float(row["value"] or 0) for row in rows}
        logical_reads = stats.get("db block gets", 0) + stats.get("consistent gets", 0)
        physical_reads = stats.get("physical reads", 0)
        cache_hit_ratio = (
            (1 - physical_reads / logical_reads) * 100 if logical_reads > 0 else 0.0
        )
        return {
            "transactions_commit": int(stats.get("user commits", 0)),
            "transactions_rollback": int(stats.get("user rollbacks", 0)),
            "cache_hit_ratio": round(cache_hit_ratio, 2),
        }

    async def _get_sqlserver_tables(self) -> List[Dict[str, Any]]:
        """获取 SQL Server 表统计"""
        rows = await self._execute_odbc_query(
            """
            SELECT TOP 20
                s.name AS schemaname,
                t.name AS tablename,
                MAX(p.rows) AS table_rows,
                SUM(a.total_pages) * 8 AS total_size_kb,
                SUM(a.used_pages) * 8 AS used_size_kb,
                SUM(
                    CASE WHEN i.index_id IN (0, 1) THEN a.used_pages ELSE 0 END
                ) * 8 AS data_size_kb
            FROM sys.tables t
            INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
            INNER JOIN sys.indexes i ON t.object_id = i.object_id
            INNER JOIN sys.partitions p
                ON i.object_id = p.object_id AND i.index_id = p.index_id
            INNER JOIN sys.allocation_units a ON p.partition_id = a.container_id
            WHERE t.is_ms_shipped = 0
            GROUP BY s.name, t.name
            ORDER BY total_size_kb DESC
            """
        )
        return rows

    async def _get_oracle_tables(self) -> List[Dict[str, Any]]:
        """获取 Oracle 表统计"""
        rows = await self._execute_oracle_query(
            """
            SELECT *
            FROM (
                SELECT t.table_name,
                       NVL(t.num_rows, 0) AS table_rows,
                       NVL(s.size_bytes, 0) AS size_bytes
                FROM user_tables t
                LEFT JOIN (
                    SELECT segment_name, SUM(bytes) AS size_bytes
                    FROM user_segments
                    WHERE segment_type IN ('TABLE', 'TABLE PARTITION')
                    GROUP BY segment_name
                ) s ON s.segment_name = t.table_name
                ORDER BY NVL(s.size_bytes, 0) DESC
            )
            WHERE ROWNUM <= 20
            """
        )
        return rows

    async def get_all_info(self, connection_id: str, connection_name: str) -> Dict[str, Any]:
        """获取所有数据库监控信息"""
        timestamp = datetime.now().isoformat()

        try:
            if not await self.connect():
                return {
                    'connection_id': connection_id,
                    'connection_name': connection_name,
                    'status': 'disconnected',
                    'basic_info': {},
                    'connection_info': {},
                    'database_size': {},
                    'performance_stats': {'cache_hit_ratio': 0.0},
                    'table_stats': [],
                    'timestamp': timestamp
                }

            data = {
                'connection_id': connection_id,
                'connection_name': connection_name,
                'status': 'connected',
                'basic_info': await self.get_basic_info(),
                'connection_info': await self.get_connection_info(),
                'database_size': await self.get_database_size(),
                'performance_stats': await self.get_performance_stats(),
                'table_stats': await self.get_table_stats(),
                'timestamp': timestamp
            }
            return serialize_data(data)
        except Exception as e:
            logger.error(f"Error getting database all info: {e}")
            return {
                'connection_id': connection_id,
                'connection_name': connection_name,
                'status': 'error',
                'basic_info': {},
                'connection_info': {},
                'database_size': {},
                'performance_stats': {'cache_hit_ratio': 0.0},
                'table_stats': [],
                'timestamp': timestamp
            }
        finally:
            await self.disconnect()

    async def get_realtime_stats(self, connection_id: str) -> Dict[str, Any]:
        """获取实时统计信息"""
        timestamp = datetime.now().isoformat()

        try:
            if not await self.connect():
                return {
                    'connection_id': connection_id,
                    'connections_used': 0,
                    'connection_usage_percent': 0.0,
                    'database_size_mb': 0.0,
                    'cache_hit_ratio': 0.0,
                    'active_connections': 0,
                    'timestamp': timestamp
                }

            connection_info = await self.get_connection_info()
            database_size = await self.get_database_size()
            performance_stats = await self.get_performance_stats()

            data = {
                'connection_id': connection_id,
                'connections_used': connection_info.get('total_connections', 0),
                'connection_usage_percent': connection_info.get('connection_usage_percent', 0.0),
                'database_size_mb': database_size.get('database_size_mb', 0.0),
                'cache_hit_ratio': performance_stats.get('cache_hit_ratio', 0.0),
                'active_connections': connection_info.get('active_connections', 0),
                'timestamp': timestamp
            }
            return serialize_data(data)
        except Exception as e:
            logger.error(f"Error getting database realtime stats: {e}")
            return {
                'connection_id': connection_id,
                'connections_used': 0,
                'connection_usage_percent': 0.0,
                'database_size_mb': 0.0,
                'cache_hit_ratio': 0.0,
                'active_connections': 0,
                'timestamp': timestamp
            }
        finally:
            await self.disconnect()
