#!/usr/bin/env nu

# Generate TLS certificates for OCI registry

export def main [
    --registry-type: string = "zot"  # zot, harbor, distribution
    --domain: string = "localhost"
    --days: int = 365
] {
    print "🔒 Generating TLS certificates..."
    print $"   Registry type: ($registry_type)"
    print $"   Domain: ($domain)"
    print $"   Validity: ($days) days\n"

    let base_path = match $registry_type {
        "zot" => "./zot/certs"
        "harbor" => "./harbor/certs"
        "distribution" => "./distribution/certs"
        _ => {
            error make {msg: $"Unknown registry type: ($registry_type)"}
        }
    }

    # Create certs directory
    mkdir $base_path

    # Generate CA key and certificate
    print "📝 Generating CA certificate..."
    generate-ca $base_path $domain $days

    # Generate server key and certificate
    print "📝 Generating server certificate..."
    generate-server-cert $base_path $domain $days

    # Generate client certificates (optional)
    print "📝 Generating client certificate..."
    generate-client-cert $base_path $domain $days

    print "\n✅ Certificates generated successfully!"
    print $"\n📂 Certificate files in: ($base_path)"
    print "   ca.crt       - CA certificate"
    print "   ca.key       - CA private key"
    print "   server.crt   - Server certificate"
    print "   server.key   - Server private key"
    print "   client.crt   - Client certificate"
    print "   client.key   - Client private key"

    print "\n📋 Next steps:"
    print "1. Trust the CA certificate on your system:"
    print $"   - macOS: sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ($base_path)/ca.crt"
    print $"   - Linux: sudo cp ($base_path)/ca.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates"
    print "2. Restart the registry service"
    print "3. Test with: docker login --tls-verify https://($domain):5000"
}

def generate-ca [base_path: string, domain: string, days: int] {
    # Generate CA private key
    ^openssl genrsa -out $"($base_path)/ca.key" 4096

    # Generate CA certificate
    ^openssl req -new -x509 \
        -key $"($base_path)/ca.key" \
        -out $"($base_path)/ca.crt" \
        -days $days \
        -subj $"/C=US/ST=State/L=City/O=Provisioning/OU=CA/CN=($domain)-CA"

    print $"   ✓ CA certificate created: ($base_path)/ca.crt"
}

def generate-server-cert [base_path: string, domain: string, days: int] {
    # Generate server private key
    ^openssl genrsa -out $"($base_path)/server.key" 4096

    # Generate server CSR
    ^openssl req -new \
        -key $"($base_path)/server.key" \
        -out $"($base_path)/server.csr" \
        -subj $"/C=US/ST=State/L=City/O=Provisioning/OU=Registry/CN=($domain)"

    # Create SAN config
    let san_config = $"($base_path)/san.cnf"
    $"[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no

[req_distinguished_name]
C = US
ST = State
L = City
O = Provisioning
OU = Registry
CN = ($domain)

[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = ($domain)
DNS.2 = localhost
DNS.3 = *.($domain)
IP.1 = 127.0.0.1
IP.2 = 0.0.0.0" | save -f $san_config

    # Sign server certificate with CA
    ^openssl x509 -req \
        -in $"($base_path)/server.csr" \
        -CA $"($base_path)/ca.crt" \
        -CAkey $"($base_path)/ca.key" \
        -CAcreateserial \
        -out $"($base_path)/server.crt" \
        -days $days \
        -extensions v3_req \
        -extfile $san_config

    # Cleanup
    rm $"($base_path)/server.csr"
    rm $san_config

    print $"   ✓ Server certificate created: ($base_path)/server.crt"
}

def generate-client-cert [base_path: string, domain: string, days: int] {
    # Generate client private key
    ^openssl genrsa -out $"($base_path)/client.key" 4096

    # Generate client CSR
    ^openssl req -new \
        -key $"($base_path)/client.key" \
        -out $"($base_path)/client.csr" \
        -subj $"/C=US/ST=State/L=City/O=Provisioning/OU=Client/CN=provisioning-client"

    # Sign client certificate with CA
    ^openssl x509 -req \
        -in $"($base_path)/client.csr" \
        -CA $"($base_path)/ca.crt" \
        -CAkey $"($base_path)/ca.key" \
        -CAcreateserial \
        -out $"($base_path)/client.crt" \
        -days $days

    # Cleanup
    rm $"($base_path)/client.csr"

    print $"   ✓ Client certificate created: ($base_path)/client.crt"
}

# Verify certificates
export def "certs verify" [
    --registry-type: string = "zot"
] {
    let base_path = match $registry_type {
        "zot" => "./zot/certs"
        "harbor" => "./harbor/certs"
        "distribution" => "./distribution/certs"
        _ => {
            error make {msg: $"Unknown registry type: ($registry_type)"}
        }
    }

    print "🔍 Verifying certificates...\n"

    # Verify CA
    print "CA Certificate:"
    ^openssl x509 -in $"($base_path)/ca.crt" -noout -text | grep -E "Subject:|Issuer:|Not After"

    # Verify server cert
    print "\nServer Certificate:"
    ^openssl x509 -in $"($base_path)/server.crt" -noout -text | grep -E "Subject:|Issuer:|Not After|DNS:"

    # Verify server cert against CA
    print "\nVerifying server cert against CA:"
    let verify = (^openssl verify -CAfile $"($base_path)/ca.crt" $"($base_path)/server.crt" | complete)

    if $verify.exit_code == 0 {
        print "✅ Server certificate valid"
    } else {
        print "❌ Server certificate invalid"
    }
}

# Show certificate info
export def "certs info" [
    cert_file: string
] {
    if not ($cert_file | path exists) {
        error make {msg: $"Certificate file not found: ($cert_file)"}
    }

    ^openssl x509 -in $cert_file -noout -text
}
