package security

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"fmt"
	"net"
)

// GenerateCSR mints a new RSA private key, builds a CSR with the given
// commonName and SANs (DNS or IP entries), and returns the key + CSR in
// PEM form. The private key is RSA 3072 (matches CAKeySize).
//
// REQ-036: server certs MUST have at least one DNS or IP SAN. This function
// enforces that constraint — calling with empty sans returns an error.
//
// Validation: dns entries must be syntactically valid hostnames; ip entries
// must be parseable by net.ParseIP. Bad inputs are rejected up-front so
// the operator gets a clear error before signing.
//
// Deprecated: v0.9 re-architecture replaces the internal CA with step-ca
// (D-101/REQ-076). GenerateCSR is retained for the dual-write window and
// scheduled for deletion in v0.10-P14. See .ciagent/PRD_v0.9.md.
func GenerateCSR(commonName string, sans []string) (keyPEM, csrPEM []byte, err error) {
	if commonName == "" {
		return nil, nil, errors.New("GenerateCSR: commonName is required")
	}
	if len(sans) == 0 {
		return nil, nil, errors.New("GenerateCSR: at least one DNS or IP SAN is required (REQ-036)")
	}

	dnsNames := make([]string, 0, len(sans))
	ipAddrs := make([]net.IP, 0, len(sans))
	for _, s := range sans {
		if s == "" {
			return nil, nil, errors.New("GenerateCSR: empty SAN entry")
		}
		if ip := net.ParseIP(s); ip != nil {
			ipAddrs = append(ipAddrs, ip)
			continue
		}
		// Treat as a DNS name. Validate it parses and is not a host:port form.
		if _, _, err := net.SplitHostPort(s); err == nil {
			return nil, nil, fmt.Errorf("GenerateCSR: SAN %q looks like host:port; use a bare hostname or IP", s)
		}
		dnsNames = append(dnsNames, s)
	}
	if len(dnsNames) == 0 && len(ipAddrs) == 0 {
		return nil, nil, errors.New("GenerateCSR: at least one valid DNS or IP SAN is required (REQ-036)")
	}

	key, err := rsa.GenerateKey(rand.Reader, CAKeySize)
	if err != nil {
		return nil, nil, fmt.Errorf("GenerateCSR: generate key: %w", err)
	}
	csr := &x509.CertificateRequest{
		Subject: pkix.Name{
			CommonName:   commonName,
			Organization: []string{"orca"},
		},
		DNSNames:    dnsNames,
		IPAddresses: ipAddrs,
	}
	csrDER, err := x509.CreateCertificateRequest(rand.Reader, csr, key)
	if err != nil {
		return nil, nil, fmt.Errorf("GenerateCSR: create CSR: %w", err)
	}

	keyDER, err := x509.MarshalPKCS8PrivateKey(key)
	if err != nil {
		return nil, nil, fmt.Errorf("GenerateCSR: marshal key: %w", err)
	}
	keyPEM = pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: keyDER})
	csrPEM = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrDER})
	return keyPEM, csrPEM, nil
}
