package apps

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

// LoadPubKey reads a PEM-encoded SubjectPublicKeyInfo (the format
// `openssl pkey -pubout` emits) from path and returns the underlying
// Ed25519 public key.
//
// Operators distribute and configure this key explicitly — same posture
// as the TLS certificate: zddc-server bakes nothing in. Customers
// running against zddc.varasys.io's release channel download the
// canonical key from zddc.varasys.io/pubkey.pem and pass the local
// path via --apps-pubkey or ZDDC_APPS_PUBKEY. Customers running their
// own signing infrastructure pass their own public key instead.
//
// Returns a descriptive error for missing files, malformed PEM, wrong
// PEM type, or non-Ed25519 keys. Callers (cmd/zddc-server's startup
// path) treat any error as fatal — refusing to start with a misconfigured
// apps-pubkey is the right posture.
func LoadPubKey(path string) (ed25519.PublicKey, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("read apps-pubkey from %s: %w", path, err)
	}
	return ParsePubKeyPEM(data)
}

// ParsePubKeyPEM is LoadPubKey's content-only variant. Useful when the
// PEM bytes come from somewhere other than disk (test fixtures, etc.).
func ParsePubKeyPEM(pemBytes []byte) (ed25519.PublicKey, error) {
	block, _ := pem.Decode(pemBytes)
	if block == nil {
		return nil, errors.New("no PEM block found")
	}
	if block.Type != "PUBLIC KEY" {
		return nil, fmt.Errorf("unexpected PEM type %q (want PUBLIC KEY)", block.Type)
	}
	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, fmt.Errorf("parse PKIX: %w", err)
	}
	edPub, ok := pub.(ed25519.PublicKey)
	if !ok {
		return nil, fmt.Errorf("public key is not Ed25519 (got %T)", pub)
	}
	return edPub, nil
}

// VerifyEd25519 checks that sig is a valid Ed25519 signature of body
// produced with the private key matching pub. Returns nil on success
// or a descriptive error otherwise.
//
// sig must be exactly 64 bytes (the raw Ed25519 signature format
// produced by `openssl pkeyutl -sign -rawin`).
func VerifyEd25519(pub ed25519.PublicKey, body, sig []byte) error {
	if pub == nil {
		return errors.New("no public key configured")
	}
	if len(sig) != ed25519.SignatureSize {
		return fmt.Errorf("signature has wrong length: %d (want %d)", len(sig), ed25519.SignatureSize)
	}
	if !ed25519.Verify(pub, body, sig) {
		return errors.New("signature does not verify against trusted public key")
	}
	return nil
}
