import logging
import re

import duckdb
from fastapi import APIRouter, Request
from starlette.responses import PlainTextResponse, Response

from n6k_server.session import get_session

log = logging.getLogger(__name__)

router = APIRouter()

_SAFE_ID = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")


@router.post("/{view_id}")
async def create_view(view_id: str, request: Request) -> Response:
    session = get_session(request)
    if session is None:
        return PlainTextResponse("no active session — connect via WebSocket first", status_code=401)

    if not _SAFE_ID.match(view_id):
        log.warning("view_id rejected: %s", view_id)
        return PlainTextResponse(
            "view_id must be alphanumeric/underscore, starting with letter or underscore",
            status_code=400,
        )

    sql = (await request.body()).decode("utf-8").strip()
    log.info("create_view %s — sql: %s", view_id, sql[:200])
    if not sql:
        return PlainTextResponse("request body must contain SQL", status_code=400)

    first_keyword = sql.split()[0].upper() if sql.split() else ""
    if first_keyword not in ("SELECT", "WITH"):
        log.warning("rejected keyword: %s", first_keyword)
        return PlainTextResponse("only SELECT/WITH statements allowed", status_code=400)

    try:
        session.db.execute(f'CREATE OR REPLACE VIEW db."{view_id}" AS {sql}')
    except duckdb.Error as e:
        log.error("SQL error creating view %s: %s", view_id, e)
        return PlainTextResponse(f"SQL error: {e}", status_code=400)

    return PlainTextResponse(f"view {view_id} created", status_code=201)


@router.delete("/{view_id}")
async def delete_view(view_id: str, request: Request) -> Response:
    session = get_session(request)
    if session is None:
        return PlainTextResponse("no active session — connect via WebSocket first", status_code=401)

    if not _SAFE_ID.match(view_id):
        log.warning("view_id rejected: %s", view_id)
        return PlainTextResponse(
            "view_id must be alphanumeric/underscore, starting with letter or underscore",
            status_code=400,
        )

    try:
        session.db.execute(f'DROP VIEW IF EXISTS db."{view_id}"')
    except duckdb.Error as e:
        log.error("SQL error dropping view %s: %s", view_id, e)
        return PlainTextResponse(f"SQL error: {e}", status_code=400)

    return PlainTextResponse(f"view {view_id} deleted", status_code=200)
