//
//  ValidationRulesTests.swift
//  honeyDueTests
//
//  Unit tests for ValidationError and ValidationRules (distinct from ValidationHelpers).
//

import Testing
@testable import honeyDue

// MARK: - ValidationError errorDescription Tests

struct ValidationErrorTests {

    @Test func requiredFieldErrorDescription() {
        let error = ValidationError.required(field: "Email")
        #expect(error.errorDescription == "Email is required")
    }

    @Test func invalidEmailErrorDescription() {
        let error = ValidationError.invalidEmail
        #expect(error.errorDescription == "Please enter a valid email address")
    }

    @Test func passwordTooShortErrorDescription() {
        let error = ValidationError.passwordTooShort(minLength: 8)
        #expect(error.errorDescription == "Password must be at least 8 characters")
    }

    @Test func passwordMismatchErrorDescription() {
        let error = ValidationError.passwordMismatch
        #expect(error.errorDescription == "Passwords do not match")
    }

    @Test func passwordMissingLetterErrorDescription() {
        let error = ValidationError.passwordMissingLetter
        #expect(error.errorDescription == "Password must contain at least one letter")
    }

    @Test func passwordMissingUppercaseErrorDescription() {
        let error = ValidationError.passwordMissingUppercase
        #expect(error.errorDescription == "Password must contain at least one uppercase letter")
    }

    @Test func passwordMissingLowercaseErrorDescription() {
        let error = ValidationError.passwordMissingLowercase
        #expect(error.errorDescription == "Password must contain at least one lowercase letter")
    }

    @Test func passwordMissingNumberErrorDescription() {
        let error = ValidationError.passwordMissingNumber
        #expect(error.errorDescription == "Password must contain at least one number")
    }

    @Test func invalidCodeErrorDescription() {
        let error = ValidationError.invalidCode(expectedLength: 6)
        #expect(error.errorDescription == "Code must be 6 digits")
    }

    @Test func invalidUsernameErrorDescription() {
        let error = ValidationError.invalidUsername
        #expect(error.errorDescription == "Username can only contain letters, numbers, and underscores")
    }

    @Test func customMessageErrorDescription() {
        let error = ValidationError.custom(message: "Something went wrong")
        #expect(error.errorDescription == "Something went wrong")
    }
}

// MARK: - Email Validation Tests

struct ValidationRulesEmailTests {

    @Test func emptyEmailReturnsRequired() {
        let error = ValidationRules.validateEmail("")
        #expect(error?.errorDescription == "Email is required")
    }

    @Test func whitespaceOnlyEmailReturnsRequired() {
        let error = ValidationRules.validateEmail("   ")
        #expect(error?.errorDescription == "Email is required")
    }

    @Test func invalidEmailReturnsInvalidEmail() {
        let error = ValidationRules.validateEmail("notanemail")
        #expect(error?.errorDescription == "Please enter a valid email address")
    }

    @Test func validEmailReturnsNil() {
        let error = ValidationRules.validateEmail("user@example.com")
        #expect(error == nil)
    }

    @Test func isValidEmailReturnsTrueForValid() {
        #expect(ValidationRules.isValidEmail("user@example.com"))
    }

    @Test func isValidEmailReturnsFalseForInvalid() {
        #expect(!ValidationRules.isValidEmail("notanemail"))
    }
}

// MARK: - Password Validation Tests

struct ValidationRulesPasswordTests {

    @Test func emptyPasswordReturnsRequired() {
        let error = ValidationRules.validatePassword("")
        #expect(error?.errorDescription == "Password is required")
    }

    @Test func shortPasswordReturnsTooShort() {
        let error = ValidationRules.validatePassword("abc")
        #expect(error?.errorDescription == "Password must be at least 8 characters")
    }

    @Test func validPasswordReturnsNil() {
        let error = ValidationRules.validatePassword("longpassword")
        #expect(error == nil)
    }

    @Test func exactMinLengthPasswordReturnsNil() {
        let error = ValidationRules.validatePassword("12345678")
        #expect(error == nil)
    }
}

// MARK: - Password Strength Tests

struct ValidationRulesPasswordStrengthTests {

    @Test func emptyPasswordReturnsRequired() {
        let error = ValidationRules.validatePasswordStrength("")
        #expect(error?.errorDescription == "Password is required")
    }

    @Test func noUppercaseReturnsMissingUppercase() {
        let error = ValidationRules.validatePasswordStrength("abc123")
        #expect(error?.errorDescription == "Password must contain at least one uppercase letter")
    }

    @Test func noLowercaseReturnsMissingLowercase() {
        let error = ValidationRules.validatePasswordStrength("ABC123")
        #expect(error?.errorDescription == "Password must contain at least one lowercase letter")
    }

    @Test func noNumberReturnsMissingNumber() {
        let error = ValidationRules.validatePasswordStrength("Abcdef")
        #expect(error?.errorDescription == "Password must contain at least one number")
    }

