"""mTLS (Mutual TLS) support for Enterprise tier.

Provides client certificate authentication for the WebSocket connection
to the qRunX Executor Gateway.  When enabled, both sides verify each
other's certificates (mutual authentication).

Configuration via environment variables:
  QRAPTOR_MTLS_ENABLED=true
  QRAPTOR_MTLS_CERT_FILE=/path/to/client.crt
  QRAPTOR_MTLS_KEY_FILE=/path/to/client.key
  QRAPTOR_MTLS_CA_FILE=/path/to/ca.crt  (optional, for pinning the server CA)
"""

from __future__ import annotations

import logging
import os
import ssl
from pathlib import Path

logger = logging.getLogger("qremotex.mtls")


class MTLSConfig:
    """mTLS configuration loaded from environment variables."""

    def __init__(self) -> None:
        self.enabled: bool = os.environ.get("QRAPTOR_MTLS_ENABLED", "false").lower() == "true"
        self.cert_file: str | None = os.environ.get("QRAPTOR_MTLS_CERT_FILE")
        self.key_file: str | None = os.environ.get("QRAPTOR_MTLS_KEY_FILE")
        self.ca_file: str | None = os.environ.get("QRAPTOR_MTLS_CA_FILE")

    def validate(self) -> list[str]:
        """Return a list of config errors (empty = valid)."""
        if not self.enabled:
            return []
        errors: list[str] = []
        if not self.cert_file:
            errors.append("QRAPTOR_MTLS_CERT_FILE is required when mTLS is enabled")
        elif not Path(self.cert_file).is_file():
            errors.append(f"QRAPTOR_MTLS_CERT_FILE not found: {self.cert_file}")
        if not self.key_file:
            errors.append("QRAPTOR_MTLS_KEY_FILE is required when mTLS is enabled")
        elif not Path(self.key_file).is_file():
            errors.append(f"QRAPTOR_MTLS_KEY_FILE not found: {self.key_file}")
        if self.ca_file and not Path(self.ca_file).is_file():
            errors.append(f"QRAPTOR_MTLS_CA_FILE not found: {self.ca_file}")
        return errors


def build_ssl_context(mtls_config: MTLSConfig) -> ssl.SSLContext | None:
    """Build an SSL context for the WebSocket connection.

    Returns None if mTLS is disabled (aiohttp will use default TLS).
    Returns a configured SSLContext if mTLS is enabled.
    """
    if not mtls_config.enabled:
        return None

    errors = mtls_config.validate()
    if errors:
        raise ValueError(f"mTLS configuration errors: {'; '.join(errors)}")

    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)

    # Enforce TLS 1.2+ (per security checklist)
    ctx.minimum_version = ssl.TLSVersion.TLSv1_2

    # Load client certificate + private key
    ctx.load_cert_chain(
        certfile=mtls_config.cert_file,  # type: ignore[arg-type]
        keyfile=mtls_config.key_file,     # type: ignore[arg-type]
    )

    # Load CA bundle for server verification
    if mtls_config.ca_file:
        ctx.load_verify_locations(cafile=mtls_config.ca_file)
    else:
        # Use system default CAs
        ctx.load_default_certs()

    ctx.verify_mode = ssl.CERT_REQUIRED
    ctx.check_hostname = True

    logger.info(
        "mTLS enabled: cert=%s ca=%s",
        mtls_config.cert_file,
        mtls_config.ca_file or "system-default",
    )
    return ctx
