#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Handler 事务支持（表单业务库与 default 行为对齐）"""
import re
import time
from typing import Any, Dict

from core.database_manager.handlers.common import serialize_row

_SAVEPOINT_NAME_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")


def validate_savepoint_name(name: str) -> str:
    if not _SAVEPOINT_NAME_RE.match(name or ""):
        raise ValueError(f"Invalid savepoint name: {name}")
    return name


class HandlerTransactionMixin:
    """在 execute_sql 上叠加请求级事务；子类需实现 _run_sql_command / _run_sql_query。"""

    _in_transaction: bool = False

    async def _run_sql_command(self, sql: str) -> int:
        raise NotImplementedError

    async def _run_sql_query(self, sql: str) -> list:
        raise NotImplementedError

    async def _exec_tx_statement(self, sql: str) -> None:
        await self._run_sql_command(sql)

    async def begin_transaction(self) -> bool:
        if self._in_transaction:
            return True
        if not await self.connect():
            return False
        await self._exec_tx_statement("BEGIN")
        self._in_transaction = True
        return True

    async def commit_transaction(self) -> None:
        if not self._in_transaction:
            return
        try:
            await self._exec_tx_statement("COMMIT")
        finally:
            self._in_transaction = False
            await self.close()

    async def rollback_transaction(self) -> None:
        if not self._in_transaction:
            return
        try:
            await self._exec_tx_statement("ROLLBACK")
        finally:
            self._in_transaction = False
            await self.close()

    async def create_savepoint(self, name: str) -> None:
        sp = validate_savepoint_name(name)
        await self._exec_tx_statement(f"SAVEPOINT {sp}")

    async def release_savepoint(self, name: str) -> None:
        sp = validate_savepoint_name(name)
        await self._exec_tx_statement(f"RELEASE SAVEPOINT {sp}")

    async def rollback_to_savepoint(self, name: str) -> None:
        sp = validate_savepoint_name(name)
        await self._exec_tx_statement(f"ROLLBACK TO SAVEPOINT {sp}")

    async def _execute_sql_impl(self, sql: str, is_query: bool = True) -> Dict[str, Any]:
        start_time = time.time()
        try:
            if not self.conn and not await self.connect():
                return {
                    "success": False,
                    "message": "数据库连接失败",
                    "columns": None,
                    "rows": None,
                    "affected_rows": None,
                    "execution_time": 0,
                }
            if is_query:
                rows = await self._run_sql_query(sql)
                execution_time = time.time() - start_time
                rows_list = [serialize_row(dict(row) if not isinstance(row, dict) else row) for row in rows]
                columns = list(rows_list[0].keys()) if rows_list else []
                return {
                    "success": True,
                    "message": f"查询成功，返回 {len(rows_list)} 行",
                    "columns": columns,
                    "rows": rows_list,
                    "affected_rows": None,
                    "execution_time": round(execution_time, 3),
                }
            affected_rows = await self._run_sql_command(sql)
            execution_time = time.time() - start_time
            return {
                "success": True,
                "message": f"执行成功，影响 {affected_rows} 行",
                "columns": None,
                "rows": None,
                "affected_rows": affected_rows,
                "execution_time": round(execution_time, 3),
            }
        except Exception as e:
            return {
                "success": False,
                "message": str(e),
                "columns": None,
                "rows": None,
                "affected_rows": None,
                "execution_time": round(time.time() - start_time, 3),
            }

    async def execute_sql(self, sql: str, is_query: bool = True) -> Dict[str, Any]:
        result = await self._execute_sql_impl(sql, is_query)
        if not self._in_transaction:
            await self.close()
        return result
