import logging

import duckdb
import pyarrow as pa
from fastapi import APIRouter, Request
from starlette.responses import Response

from n6k_server.formats import arrow_response, negotiate
from n6k_server.pushdown import build_query
from n6k_server.session import get_session

log = logging.getLogger(__name__)
router = APIRouter(redirect_slashes=False)


def _get_db(request: Request) -> duckdb.DuckDBPyConnection:
    session = get_session(request)
    if session is not None:
        return session.db
    db: duckdb.DuckDBPyConnection = request.app.state.shared_db
    return db


@router.get("")
@router.get("/")
async def list_tables(request: Request) -> Response:
    registry = request.app.state.table_registry
    names = registry.all_names

    table = pa.table(
        {
            "name": pa.array(names, type=pa.utf8()),
            "path": pa.array([f"/tables/{n}" for n in names], type=pa.utf8()),
            "schema_path": pa.array([f"/tables/{n}/_schema" for n in names], type=pa.utf8()),
        }
    )
    return arrow_response(table, negotiate(request))


@router.get("/{name}")
async def get_table(name: str, request: Request, columns: str | None = None, filters: str | None = None) -> Response:
    registry = request.app.state.table_registry
    if registry.is_known(name):
        registry.ensure_loaded(name)

    db = _get_db(request)
    sql, params = build_query(name, columns, filters)
    try:
        table = db.execute(sql, params).to_arrow_table()
    except duckdb.Error:
        return Response(content=f"table not found: {name}", status_code=404)
    log.info("GET /tables/%s — %d rows", name, table.num_rows)
    return arrow_response(table, negotiate(request))


@router.get("/{name}/_schema")
async def get_schema(name: str, request: Request) -> Response:
    registry = request.app.state.table_registry
    if registry.is_known(name):
        registry.ensure_loaded(name)

    db = _get_db(request)
    try:
        table = db.execute(f'SELECT * FROM db."{name}" LIMIT 0').to_arrow_table()
    except duckdb.Error:
        return Response(content=f"table not found: {name}", status_code=404)

    return arrow_response(table, negotiate(request))
