package auth

import (
	"bytes"
	"image/png"
	"time"

	"github.com/pquerna/otp"
	"github.com/pquerna/otp/totp"
)

// GenerateSecret creates a new TOTP secret for the given user.
// Returns the base32-encoded secret, the otpauth:// URL, and a QR code as PNG bytes.
func GenerateSecret(username, issuer string) (secret string, otpauthURL string, qrPNG []byte, err error) {
	key, err := totp.Generate(totp.GenerateOpts{
		Issuer:      issuer,
		AccountName: username,
		SecretSize:  20,
		Algorithm:   otp.AlgorithmSHA1,
		Digits:      otp.DigitsSix,
		Period:      30,
	})
	if err != nil {
		return "", "", nil, err
	}
	secret = key.Secret()
	otpauthURL = key.URL()

	img, err := key.Image(200, 200)
	if err != nil {
		return secret, otpauthURL, nil, nil // QR code is optional
	}
	var buf bytes.Buffer
	if encErr := png.Encode(&buf, img); encErr == nil {
		qrPNG = buf.Bytes()
	}
	return secret, otpauthURL, qrPNG, nil
}

// ValidateTOTP checks whether the given code is valid for the base32 secret.
// Allows +/- 1 time step (30s) tolerance.
func ValidateTOTP(secret, code string) bool {
	valid, err := totp.ValidateCustom(code, secret, time.Now().UTC(), totp.ValidateOpts{
		Period:    30,
		Skew:     1,
		Digits:   otp.DigitsSix,
		Algorithm: otp.AlgorithmSHA1,
	})
	return err == nil && valid
}
