package auth

import (
	"context"
	"crypto/rand"
	"errors"

	"github.com/go-webauthn/webauthn/webauthn"

	"github.com/operator/command-center/internal/secrets"
)

// userIDSecretKey is the canonical secrets-store key under which the operator's
// stable WebAuthn user.id is persisted. Generated on first registration,
// reused thereafter. The value is 32 random bytes (well above the spec's
// minimum) base64-encoded for the library's []byte signature.
const userIDSecretKey = "auth:user_id"

// User is the single operator. WebAuthn requires a user object for credential
// scoping; in a single-operator system the same User backs every ceremony.
type User struct {
	id          []byte
	name        string
	displayName string
	creds       []webauthn.Credential
}

func (u *User) WebAuthnID() []byte                         { return u.id }
func (u *User) WebAuthnName() string                       { return u.name }
func (u *User) WebAuthnDisplayName() string                { return u.displayName }
func (u *User) WebAuthnCredentials() []webauthn.Credential { return u.creds }

// LoadOrCreateUser returns the operator user with stored credentials
// attached. On first call (no user_id in secrets), it generates one.
func LoadOrCreateUser(ctx context.Context, store *secrets.Store, credStore *CredentialStore) (*User, error) {
	if store == nil || credStore == nil {
		return nil, errors.New("auth: nil store")
	}

	id, err := store.Get(ctx, userIDSecretKey)
	if errors.Is(err, secrets.ErrNotFound) {
		id = make([]byte, 32)
		if _, err := rand.Read(id); err != nil {
			return nil, err
		}
		if err := store.Set(ctx, userIDSecretKey, id); err != nil {
			return nil, err
		}
	} else if err != nil {
		return nil, err
	}

	creds, err := credStore.All(ctx)
	if err != nil {
		return nil, err
	}
	return &User{
		id:          id,
		name:        "operator",
		displayName: "Operator",
		creds:       creds,
	}, nil
}
