"""Self-signed TLS certificate generation."""
from __future__ import annotations

import datetime as _dt
import ssl

from app.tls import cert_fingerprint_sha256, ensure_cert, generate_self_signed

_NOW = _dt.datetime(2026, 1, 1, tzinfo=_dt.timezone.utc)


def test_generate_writes_cert_and_key(tmp_path):
    cert = tmp_path / "cert.pem"
    key = tmp_path / "key.pem"
    fp = generate_self_signed(cert, key, now=_NOW)
    assert cert.exists() and key.exists()
    assert len(fp) == 64 and all(c in "0123456789abcdef" for c in fp)
    assert b"BEGIN CERTIFICATE" in cert.read_bytes()
    assert b"PRIVATE KEY" in key.read_bytes()


def test_fingerprint_matches_der(tmp_path):
    cert = tmp_path / "cert.pem"
    key = tmp_path / "key.pem"
    fp = generate_self_signed(cert, key, now=_NOW)
    assert cert_fingerprint_sha256(cert.read_bytes()) == fp


def test_cert_has_local_sans(tmp_path):
    from cryptography import x509
    cert = tmp_path / "cert.pem"
    key = tmp_path / "key.pem"
    generate_self_signed(cert, key, now=_NOW)
    parsed = x509.load_pem_x509_certificate(cert.read_bytes())
    san = parsed.extensions.get_extension_for_class(
        x509.SubjectAlternativeName).value
    dns = san.get_values_for_type(x509.DNSName)
    ips = [str(i) for i in san.get_values_for_type(x509.IPAddress)]
    assert "localhost" in dns
    assert "127.0.0.1" in ips


def test_cert_loads_as_ssl_context(tmp_path):
    """The generated pair must be usable by an SSL server context."""
    cert = tmp_path / "cert.pem"
    key = tmp_path / "key.pem"
    generate_self_signed(cert, key, now=_NOW)
    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    ctx.load_cert_chain(str(cert), str(key))  # raises on mismatch


def test_ensure_reuses_existing(tmp_path):
    cert = tmp_path / "cert.pem"
    key = tmp_path / "key.pem"
    fp1 = ensure_cert(cert, key, now=_NOW)
    fp2 = ensure_cert(cert, key, now=_NOW)
    assert fp1 == fp2  # not regenerated


def test_ensure_regenerates_on_missing_key(tmp_path):
    cert = tmp_path / "cert.pem"
    key = tmp_path / "key.pem"
    fp1 = ensure_cert(cert, key, now=_NOW)
    key.unlink()
    fp2 = ensure_cert(cert, key, now=_NOW)
    assert fp2 != fp1 and key.exists()


def test_ensure_regenerates_on_corrupt_cert(tmp_path):
    cert = tmp_path / "cert.pem"
    key = tmp_path / "key.pem"
    generate_self_signed(cert, key, now=_NOW)
    cert.write_bytes(b"not a certificate")
    fp = ensure_cert(cert, key, now=_NOW)
    assert len(fp) == 64
    assert b"BEGIN CERTIFICATE" in cert.read_bytes()
