"""
Catalog — temp-view registry backed by DuckDB.

DuckDB can consume Polars DataFrames directly (zero-copy via Apache Arrow),
so we register each temp view with DuckDB and run SQL against it.
"""
from __future__ import annotations

import threading

import duckdb
import polars as pl


class Catalog:
    def __init__(self):
        self._views: dict[str, pl.DataFrame] = {}
        # One in-process DuckDB connection per Catalog instance
        self._conn: duckdb.DuckDBPyConnection = duckdb.connect()
        self._lock = threading.Lock()

    # ------------------------------------------------------------------
    # View registration
    # ------------------------------------------------------------------

    def register(self, name: str, df: pl.DataFrame) -> None:
        """Register a Polars DataFrame as a named view in DuckDB."""
        with self._lock:
            self._views[name] = df
            # DuckDB accepts polars DataFrames directly via Arrow protocol
            self._conn.register(name, df)

    def unregister(self, name: str) -> None:
        """Remove a named view."""
        with self._lock:
            self._views.pop(name, None)
            try:
                self._conn.unregister(name)
            except Exception:
                pass

    def tableExists(self, name: str) -> bool:
        return name in self._views

    def listTables(self) -> list[str]:
        return list(self._views.keys())

    def dropTempView(self, name: str) -> None:
        self.unregister(name)

    def dropGlobalTempView(self, name: str) -> None:
        self.unregister(name)

    def listDatabases(self) -> list[str]:
        return ["default"]

    def currentDatabase(self) -> str:
        return "default"

    def currentCatalog(self) -> str:
        return "singlespark"

    # ------------------------------------------------------------------
    # SQL execution
    # ------------------------------------------------------------------

    def sql(self, query: str) -> pl.DataFrame:
        """
        Execute a SQL query using DuckDB and return the result as a Polars DataFrame.

        All registered temp views are available as table names.
        """
        with self._lock:
            try:
                result = self._conn.execute(query)
                return result.pl()
            except duckdb.Error as exc:
                raise RuntimeError(f"SQL execution error: {exc}\nQuery: {query}") from exc

    # ------------------------------------------------------------------
    # Cleanup
    # ------------------------------------------------------------------

    def close(self) -> None:
        try:
            self._conn.close()
        except Exception:
            pass

    def __repr__(self):
        views = list(self._views.keys())
        return f"Catalog(views={views})"
