"""WaftDB — auto-configuring database wrapper.

Detects PostgreSQL (production) vs SQLite (local dev) from DATABASE_URL.
Provides a unified connection interface regardless of backend.
"""

from __future__ import annotations

import os
import sqlite3
from contextlib import contextmanager
from typing import Generator


class WaftDB:
    """Database wrapper that auto-configures from DATABASE_URL.

    In production (waft-deployed), DATABASE_URL points to PostgreSQL.
    Locally, it falls back to a SQLite file for development.
    """

    def __init__(self, database_url: str | None = None):
        self._url = database_url or os.environ.get("DATABASE_URL", "")
        self._is_postgres = self._url.startswith("postgres")

        if self._is_postgres:
            try:
                import psycopg2  # noqa: F401
            except ImportError as e:
                raise ImportError(
                    "psycopg2 is required for PostgreSQL. "
                    "Install with: pip install waft-client[postgres]"
                ) from e

    @property
    def is_postgres(self) -> bool:
        """True if connected to PostgreSQL (production)."""
        return self._is_postgres

    @property
    def is_sqlite(self) -> bool:
        """True if using SQLite (local development)."""
        return not self._is_postgres

    @contextmanager
    def connection(self) -> Generator:
        """Get a database connection. Use as a context manager.

        Yields a connection object with .execute(), .cursor(), etc.
        The connection is committed on success and rolled back on error.
        """
        if self._is_postgres:
            conn = self._pg_connect()
            try:
                yield conn
                conn.commit()
            except Exception:
                conn.rollback()
                raise
            finally:
                conn.close()
        else:
            path = self._sqlite_path()
            conn = sqlite3.connect(path)
            conn.row_factory = sqlite3.Row
            conn.execute("PRAGMA journal_mode=WAL")
            conn.execute("PRAGMA foreign_keys=ON")
            try:
                yield conn
                conn.commit()
            except Exception:
                conn.rollback()
                raise
            finally:
                conn.close()

    def execute(self, sql: str, params: tuple | list = ()) -> list:
        """Execute SQL and return all rows as dicts. Convenience method."""
        with self.connection() as conn:
            cursor = conn.execute(sql, params)
            if cursor.description:
                cols = [d[0] for d in cursor.description]
                return [dict(zip(cols, row)) for row in cursor.fetchall()]
            return []

    def _pg_connect(self):
        """Create a PostgreSQL connection."""
        import psycopg2
        import psycopg2.extras

        conn = psycopg2.connect(self._url)
        conn.cursor_factory = psycopg2.extras.RealDictCursor
        return conn

    def _sqlite_path(self) -> str:
        """Determine SQLite file path from DATABASE_URL or default."""
        if self._url.startswith("sqlite:///"):
            return self._url[len("sqlite:///"):]
        if self._url and not self._url.startswith("postgres"):
            return self._url
        return "app.db"
