"""Pydantic models for file-based fail2ban configuration management.

Covers jail config files (``jail.d/``), filter definitions (``filter.d/``),
and action definitions (``action.d/``).
"""

from pydantic import BaseModel, ConfigDict, Field

# ---------------------------------------------------------------------------
# Jail config file models (Task 4a)
# ---------------------------------------------------------------------------


class JailConfigFile(BaseModel):
    """Metadata for a single jail configuration file in ``jail.d/``."""

    model_config = ConfigDict(strict=True)

    name: str = Field(..., description="Jail name (file stem, e.g. ``sshd``).")
    filename: str = Field(..., description="Actual filename (e.g. ``sshd.conf``).")
    enabled: bool = Field(
        ...,
        description=(
            "Whether the jail is enabled.  Derived from the ``enabled`` key "
            "inside the file; defaults to ``true`` when the key is absent."
        ),
    )


class JailConfigFilesResponse(BaseModel):
    """Response for ``GET /api/config/jail-files``."""

    model_config = ConfigDict(strict=True)

    files: list[JailConfigFile] = Field(default_factory=list)
    total: int = Field(..., ge=0)


class JailConfigFileContent(BaseModel):
    """Single jail config file with its raw content."""

    model_config = ConfigDict(strict=True)

    name: str = Field(..., description="Jail name (file stem).")
    filename: str = Field(..., description="Actual filename.")
    enabled: bool = Field(..., description="Whether the jail is enabled.")
    content: str = Field(..., description="Raw file content.")


class JailConfigFileEnabledUpdate(BaseModel):
    """Payload for ``PUT /api/config/jail-files/{filename}/enabled``."""

    model_config = ConfigDict(strict=True)

    enabled: bool = Field(..., description="New enabled state for this jail.")


# ---------------------------------------------------------------------------
# Generic conf-file entry (shared by filter.d and action.d)
# ---------------------------------------------------------------------------


class ConfFileEntry(BaseModel):
    """Metadata for a single ``.conf`` or ``.local`` file."""

    model_config = ConfigDict(strict=True)

    name: str = Field(..., description="Base name without extension (e.g. ``sshd``).")
    filename: str = Field(..., description="Actual filename (e.g. ``sshd.conf``).")


class ConfFilesResponse(BaseModel):
    """Response for list endpoints (``GET /api/config/filters`` and ``GET /api/config/actions``)."""

    model_config = ConfigDict(strict=True)

    files: list[ConfFileEntry] = Field(default_factory=list)
    total: int = Field(..., ge=0)


class ConfFileContent(BaseModel):
    """A conf file with its raw text content."""

    model_config = ConfigDict(strict=True)

    name: str = Field(..., description="Base name without extension.")
    filename: str = Field(..., description="Actual filename.")
    content: str = Field(..., description="Raw file content.")


class ConfFileUpdateRequest(BaseModel):
    """Payload for ``PUT /api/config/filters/{name}`` and ``PUT /api/config/actions/{name}``."""

    model_config = ConfigDict(strict=True)

    content: str = Field(..., description="New raw file content (must not exceed 512 KB).")


class ConfFileCreateRequest(BaseModel):
    """Payload for ``POST /api/config/filters`` and ``POST /api/config/actions``."""

    model_config = ConfigDict(strict=True)

    name: str = Field(
        ...,
        description="New file base name (without extension).  Must contain only "
        "alphanumeric characters, hyphens, underscores, and dots.",
    )
    content: str = Field(..., description="Initial raw file content (must not exceed 512 KB).")
