// Package busauth bridges a unibus peer's Ed25519 identity to NATS nkey
// authentication. A NATS nkey IS an Ed25519 keypair, so the bus reuses the
// peer's existing signing identity for the data plane instead of minting new
// key material — one identity authenticates both planes (HTTP request signatures
// and NATS connections), keyed in the user allowlist by the same Ed25519 public
// key.
//
// This is transport glue specific to NATS + unibus, not a general-purpose
// registry primitive: it deliberately lives in the app to avoid pulling
// github.com/nats-io/nkeys into the multi-domain registry module. The Ed25519
// signing/verification it relies on comes from the registry cybersecurity
// package; this package never reimplements a primitive.
package busauth

import (
	"crypto/ed25519"
	"encoding/hex"
	"fmt"

	"github.com/nats-io/nkeys"
)

// ClientNkey derives, from a peer's Ed25519 private key, the NATS user nkey
// public string ("U...") and a signature callback suitable for
// nats.Nkey(pub, sign). The callback signs the server-presented nonce with the
// same Ed25519 key, so the server can verify it and map it back to the bus user.
//
// signPriv must be a 64-byte Ed25519 private key (as produced by the registry's
// GenerateIdentity). Its first 32 bytes are the seed nkeys needs.
func ClientNkey(signPriv []byte) (pub string, sign func([]byte) ([]byte, error), err error) {
	if len(signPriv) != ed25519.PrivateKeySize {
		return "", nil, fmt.Errorf("busauth: signPriv must be %d bytes, got %d", ed25519.PrivateKeySize, len(signPriv))
	}
	seed := ed25519.PrivateKey(signPriv).Seed() // 32-byte Ed25519 seed
	kp, err := nkeys.FromRawSeed(nkeys.PrefixByteUser, seed)
	if err != nil {
		return "", nil, fmt.Errorf("busauth: derive nkey from seed: %w", err)
	}
	pub, err = kp.PublicKey()
	if err != nil {
		return "", nil, fmt.Errorf("busauth: nkey public key: %w", err)
	}
	sign = func(nonce []byte) ([]byte, error) {
		return kp.Sign(nonce)
	}
	return pub, sign, nil
}

// NkeyPublicFromSignPub derives the NATS user nkey public string from a 32-byte
// Ed25519 public key. It is the inverse view of the identity used by callers
// that have only the public key (e.g. to display or pre-register an nkey).
func NkeyPublicFromSignPub(signPub []byte) (string, error) {
	if len(signPub) != ed25519.PublicKeySize {
		return "", fmt.Errorf("busauth: signPub must be %d bytes, got %d", ed25519.PublicKeySize, len(signPub))
	}
	pub, err := nkeys.Encode(nkeys.PrefixByteUser, signPub)
	if err != nil {
		return "", fmt.Errorf("busauth: encode nkey public: %w", err)
	}
	return string(pub), nil
}

// SignPubHexFromNkey decodes a NATS user nkey public string ("U...") back to the
// lowercase hex of its 32-byte Ed25519 public key — the identity key used to
// look a peer up in the bus user allowlist. The server calls this to map the
// nkey a client presented to the users table.
func SignPubHexFromNkey(nkeyPub string) (string, error) {
	raw, err := nkeys.Decode(nkeys.PrefixByteUser, []byte(nkeyPub))
	if err != nil {
		return "", fmt.Errorf("busauth: decode nkey %q: %w", nkeyPub, err)
	}
	if len(raw) != ed25519.PublicKeySize {
		return "", fmt.Errorf("busauth: decoded nkey is %d bytes, want %d", len(raw), ed25519.PublicKeySize)
	}
	return hex.EncodeToString(raw), nil
}
