import oracledb
import asyncio
import os
import re
import logging
import datetime

# 配置日志
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    encoding='utf-8'
)
logger = logging.getLogger(__name__)

connection_string = ""
lib_dir=""
pool = None
dql_limits_rows = ""

# 初始化Oracle客户端和连接池
async def init_pool():
    global pool
    if pool is None:
        try:
            logger.debug("开始初始化连接池")
            if connection_string is None:
                return
            # 解析连接字符串
            user, host = connection_string.split('@')
            username, password = user.split('/')
            hostname, service = host.split('/')
            hostname, port = hostname.split(':')
            
            logger.debug(f"连接参数: host={hostname}, port={port}, service={service}, user={username}")
            
            oracledb.init_oracle_client(lib_dir=lib_dir)
            logger.debug("Oracle客户端初始化成功")
            
            # 创建连接池
            pool = await asyncio.to_thread(
                oracledb.create_pool,
                user=username,
                password=password,
                dsn=f"{hostname}:{port}/{service}",
                min=2,
                max=10,
                increment=1,
                getmode=oracledb.POOL_GETMODE_WAIT
            )
            logger.info("数据库连接池初始化成功，最小连接数: 2, 最大连接数: 10")
        except Exception as e:
            logger.error(f"连接池初始化失败: {str(e)}", exc_info=True)
            raise

async def list_tables() -> list:
    tables = []
    try:
        # 在单独的线程中运行数据库操作
        def db_operation():
            result_tables = []
            with pool.acquire() as conn:
                cursor = conn.cursor()
                cursor.execute(
                    "SELECT table_name FROM user_tables ORDER BY table_name")
                for row in cursor:
                    result_tables.append(row[0])
            return '\n'.join(result_tables)

        return await asyncio.to_thread(db_operation)
    except oracledb.DatabaseError as e:
        print('Error occurred:', e)
        return str(e)

async def describe_table(table_name: str) -> str:
    try:
        # 在单独的线程中运行数据库操作
        def db_operation(table):
            with pool.acquire() as conn:
                cursor = conn.cursor()

                # Create CSV headers
                result = [
                    "COLUMN_NAME,DATA_TYPE,NULLABLE,DATA_LENGTH,PRIMARY_KEY,FOREIGN_KEY"]

                # Get primary key columns
                pk_columns = []
                cursor.execute(
                    """
                    SELECT cols.column_name
                    FROM all_constraints cons, all_cons_columns cols
                    WHERE cons.constraint_type = 'P'
                    AND cons.constraint_name = cols.constraint_name
                    AND cons.owner = cols.owner
                    AND cols.table_name = :table_name
                    """,
                    table_name=table.upper()
                )
                for row in cursor:
                    pk_columns.append(row[0])

                # Get foreign key columns and references
                fk_info = {}
                cursor.execute(
                    """
                    SELECT a.column_name, c_pk.table_name as referenced_table, b.column_name as referenced_column
                    FROM all_cons_columns a
                    JOIN all_constraints c ON a.owner = c.owner AND a.constraint_name = c.constraint_name
                    JOIN all_constraints c_pk ON c.r_owner = c_pk.owner AND c.r_constraint_name = c_pk.constraint_name
                    JOIN all_cons_columns b ON c_pk.owner = b.owner AND c_pk.constraint_name = b.constraint_name
                    WHERE c.constraint_type = 'R'
                    AND a.table_name = :table_name
                    """,
                    table_name=table.upper()
                )
                for row in cursor:
                    fk_info[row[0]] = f"{row[1]}.{row[2]}"

                # Get main column information
                cursor.execute(
                    """
                    SELECT column_name, data_type, nullable, data_length 
                    FROM user_tab_columns 
                    WHERE table_name = :table_name 
                    ORDER BY column_id
                    """,
                    table_name=table.upper()
                )

                rows_found = False
                for row in cursor:
                    rows_found = True
                    column_name = row[0]
                    data_type = row[1]
                    nullable = row[2]
                    data_length = str(row[3])
                    is_pk = "YES" if column_name in pk_columns else "NO"
                    fk_ref = fk_info.get(column_name, "NO")

                    # Format as CSV row
                    result.append(
                        f"{column_name},{data_type},{nullable},{data_length},{is_pk},{fk_ref}")

                if not rows_found:
                    return f"Table {table} not found or has no columns."

                return '\n'.join(result)

        return await asyncio.to_thread(db_operation, table_name)
    except oracledb.DatabaseError as e:
        print('Error occurred:', e)
        return str(e)

