"""Auth HTTP endpoints: /auth/info, /auth/login, /auth/refresh, /auth/logout."""
from __future__ import annotations
import asyncio
from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel
from .middleware import get_current_user
from .tokens import create_access_token, create_refresh_token, rotate_refresh_token, _hash_token
from .base import User
from .db import _connect
from .audit import log_event


class LoginRequest(BaseModel):
    email: str
    password: str


class RefreshRequest(BaseModel):
    refresh_token: str


class LogoutRequest(BaseModel):
    refresh_token: str


def create_auth_router() -> APIRouter:
    router = APIRouter(prefix="/auth", tags=["auth"])

    @router.get("/info")
    async def auth_info(request: Request):
        config = request.app.state.config
        methods = {}
        if config.auth.local:
            methods["local"] = True
        return {
            "server_name": config.name,
            "logo": config.logo,
            "auth_methods": methods,
        }

    @router.post("/login")
    async def login(body: LoginRequest, request: Request):
        rl = request.app.state.rate_limiter
        ip = request.client.host if request.client else "unknown"
        if rl.is_locked_out(ip, body.email):
            raise HTTPException(status_code=423, detail="Account locked")
        if not rl.check_and_record(ip, body.email):
            raise HTTPException(status_code=429, detail="Too many login attempts")

        provider = request.app.state.auth_provider
        user = await asyncio.to_thread(
            provider.authenticate, email=body.email, password=body.password
        )
        if not user:
            rl.record_failure(ip, body.email)
            await asyncio.to_thread(
                log_event, request.app.state.db_path, action="LOGIN",
                detail=f"failed:{body.email}", ip_address=ip,
            )
            raise HTTPException(status_code=401, detail="Invalid credentials")

        config = request.app.state.config
        access = create_access_token(
            request.app.state.jwt_key,
            user_id=user.id,
            ttl=config.auth.access_token_ttl,
        )
        refresh = await asyncio.to_thread(
            create_refresh_token, request.app.state.db_path,
            user_id=user.id, ttl=config.auth.refresh_token_ttl,
        )
        await asyncio.to_thread(
            log_event, request.app.state.db_path, user_id=user.id,
            action="LOGIN", detail="success", ip_address=ip,
        )
        return {
            "access_token": access,
            "refresh_token": refresh,
            "expires_in": config.auth.access_token_ttl,
        }

    @router.post("/refresh")
    async def refresh(body: RefreshRequest, request: Request):
        ip = request.client.host if request.client else "unknown"
        config = request.app.state.config
        result = await asyncio.to_thread(
            rotate_refresh_token, request.app.state.db_path,
            body.refresh_token, ttl=config.auth.refresh_token_ttl,
        )
        if not result:
            raise HTTPException(status_code=401, detail="Invalid or expired refresh token")
        new_refresh, user_id = result
        access = create_access_token(
            request.app.state.jwt_key, user_id=user_id,
            ttl=config.auth.access_token_ttl,
        )
        await asyncio.to_thread(
            log_event, request.app.state.db_path, user_id=user_id,
            action="REFRESH", ip_address=ip,
        )
        return {
            "access_token": access,
            "refresh_token": new_refresh,
            "expires_in": config.auth.access_token_ttl,
        }

    @router.delete("/logout")
    async def logout(body: LogoutRequest, request: Request, user: User = Depends(get_current_user)):
        ip = request.client.host if request.client else "unknown"

        def _revoke():
            token_hash = _hash_token(body.refresh_token)
            conn = _connect(request.app.state.db_path)
            result = conn.execute(
                "UPDATE refresh_tokens SET revoked = 1 WHERE token_hash = ? AND user_id = ?",
                (token_hash, user.id),
            )
            conn.commit()
            conn.close()
            return result.rowcount

        rowcount = await asyncio.to_thread(_revoke)
        if rowcount == 0:
            raise HTTPException(status_code=403, detail="Token does not belong to this user")
        await asyncio.to_thread(
            log_event, request.app.state.db_path, user_id=user.id,
            action="LOGOUT", ip_address=ip,
        )
        return {"ok": True}

    return router
