package auth

import (
	"context"
	"crypto/rand"
	"database/sql"
	"errors"
	"math/big"
	"time"
)

// OTPStore مدیریت کدهای OTP در جدول otp_tokens.
type OTPStore struct {
	db  *sql.DB
	ttl time.Duration
}

func NewOTPStore(db *sql.DB, ttl time.Duration) *OTPStore {
	return &OTPStore{db: db, ttl: ttl}
}

// Generate یک کد ۵ رقمی امن می‌سازد (مطابق rand(10000,99999) در Laravel).
func Generate() string {
	n, err := rand.Int(rand.Reader, big.NewInt(90000))
	if err != nil {
		return "12345" // عملاً رخ نمی‌دهد
	}
	return big.NewInt(10000 + n.Int64()).String()
}

// Create کد را برای کاربر ذخیره می‌کند.
func (s *OTPStore) Create(ctx context.Context, userID int64, token string) error {
	_, err := s.db.ExecContext(ctx,
		`INSERT INTO otp_tokens (user_id, token) VALUES (?, ?)`, userID, token)
	return err
}

var ErrInvalidOTP = errors.New("token not valid")

// Verify اعتبار کد را در بازه ttl بررسی و پس از مصرف حذف می‌کند.
func (s *OTPStore) Verify(ctx context.Context, userID int64, token string) error {
	cutoff := time.Now().Add(-s.ttl).UTC().Format("2006-01-02 15:04:05")
	var id int64
	err := s.db.QueryRowContext(ctx,
		`SELECT id FROM otp_tokens
		 WHERE user_id = ? AND token = ? AND created_at > ?
		 ORDER BY id DESC LIMIT 1`, userID, token, cutoff).Scan(&id)
	if errors.Is(err, sql.ErrNoRows) {
		return ErrInvalidOTP
	}
	if err != nil {
		return err
	}
	// مصرف شد ⇒ حذف
	_, err = s.db.ExecContext(ctx, `DELETE FROM otp_tokens WHERE id = ?`, id)
	return err
}
