"""Auth router for BadNote."""

from datetime import datetime, timezone
from uuid import uuid4

from fastapi import APIRouter, Depends, HTTPException, status

from ..auth import (
    create_access_token,
    dummy_verify,
    get_current_user,
    hash_password,
    verify_password,
)
from ..database import get_db
from ..models import TokenResponse, UserCreate, UserLogin

router = APIRouter()


@router.post("/register", response_model=TokenResponse, status_code=status.HTTP_201_CREATED)
async def register(body: UserCreate) -> TokenResponse:
    """Register a new user."""
    db = await get_db()
    existing = await db.execute(
        "SELECT id FROM users WHERE username = ?", (body.username,)
    )
    if await existing.fetchone() is not None:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="Username already taken",
        )

    user_id = str(uuid4())
    now = datetime.now(timezone.utc).isoformat()
    await db.execute(
        "INSERT INTO users (id, username, password_hash, created_at) VALUES (?, ?, ?, ?)",
        (user_id, body.username, hash_password(body.password), now),
    )
    await db.commit()

    token = create_access_token(user_id)
    return TokenResponse(token=token, user_id=user_id)


@router.post("/login", response_model=TokenResponse)
async def login(body: UserLogin) -> TokenResponse:
    """Authenticate and return a token."""
    db = await get_db()
    row = await (
        await db.execute(
            "SELECT id, password_hash FROM users WHERE username = ?", (body.username,)
        )
    ).fetchone()

    if row is None:
        # Spend comparable time hashing so timing does not reveal whether the
        # username exists.
        dummy_verify()
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid username or password",
        )
    if not verify_password(body.password, row["password_hash"]):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid username or password",
        )

    token = create_access_token(row["id"])
    return TokenResponse(token=token, user_id=row["id"])


@router.post("/refresh", response_model=TokenResponse)
async def refresh(user_id: str = Depends(get_current_user)) -> TokenResponse:
    """Refresh an existing valid token."""
    token = create_access_token(user_id)
    return TokenResponse(token=token, user_id=user_id)
