package auth

import (
	"testing"
	"time"
)

func TestGenerateOTP(t *testing.T) {
	otp, otpStruct, err := GenerateOTP()
	if err != nil {
		t.Fatalf("GenerateOTP failed: %v", err)
	}

	if len(otp) != OTPLength {
		t.Errorf("Expected OTP length %d, got %d", OTPLength, len(otp))
	}

	// Verify OTP is numeric
	for _, ch := range otp {
		if ch < '0' || ch > '9' {
			t.Errorf("OTP contains non-digit character: %c", ch)
		}
	}

	if otpStruct.Hash == "" {
		t.Error("OTP hash is empty")
	}

	if otpStruct.Expiry.IsZero() {
		t.Error("OTP expiry is zero")
	}

	// Expiry should be in the future
	if !otpStruct.Expiry.After(time.Now()) {
		t.Error("OTP expiry is not in the future")
	}
}

func TestVerifyOTP(t *testing.T) {
	// Generate OTP
	otp, otpStruct, err := GenerateOTP()
	if err != nil {
		t.Fatalf("GenerateOTP failed: %v", err)
	}

	// Test valid OTP
	if !VerifyOTP(otp, otpStruct) {
		t.Error("Valid OTP verification failed")
	}

	// Test wrong OTP
	if VerifyOTP("000000", otpStruct) {
		t.Error("Wrong OTP verification should have failed")
	}

	// Test expired OTP
	expiredOTP := &OTP{
		Hash:   otpStruct.Hash,
		Expiry: time.Now().Add(-1 * time.Hour),
	}
	if VerifyOTP(otp, expiredOTP) {
		t.Error("Expired OTP verification should have failed")
	}

	// Test nil OTP
	if VerifyOTP(otp, nil) {
		t.Error("Nil OTP verification should have failed")
	}
}

func TestInMemoryOTPStore(t *testing.T) {
	store := NewInMemoryOTPStore()
	email := "test@example.com"
	otp := "123456"
	expiry := time.Now().Add(10 * time.Minute)

	// Store OTP
	err := store.StoreOTP(email, otp, expiry)
	if err != nil {
		t.Fatalf("StoreOTP failed: %v", err)
	}

	// Retrieve OTP
	retrievedOTP, retrievedExpiry, err := store.GetOTP(email)
	if err != nil {
		t.Fatalf("GetOTP failed: %v", err)
	}

	if retrievedOTP != otp {
		t.Errorf("Expected OTP %s, got %s", otp, retrievedOTP)
	}

	if !retrievedExpiry.Equal(expiry) {
		t.Errorf("Expected expiry %v, got %v", expiry, retrievedExpiry)
	}

	// Delete OTP
	err = store.DeleteOTP(email)
	if err != nil {
		t.Fatalf("DeleteOTP failed: %v", err)
	}

	// Try to retrieve deleted OTP
	_, _, err = store.GetOTP(email)
	if err == nil {
		t.Error("Expected error after deleting OTP")
	}
}

func TestSMTPSenderValidation(t *testing.T) {
	config := SMTPConfig{
		Host:     "smtp.example.com",
		Port:     "587",
		Username: "user@example.com",
		Password: "password",
		From:     "user@example.com",
	}

	err := config.ValidateConfig()
	if err != nil {
		t.Errorf("Valid config validation failed: %v", err)
	}

	// Test invalid configs
	invalidConfigs := []SMTPConfig{
		{Host: "", Port: "587", Username: "user", Password: "pass", From: "user"},
		{Host: "smtp.example.com", Port: "", Username: "user", Password: "pass", From: "user"},
		{Host: "smtp.example.com", Port: "587", Username: "", Password: "pass", From: "user"},
		{Host: "smtp.example.com", Port: "587", Username: "user", Password: "", From: "user"},
		{Host: "smtp.example.com", Port: "587", Username: "user", Password: "pass", From: ""},
	}

	for _, cfg := range invalidConfigs {
		if cfg.ValidateConfig() == nil {
			t.Errorf("Expected validation error for config: %+v", cfg)
		}
	}
}