#!/usr/bin/python3

import os
import sys
from cryptography import x509
from cryptography.hazmat.primitives import hashes

path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
    sys.path.append(path)
import confluent.client as client

def removebmccacert(noderange, certid, cmd):
    for res in cmd.delete(f'/noderange/{noderange}/configuration/management_controller/certificate_authorities/{certid}'):
        print(repr(res))

def listbmccacerts(noderange, cmd):
    certids = []
    for res in cmd.read(f'/noderange/{noderange}/configuration/management_controller/certificate_authorities'):
        certids.append(res.get('item', {}).get('href', ''))
    for certid in certids:
        for res in cmd.read(f'/noderange/{noderange}/configuration/management_controller/certificate_authorities/{certid}'):
            for node in res.get('databynode', {}):
                certdata = res['databynode'][node].get('pem', {}).get('value', '')
                summary = ''
                if not certdata:
                    continue
                san = res['databynode'][node].get('san', {}).get('value', '')
                if san:
                    summary += f" SANs: {san}"
                subject = res['databynode'][node].get('subject', {}).get('value', '')
                if subject:
                    summary = subject
                try:
                    cert = x509.load_pem_x509_certificate(certdata.encode())
                    sha256 = cert.fingerprint(hashes.SHA256()).hex().upper()
                except Exception as e:
                    print(f"Error processing certificate for {node}: {e}", file=sys.stderr)
                    continue
                summary += f" (SHA256={sha256})"
                print(f"{node}: {certid}: {summary}")

def installbmccacert(noderange, certfile, cmd):
    if certfile:
        try:
            with open(certfile, 'r') as f:
                certdata = f.read()
        except Exception as e:
            print(f"Error reading certificate file: {e}", file=sys.stderr)
            sys.exit(1)

        # Simple validation: check if it starts and ends with the correct PEM markers
        if not (certdata.startswith("-----BEGIN CERTIFICATE-----") and certdata.strip().endswith("-----END CERTIFICATE-----")):
            print("Invalid certificate format. Must be a PEM encoded certificate.", file=sys.stderr)
            sys.exit(1)
        payload = {'pem': certdata}
        for res in cmd.update(f'/noderange/{noderange}/configuration/management_controller/certificate_authorities', payload):
            print(repr(res))

    

if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser(description='Node certificate utility')
    parser.add_argument('noderange', help='Node range to operate on')
    subparsers = parser.add_subparsers(dest='command', help='Available commands')

    # installbmccacert subcommand
    install_parser = subparsers.add_parser('installbmccacert', help='Install BMC CA certificate')
    install_parser.add_argument('filename', help='Certificate file to install')

    remove_parser = subparsers.add_parser('removebmccacert', help='Remove BMC CA certificate')
    remove_parser.add_argument('id', help='Certificate id to remove')

    list_parser = subparsers.add_parser('listbmccacerts', help='List BMC CA certificates')

    sign_bmc_parser = subparsers.add_parser('signbmccert', help='Sign BMC certificate')
    sign_bmc_parser.add_argument('--days', type=int, help='Number of days the certificate is valid for')
    sign_bmc_parser.add_argument('--added-names', type=str, help='Additional names to include in the certificate')

    args = parser.parse_args()
    c = client.Command()
    if args.command == 'installbmccacert':
        installbmccacert(args.noderange, args.filename, c)
    elif args.command == 'removebmccacert':
        removebmccacert(args.noderange, args.id, c)
    elif args.command == 'listbmccacerts':
        listbmccacerts(args.noderange, c)
    elif args.command == 'signbmccert':
        payload = {}
        if args.days is not None:
            payload['days'] = args.days
        else:
            print("Error: --days is required for signbmccert", file=sys.stderr)
            sys.exit(1)
        if args.added_names:
            payload['added_names'] = args.added_names
        for res in c.update(f'/noderange/{args.noderange}/configuration/management_controller/certificate/sign', payload):
            print(repr(res))
    else:
        parser.print_help()
        sys.exit(1)