"""Cloud-aware connection factories for Postgres and Redis."""

from __future__ import annotations

import logging
import os
import re
from urllib.parse import urlparse

import asyncpg
import redis.asyncio as aioredis

from loom.config import DatabaseConfig, RedisConfig

logger = logging.getLogger(__name__)


def _extract_database(dsn: str) -> str:
    """Extract database name from a DSN."""
    parsed = urlparse(dsn)
    return parsed.path.lstrip("/") if parsed.path else "loom"


def _extract_user(dsn: str) -> str:
    """Extract username from a DSN."""
    parsed = urlparse(dsn)
    return parsed.username or "loom"


def _extract_password(dsn: str) -> str:
    """Extract password from a DSN."""
    parsed = urlparse(dsn)
    return parsed.password or ""


def _redact_url(url: str) -> str:
    """Redact password from a URL for safe logging."""
    return re.sub(r"://([^:]+):([^@]+)@", r"://\1:***@", url)


async def create_pool(config: DatabaseConfig) -> asyncpg.Pool:
    """Create an asyncpg connection pool.

    Detects CLOUD_SQL_CONNECTION_NAME env var to connect via Unix socket
    (Cloud SQL Auth Proxy); otherwise uses standard TCP from config.url.
    """
    cloud_sql = os.environ.get("CLOUD_SQL_CONNECTION_NAME")

    if cloud_sql:
        socket_path = f"/cloudsql/{cloud_sql}"
        database = _extract_database(config.url)
        user = _extract_user(config.url)
        password = _extract_password(config.url)
        logger.info(
            "Connecting to Cloud SQL via Unix socket: %s (db=%s, user=%s)",
            socket_path, database, user,
        )
        pool = await asyncpg.create_pool(
            host=socket_path,
            database=database,
            user=user,
            password=password,
            min_size=config.pool_min_size,
            max_size=config.pool_max_size,
        )
    else:
        logger.info("Connecting to Postgres: %s", _redact_url(config.url))
        pool = await asyncpg.create_pool(
            config.url,
            min_size=config.pool_min_size,
            max_size=config.pool_max_size,
        )

    return pool


async def create_redis(config: RedisConfig) -> aioredis.Redis:
    """Create a Redis async client.

    Detects LOOM_REDIS_TLS=true to rewrite redis:// to rediss:// and
    set ssl_cert_reqs for GCP Memorystore; otherwise standard connection.
    """
    url = config.url
    use_tls = os.environ.get("LOOM_REDIS_TLS", "").lower() == "true"

    if use_tls and url.startswith("redis://"):
        url = "rediss://" + url[len("redis://"):]
        logger.info("Connecting to Redis with TLS: %s", _redact_url(url))
        client = aioredis.from_url(
            url, decode_responses=True, ssl_cert_reqs="optional",
        )
    else:
        logger.info("Connecting to Redis: %s", _redact_url(url))
        client = aioredis.from_url(url, decode_responses=True)

    return client
