"""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, Request, status

from app.dependencies import AuthDep, Fail2BanSocketDep
from app.mappers import server_mappers
from app.models.response import FlushLogsResponse
from app.models.server import ServerSettingsResponse, ServerSettingsUpdate
from app.services import server_service

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


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


@router.get(
    "/settings",
    response_model=ServerSettingsResponse,
    summary="Return fail2ban server-level settings",
    responses={
        200: {"description": "Server settings returned", "model": ServerSettingsResponse},
        401: {"description": "Session missing, expired, or invalid"},
        502: {"description": "fail2ban unreachable"},
    },
)
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.
    """
    domain_result = await server_service.get_settings(socket_path)
    return server_mappers.map_domain_server_settings_result_to_response(domain_result)


@router.put(
    "/settings",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Update fail2ban server-level settings",
    responses={
        204: {"description": "Settings updated successfully"},
        400: {"description": "Set command rejected by fail2ban"},
        401: {"description": "Session missing, expired, or invalid"},
        502: {"description": "fail2ban unreachable"},
    },
)
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.
    """
    await server_service.update_settings(socket_path, body)


@router.post(
    "/flush-logs",
    status_code=status.HTTP_200_OK,
    summary="Flush and re-open fail2ban log files",
    response_model=FlushLogsResponse,
    responses={
        200: {"description": "Logs flushed successfully", "model": FlushLogsResponse},
        400: {"description": "Command rejected by fail2ban"},
        401: {"description": "Session missing, expired, or invalid"},
        502: {"description": "fail2ban unreachable"},
    },
)
async def flush_logs(
    request: Request,
    _auth: AuthDep,
    socket_path: Fail2BanSocketDep,
) -> FlushLogsResponse:
    """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:
        :class:`~app.models.response.FlushLogsResponse` with the result from fail2ban.

    Raises:
        HTTPException: 400 when the command is rejected.
        HTTPException: 502 when fail2ban is unreachable.
    """
    result = await server_service.flush_logs(socket_path)
    return FlushLogsResponse(message=result)
