#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""数据库连接解析器"""
import logging
import time
from typing import Dict, Optional, Tuple

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.config import settings
from app.database import AsyncSessionLocal
from core.database_connection.model import DatabaseConnection
from core.database_connection.types import ConnectionInfo
from core.database_manager.service import parse_database_url
from utils.secret_crypto import decrypt_secret

logger = logging.getLogger(__name__)

_CACHE: Dict[str, Tuple[ConnectionInfo, float]] = {}
_CACHE_TTL = 60.0


class ConnectionResolver:
    @staticmethod
    def invalidate_cache(code: Optional[str] = None) -> None:
        if code:
            _CACHE.pop(code, None)
        else:
            _CACHE.clear()

    @staticmethod
    def default_connection_info() -> ConnectionInfo:
        db_info = parse_database_url(settings.DATABASE_URL or "")
        if not db_info:
            raise ValueError("Invalid DATABASE_URL configuration")
        return ConnectionInfo(
            code="default",
            db_type=db_info["db_type"],
            host=db_info["host"],
            port=db_info["port"],
            user=db_info["user"],
            password=db_info["password"],
            database=db_info["database"],
            is_system=True,
            display_name=db_info["database"] or "default",
        )

    @classmethod
    async def resolve(
        cls,
        code: str,
        db: Optional[AsyncSession] = None,
    ) -> ConnectionInfo:
        if code == "default":
            return cls.default_connection_info()

        now = time.time()
        cached = _CACHE.get(code)
        if cached and now - cached[1] < _CACHE_TTL:
            return cached[0]

        if db is None:
            async with AsyncSessionLocal() as session:
                info = await cls._resolve_from_db(session, code)
        else:
            info = await cls._resolve_from_db(db, code)

        _CACHE[code] = (info, now)
        return info

    @classmethod
    async def _resolve_from_db(cls, db: AsyncSession, code: str) -> ConnectionInfo:
        result = await db.execute(
            select(DatabaseConnection).where(
                DatabaseConnection.code == code,
                DatabaseConnection.is_deleted == False,
            )
        )
        row = result.scalar_one_or_none()
        if not row or not row.status:
            raise ValueError(f"Database connection '{code}' not found or disabled")
        if row.is_system:
            return cls.default_connection_info()

        password = decrypt_secret(row.password_enc or "")
        if row.password_enc and not password:
            logger.error(
                "Failed to decrypt password for connection code=%s (check DB_CONN_SECRET_KEY / JWT_SECRET_KEY)",
                row.code,
            )

        return ConnectionInfo(
            code=row.code,
            db_type=row.db_type,
            host=row.host,
            port=row.port,
            user=row.user or "",
            password=password,
            database=row.default_database or "",
            is_system=False,
            display_name=row.name,
            extra_options=row.extra_options or {},
        )
