#!/usr/bin/env python3
"""Certificate Authority management agent using OpenSSL and cryptography library."""

import json
import sys
import argparse
from datetime import datetime

try:
    from cryptography import x509
    from cryptography.x509.oid import NameOID
    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.primitives.asymmetric import rsa
    from datetime import timedelta
except ImportError:
    print("Install: pip install cryptography")
    sys.exit(1)


def generate_ca_certificate(cn="Internal Root CA", org="Organization", days=3650):
    """Generate a self-signed root CA certificate."""
    key = rsa.generate_private_key(public_exponent=65537, key_size=4096)
    subject = issuer = x509.Name([
        x509.NameAttribute(NameOID.COMMON_NAME, cn),
        x509.NameAttribute(NameOID.ORGANIZATION_NAME, org),
    ])
    cert = (x509.CertificateBuilder()
            .subject_name(subject)
            .issuer_name(issuer)
            .public_key(key.public_key())
            .serial_number(x509.random_serial_number())
            .not_valid_before(datetime.utcnow())
            .not_valid_after(datetime.utcnow() + timedelta(days=days))
            .add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
            .add_extension(x509.KeyUsage(digital_signature=True, key_cert_sign=True,
                                          crl_sign=True, content_commitment=False,
                                          key_encipherment=False, data_encipherment=False,
                                          key_agreement=False, encipher_only=False,
                                          decipher_only=False), critical=True)
            .sign(key, hashes.SHA256()))
    return cert, key


def generate_server_cert(ca_cert, ca_key, cn, san_names, days=365):
    """Generate a server certificate signed by the CA."""
    key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
    subject = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])
    san = x509.SubjectAlternativeName([x509.DNSName(n) for n in san_names])
    cert = (x509.CertificateBuilder()
            .subject_name(subject)
            .issuer_name(ca_cert.subject)
            .public_key(key.public_key())
            .serial_number(x509.random_serial_number())
            .not_valid_before(datetime.utcnow())
            .not_valid_after(datetime.utcnow() + timedelta(days=days))
            .add_extension(san, critical=False)
            .add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True)
            .sign(ca_key, hashes.SHA256()))
    return cert, key


def audit_certificate(cert_path):
    """Audit an existing certificate for security issues."""
    with open(cert_path, "rb") as f:
        cert_data = f.read()
    cert = x509.load_pem_x509_certificate(cert_data)
    issues = []
    if cert.public_key().key_size < 2048:
        issues.append({"issue": "Weak key size", "severity": "HIGH",
                        "detail": f"Key size {cert.public_key().key_size} < 2048"})
    if cert.not_valid_after_utc.replace(tzinfo=None) < datetime.utcnow():
        issues.append({"issue": "Certificate expired", "severity": "CRITICAL",
                        "detail": f"Expired on {cert.not_valid_after_utc}"})
    days_remaining = (cert.not_valid_after_utc.replace(tzinfo=None) - datetime.utcnow()).days
    if 0 < days_remaining < 30:
        issues.append({"issue": "Certificate expiring soon", "severity": "HIGH",
                        "detail": f"{days_remaining} days remaining"})
    sig_algo = cert.signature_hash_algorithm
    if sig_algo and sig_algo.name in ("sha1", "md5"):
        issues.append({"issue": f"Weak signature algorithm: {sig_algo.name}", "severity": "HIGH"})
    return {
        "subject": cert.subject.rfc4514_string(),
        "issuer": cert.issuer.rfc4514_string(),
        "not_before": str(cert.not_valid_before_utc),
        "not_after": str(cert.not_valid_after_utc),
        "key_size": cert.public_key().key_size,
        "serial": cert.serial_number,
        "issues": issues,
    }


def run_audit(cert_path=None, generate=False, cn=None, org=None):
    """Execute CA operations."""
    print(f"\n{'='*60}")
    print(f"  CERTIFICATE AUTHORITY AGENT")
    print(f"  Generated: {datetime.utcnow().isoformat()} UTC")
    print(f"{'='*60}\n")

    if cert_path:
        info = audit_certificate(cert_path)
        print(f"--- CERTIFICATE AUDIT ---")
        print(f"  Subject: {info['subject']}")
        print(f"  Issuer: {info['issuer']}")
        print(f"  Valid: {info['not_before']} to {info['not_after']}")
        print(f"  Key Size: {info['key_size']}")
        print(f"  Issues: {len(info['issues'])}")
        for i in info["issues"]:
            print(f"    [{i['severity']}] {i['issue']}: {i.get('detail', '')}")
        return info

    if generate:
        cert, key = generate_ca_certificate(cn=cn or "Internal Root CA", org=org or "Org")
        print(f"--- CA CERTIFICATE GENERATED ---")
        print(f"  Subject: {cert.subject.rfc4514_string()}")
        print(f"  Serial: {cert.serial_number}")
        return {"status": "generated", "subject": cert.subject.rfc4514_string()}

    return {}


def main():
    parser = argparse.ArgumentParser(description="Certificate Authority Agent")
    parser.add_argument("--audit", help="Path to PEM certificate to audit")
    parser.add_argument("--generate", action="store_true", help="Generate new CA")
    parser.add_argument("--cn", help="Common name for CA cert")
    parser.add_argument("--org", help="Organization name")
    parser.add_argument("--output", help="Save report to JSON file")
    args = parser.parse_args()

    report = run_audit(args.audit, args.generate, args.cn, args.org)
    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2, default=str)
        print(f"\n[+] Report saved to {args.output}")


if __name__ == "__main__":
    main()
