"""Server settings router.

Provides endpoints to view and update fail2ban server-level settings and
to flush log files.

* ``GET  /api/server/settings``  — current log level, target, and DB config
* ``PUT  /api/server/settings``  — update server-level settings
* ``POST /api/server/flush-logs`` — flush and re-open log files
"""

from __future__ import annotations

from fastapi import APIRouter, HTTPException, Request, status

from app.dependencies import AuthDep, Fail2BanSocketDep
from app.models.server import ServerSettingsResponse, ServerSettingsUpdate
from app.services import server_service
from app.exceptions import ServerOperationError
from app.exceptions import Fail2BanConnectionError

router: APIRouter = APIRouter(prefix="/api/server", tags=["Server"])


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _bad_gateway(exc: Exception) -> HTTPException:
    return HTTPException(
        status_code=status.HTTP_502_BAD_GATEWAY,
        detail=f"Cannot reach fail2ban: {exc}",
    )


def _bad_request(message: str) -> HTTPException:
    return HTTPException(
        status_code=status.HTTP_400_BAD_REQUEST,
        detail=message,
    )


# ---------------------------------------------------------------------------
# Endpoints
# ---------------------------------------------------------------------------


@router.get(
    "/settings",
    response_model=ServerSettingsResponse,
    summary="Return fail2ban server-level settings",
)
async def get_server_settings(
    request: Request,
    _auth: AuthDep,
    socket_path: Fail2BanSocketDep,
) -> ServerSettingsResponse:
    """Return the current fail2ban server-level settings.

    Includes log level, log target, syslog socket, database file path,
    database purge age, and maximum stored matches per record.

    Args:
        request: Incoming request (used to access ``app.state``).
        _auth: Validated session — enforces authentication.

    Returns:
        :class:`~app.models.server.ServerSettingsResponse`.

    Raises:
        HTTPException: 502 when fail2ban is unreachable.
    """
    try:
        return await server_service.get_settings(socket_path)
    except Fail2BanConnectionError as exc:
        raise _bad_gateway(exc) from exc


@router.put(
    "/settings",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Update fail2ban server-level settings",
)
async def update_server_settings(
    request: Request,
    _auth: AuthDep,
    body: ServerSettingsUpdate,
    socket_path: Fail2BanSocketDep,
) -> None:
    """Update fail2ban server-level settings.

    Only non-None fields in the request body are written.  Changes take
    effect immediately without a daemon restart.

    Args:
        request: Incoming request.
        _auth: Validated session.
        body: Partial settings update.

    Raises:
        HTTPException: 400 when a set command is rejected by fail2ban.
        HTTPException: 502 when fail2ban is unreachable.
    """
    try:
        await server_service.update_settings(socket_path, body)
    except ServerOperationError as exc:
        raise _bad_request(str(exc)) from exc
    except Fail2BanConnectionError as exc:
        raise _bad_gateway(exc) from exc


@router.post(
    "/flush-logs",
    status_code=status.HTTP_200_OK,
    summary="Flush and re-open fail2ban log files",
)
async def flush_logs(
    request: Request,
    _auth: AuthDep,
    socket_path: Fail2BanSocketDep,
) -> dict[str, str]:
    """Flush and re-open fail2ban log files.

    Useful after log rotation so the daemon writes to the newly created
    log file rather than continuing to append to the rotated one.

    Args:
        request: Incoming request.
        _auth: Validated session.

    Returns:
        ``{"message": "<response from fail2ban>"}``

    Raises:
        HTTPException: 400 when the command is rejected.
        HTTPException: 502 when fail2ban is unreachable.
    """
    try:
        result = await server_service.flush_logs(socket_path)
        return {"message": result}
    except ServerOperationError as exc:
        raise _bad_request(str(exc)) from exc
    except Fail2BanConnectionError as exc:
        raise _bad_gateway(exc) from exc