async def execute_DQL(query: str) -> str:
    # 移除SQL注释以便进行准确的验证
    # 首先移除 -- 风格的单行注释
    no_line_comments = re.sub(r'--[^\n]*', '', query)
    # 然后移除 /* ... */ 风格的多行注释
    no_block_comments = re.sub(r'/\*.*?\*/', '', no_line_comments, flags=re.DOTALL)
    
    cleaned_query = no_block_comments.strip()
    # 检查清理后的查询是否以 SELECT 或 WITH 开头
    if not (cleaned_query.upper().startswith('SELECT') or cleaned_query.upper().startswith('WITH')):
        return "错误：只支持 SELECT 或 WITH 查询语句。"

    try:
        # 在单独的线程中运行数据库操作
        def db_operation(query):
            with pool.acquire() as conn:
                cursor = conn.cursor()

                # 直接执行原始查询，不进行修改
                logger.debug(f"执行查询: {query}")
                cursor.execute(query)

                # 获取列名
                columns = [col[0] for col in cursor.description]
                result = [','.join(columns)]  # 添加列标题

                # 确保行数限制是整数，以防止类型错误
                try:
                    limit = int(dql_limits_rows)
                except (ValueError, TypeError):
                    limit = 10  # 如果转换失败，使用安全的默认值
                
                # 使用 fetchmany 来安全地限制返回的行数
                rows = cursor.fetchmany(limit)

                if not rows:
                    return "查询未返回任何行。"

                # 处理获取到的行
                for row in rows:
                    # 将元组中的每个值转换为字符串
                    string_values = [
                        str(val) if val is not None else "NULL" for val in row]
                    result.append(','.join(string_values))

                return '\n'.join(result)

        return await asyncio.to_thread(db_operation, query)
    except oracledb.DatabaseError as e:
        print('Error occurred:', e)
        return str(e)

async def execute_DDL(query: str) -> str:
    """
    执行 DDL（数据定义语言）语句，如 CREATE、ALTER、DROP、TRUNCATE 等
    
    Args:
        query (str): DDL 查询语句
        
    Returns:
        str: 执行结果消息
    """
    # 移除SQL注释以便进行准确的验证
    # 首先移除 -- 风格的单行注释
    no_line_comments = re.sub(r'--[^\n]*', '', query)
    # 然后移除 /* ... */ 风格的多行注释
    no_block_comments = re.sub(r'/\*.*?\*/', '', no_line_comments, flags=re.DOTALL)
    
    cleaned_query = no_block_comments.strip()
    
    # 检查是否为DDL语句
    ddl_keywords = ['CREATE', 'ALTER', 'DROP', 'TRUNCATE', 'COMMENT', 'RENAME']
    if not any(cleaned_query.upper().startswith(keyword) for keyword in ddl_keywords):
        return "错误：只支持 DDL 语句（CREATE、ALTER、DROP、TRUNCATE、COMMENT、RENAME）。"
    
    # 检查危险操作
    dangerous_patterns = [
        r'\bDROP\s+DATABASE\b',
        r'\bDROP\s+TABLESPACE\b',
        r'\bDROP\s+USER\b'
    ]
    
    for pattern in dangerous_patterns:
        if re.search(pattern, cleaned_query, re.IGNORECASE):
            return f"错误：出于安全考虑，不允许执行此类操作：{pattern}"

    try:
        # 在单独的线程中运行数据库操作
        def db_operation(query):
            with pool.acquire() as conn:
                cursor = conn.cursor()
                
                logger.debug(f"执行DDL语句: {query}")
                
                # 执行DDL语句
                cursor.execute(query)
                
                # 提交事务
                conn.commit()
                
                # 根据DDL类型返回相应的成功消息
                if cleaned_query.upper().startswith('CREATE'):
                    return "DDL语句执行成功：对象已创建。"
                elif cleaned_query.upper().startswith('ALTER'):
                    return "DDL语句执行成功：对象已修改。"
                elif cleaned_query.upper().startswith('DROP'):
                    return "DDL语句执行成功：对象已删除。"
                elif cleaned_query.upper().startswith('TRUNCATE'):
                    return "DDL语句执行成功：表已清空。"
                elif cleaned_query.upper().startswith('COMMENT'):
                    return "DDL语句执行成功：注释已添加。"
                elif cleaned_query.upper().startswith('RENAME'):
                    return "DDL语句执行成功：对象已重命名。"
                else:
                    return "DDL语句执行成功。"

        return await asyncio.to_thread(db_operation, query)
    except oracledb.DatabaseError as e:
        logger.error(f"DDL执行失败: {str(e)}")
        return f"DDL执行失败: {str(e)}"
    except Exception as e:
        logger.error(f"执行DDL时发生意外错误: {str(e)}")
        return f"执行DDL时发生意外错误: {str(e)}"

# 关闭连接池
async def close_pool():
    global pool
    if pool:
        await asyncio.to_thread(pool.close)
        print("数据库连接池已关闭")
        pool = None

if __name__ == "__main__":
    # Create and run the async event loop
    async def main():
        # 初始化连接池
        await init_pool()
        #await list_tables()
        # try:
            # print(await list_tables())
        print(await describe_table('CONTACT'))
        # finally:
        #     await close_pool()

    asyncio.run(main())