    @Test func uppercaseLowercaseAndNumberReturnsNil() {
        let error = ValidationRules.validatePasswordStrength("Abc123")
        #expect(error == nil)
    }

    @Test func isValidPasswordReturnsTrueForComplex() {
        #expect(ValidationRules.isValidPassword("Abc123"))
    }

    @Test func isValidPasswordReturnsFalseForLowercaseOnly() {
        #expect(!ValidationRules.isValidPassword("abcdef"))
    }

    @Test func isValidPasswordReturnsFalseForUppercaseOnly() {
        #expect(!ValidationRules.isValidPassword("ABCDEF"))
    }

    @Test func isValidPasswordReturnsFalseForNumbersOnly() {
        #expect(!ValidationRules.isValidPassword("123456"))
    }

    @Test func isValidPasswordReturnsFalseForNoUppercase() {
        #expect(!ValidationRules.isValidPassword("abc123"))
    }

    @Test func isValidPasswordReturnsFalseForNoLowercase() {
        #expect(!ValidationRules.isValidPassword("ABC123"))
    }

    @Test func isValidPasswordReturnsFalseForNoDigit() {
        #expect(!ValidationRules.isValidPassword("Abcdef"))
    }
}

// MARK: - Password Match Tests

struct ValidationRulesPasswordMatchTests {

    @Test func matchingPasswordsReturnsNil() {
        let error = ValidationRules.validatePasswordMatch("abc123", "abc123")
        #expect(error == nil)
    }

    @Test func mismatchedPasswordsReturnsMismatch() {
        let error = ValidationRules.validatePasswordMatch("abc123", "xyz789")
        #expect(error?.errorDescription == "Passwords do not match")
    }

    @Test func caseSensitiveMismatch() {
        let error = ValidationRules.validatePasswordMatch("Password", "password")
        #expect(error?.errorDescription == "Passwords do not match")
    }
}

// MARK: - Code Validation Tests

struct ValidationRulesCodeTests {

    @Test func emptyCodeReturnsRequired() {
        let error = ValidationRules.validateCode("")
        #expect(error?.errorDescription == "Code is required")
    }

    @Test func wrongLengthReturnsInvalidCode() {
        let error = ValidationRules.validateCode("123")
        #expect(error?.errorDescription == "Code must be 6 digits")
    }

    @Test func nonNumericCodeReturnsInvalidCode() {
        let error = ValidationRules.validateCode("abcdef")
        #expect(error?.errorDescription == "Code must be 6 digits")
    }

    @Test func validSixDigitCodeReturnsNil() {
        let error = ValidationRules.validateCode("123456")
        #expect(error == nil)
    }

    @Test func customLengthFourDigitCode() {
        let error = ValidationRules.validateCode("1234", expectedLength: 4)
        #expect(error == nil)
    }

    @Test func customLengthWrongDigitCount() {
        let error = ValidationRules.validateCode("123", expectedLength: 4)
        #expect(error?.errorDescription == "Code must be 4 digits")
    }
}

// MARK: - Username Validation Tests

struct ValidationRulesUsernameTests {

    @Test func emptyUsernameReturnsRequired() {
        let error = ValidationRules.validateUsername("")
        #expect(error?.errorDescription == "Username is required")
    }

    @Test func validAlphanumericUsernameReturnsNil() {
        let error = ValidationRules.validateUsername("john_doe123")
        #expect(error == nil)
    }

    @Test func usernameWithSpacesReturnsInvalid() {
        let error = ValidationRules.validateUsername("john doe")
        #expect(error?.errorDescription == "Username can only contain letters, numbers, and underscores")
    }

    @Test func usernameWithSpecialCharsReturnsInvalid() {
        let error = ValidationRules.validateUsername("user@name!")
        #expect(error?.errorDescription == "Username can only contain letters, numbers, and underscores")
    }
}

// MARK: - Required Field Validation Tests

struct ValidationRulesRequiredTests {

    @Test func emptyValueReturnsRequired() {
        let error = ValidationRules.validateRequired("", fieldName: "Name")
        #expect(error?.errorDescription == "Name is required")
    }

    @Test func whitespaceOnlyReturnsRequired() {
        let error = ValidationRules.validateRequired("   ", fieldName: "Name")
        #expect(error?.errorDescription == "Name is required")
    }

    @Test func nonEmptyReturnsNil() {
        let error = ValidationRules.validateRequired("hello", fieldName: "Name")
        #expect(error == nil)
    }

    @Test func isNotEmptyReturnsTrueForNonEmpty() {
        #expect(ValidationRules.isNotEmpty("hello"))
    }

    @Test func isNotEmptyReturnsFalseForEmpty() {
        #expect(!ValidationRules.isNotEmpty(""))
    }

    @Test func isNotEmptyReturnsFalseForWhitespace() {
        #expect(!ValidationRules.isNotEmpty("   "))
    }
}
