package security

import (
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"fmt"
	"os"
)

// Fingerprint returns the SHA-256 hex digest of the certificate's DER bytes,
// computed from the on-disk PEM at certPath. The output is lowercase hex
// (64 chars) and matches the value operators see with `openssl x509 -fingerprint
// -sha256 -noout`. Used for the `orca node join --ca-fingerprint <sha>` pin.
func Fingerprint(certPath string) (string, error) {
	if certPath == "" {
		return "", errors.New("Fingerprint: certPath is required")
	}
	pemBytes, err := os.ReadFile(certPath)
	if err != nil {
		return "", fmt.Errorf("Fingerprint: read cert: %w", err)
	}
	der, err := firstCertDER(pemBytes)
	if err != nil {
		return "", fmt.Errorf("Fingerprint: %w", err)
	}
	return FingerprintOf(der), nil
}

// FingerprintOf returns the SHA-256 hex digest of a DER-encoded certificate.
// Lowercase hex; matches `openssl ... -fingerprint -sha256` output.
func FingerprintOf(der []byte) string {
	sum := sha256.Sum256(der)
	return hex.EncodeToString(sum[:])
}

// firstCertDER decodes PEM bytes and returns the DER of the first
// CERTIFICATE block. Errors if the input is empty or no CERTIFICATE block
// is present.
func firstCertDER(pemBytes []byte) ([]byte, error) {
	if len(pemBytes) == 0 {
		return nil, errors.New("empty input")
	}
	block, _ := pem.Decode(pemBytes)
	if block == nil {
		return nil, errors.New("no PEM data found")
	}
	if block.Type != "CERTIFICATE" {
		return nil, fmt.Errorf("unexpected PEM type %q, want CERTIFICATE", block.Type)
	}
	// Re-parse through x509 to validate the cert is well-formed.
	if _, err := x509.ParseCertificate(block.Bytes); err != nil {
		return nil, fmt.Errorf("parse certificate: %w", err)
	}
	return block.Bytes, nil
}
