"""Remediation configuration with security controls."""

from __future__ import annotations

from pathlib import Path
from typing import Annotated

from pydantic import BaseModel, ConfigDict, Field


class SignatureConfig(BaseModel):
    """Signature verification configuration for playbook bundles."""

    model_config = ConfigDict(frozen=True)

    # PEM-encoded public keys indexed by key_id
    # Example: {"key-2024": "-----BEGIN PUBLIC KEY-----\n..."}
    public_keys: dict[str, str] = Field(default_factory=dict)

    # Directory to load public keys from (each file is key_id.pem)
    # If set, keys are loaded from this directory on startup
    public_key_directory: Path | None = None

    # Allow fetching keys from server (requires TLS)
    allow_key_fetch: bool = False

    # URL to fetch keys from (only used if allow_key_fetch=True)
    key_fetch_url: str | None = None

    # Minimum key size in bits (for RSA) or curve size (for ECDSA)
    # ECDSA P-256 = 256 bits, RSA minimum recommended = 2048 bits
    min_rsa_key_size: int = 2048
    min_ecdsa_key_size: int = 256


class RemediationConfig(BaseModel):
    """Remediation configuration with security controls."""

    model_config = ConfigDict(frozen=True)

    # Feature toggle
    enabled: bool = False  # Disabled by default for safety

    # Polling intervals
    sync_interval: Annotated[float, Field(gt=0, le=3600)] = 300.0
    check_interval: Annotated[float, Field(gt=0, le=3600)] = 60.0

    # Concurrency and rate limits
    max_concurrent: Annotated[int, Field(ge=1, le=10)] = 1
    global_cooldown: Annotated[float, Field(ge=0, le=3600)] = 60.0
    max_remediations_per_hour: Annotated[int, Field(ge=1, le=100)] = 20

    # Security
    require_signature: bool = True
    dry_run: bool = False  # Log but don't execute

    # Signature verification configuration
    signature: SignatureConfig = Field(default_factory=SignatureConfig)

    # Path restrictions for log_pattern checks
    allowed_log_paths: list[str] = Field(
        default_factory=lambda: ["/var/log/**", "/opt/*/logs/**"]
    )

    # Host restrictions for HTTP checks (prevent SSRF)
    allowed_http_hosts: list[str] = Field(
        default_factory=lambda: ["localhost", "127.0.0.1"]
    )

    # Command restrictions (more strict than executor allowlist)
    detection_allowlist: list[str] = Field(
        default_factory=lambda: [
            "systemctl is-active *",
            "systemctl status *",
            "pgrep *",
            "curl -s http://localhost:*",
            "cat /var/log/**",
        ]
    )

    remediation_allowlist: list[str] = Field(
        default_factory=lambda: [
            "systemctl restart *",
            "systemctl start *",
            "systemctl stop *",
            "kill -HUP *",
        ]
    )


def load_public_keys_from_directory(directory: Path) -> dict[str, str]:
    """
    Load public keys from a directory.

    Each file should be named {key_id}.pem and contain a PEM-encoded public key.

    Args:
        directory: Directory containing .pem key files

    Returns:
        Dictionary mapping key_id to PEM-encoded public key

    Raises:
        ValueError: If directory doesn't exist or contains invalid keys
    """
    import structlog

    log = structlog.get_logger(__name__)

    if not directory.exists():
        raise ValueError(f"Public key directory does not exist: {directory}")

    if not directory.is_dir():
        raise ValueError(f"Public key path is not a directory: {directory}")

    keys: dict[str, str] = {}

    for pem_file in directory.glob("*.pem"):
        key_id = pem_file.stem  # filename without .pem extension

        try:
            key_content = pem_file.read_text().strip()

            # Basic validation that it looks like a PEM public key
            if "-----BEGIN PUBLIC KEY-----" not in key_content:
                log.warning(
                    "invalid_public_key_file",
                    file=str(pem_file),
                    reason="Missing PEM header",
                )
                continue

            if "-----END PUBLIC KEY-----" not in key_content:
                log.warning(
                    "invalid_public_key_file",
                    file=str(pem_file),
                    reason="Missing PEM footer",
                )
                continue

            keys[key_id] = key_content
            log.info("loaded_public_key", key_id=key_id, file=str(pem_file))

        except Exception as e:
            log.error(
                "failed_to_load_public_key",
                file=str(pem_file),
                error=str(e),
            )

    return keys
