//
//  PasswordResetViewModelTests.swift
//  honeyDueTests
//
//  Unit tests for PasswordResetViewModel navigation, state management,
//  and client-side validation (no network calls).
//

import Testing
@testable import honeyDue

// MARK: - PasswordResetStep Tests

struct PasswordResetStepTests {

    @Test func allCasesHasFiveValues() {
        #expect(PasswordResetStep.allCases.count == 5)
    }

    @Test func allCasesContainsExpectedSteps() {
        let cases = PasswordResetStep.allCases
        #expect(cases.contains(.requestCode))
        #expect(cases.contains(.verifyCode))
        #expect(cases.contains(.resetPassword))
        #expect(cases.contains(.loggingIn))
        #expect(cases.contains(.success))
    }
}

// MARK: - Initialization Tests

@MainActor
struct PasswordResetViewModelInitTests {

    @Test func defaultInitStartsAtRequestCode() {
        let vm = PasswordResetViewModel()
        #expect(vm.currentStep == .requestCode)
        #expect(vm.resetToken == nil)
    }

    @Test func initWithTokenStartsAtResetPassword() {
        let vm = PasswordResetViewModel(resetToken: "abc123")
        #expect(vm.currentStep == .resetPassword)
        #expect(vm.resetToken == "abc123")
    }
}

// MARK: - Navigation Tests

@MainActor
struct PasswordResetViewModelNavigationTests {

    @Test func moveToNextStepFromRequestCode() {
        let vm = PasswordResetViewModel()
        vm.currentStep = .requestCode
        vm.moveToNextStep()
        #expect(vm.currentStep == .verifyCode)
    }

    @Test func moveToNextStepFromVerifyCode() {
        let vm = PasswordResetViewModel()
        vm.currentStep = .verifyCode
        vm.moveToNextStep()
        #expect(vm.currentStep == .resetPassword)
    }

    @Test func moveToNextStepFromResetPassword() {
        let vm = PasswordResetViewModel()
        vm.currentStep = .resetPassword
        vm.moveToNextStep()
        #expect(vm.currentStep == .loggingIn)
    }

    @Test func moveToNextStepFromLoggingIn() {
        let vm = PasswordResetViewModel()
        vm.currentStep = .loggingIn
        vm.moveToNextStep()
        #expect(vm.currentStep == .success)
    }

    @Test func moveToNextStepFromSuccessIsNoOp() {
        let vm = PasswordResetViewModel()
        vm.currentStep = .success
        vm.moveToNextStep()
        #expect(vm.currentStep == .success)
    }

    @Test func moveToPreviousStepFromVerifyCode() {
        let vm = PasswordResetViewModel()
        vm.currentStep = .verifyCode
        vm.moveToPreviousStep()
        #expect(vm.currentStep == .requestCode)
    }

    @Test func moveToPreviousStepFromResetPassword() {
        let vm = PasswordResetViewModel()
        vm.currentStep = .resetPassword
        vm.moveToPreviousStep()
        #expect(vm.currentStep == .verifyCode)
    }

    @Test func moveToPreviousStepFromRequestCodeIsNoOp() {
        let vm = PasswordResetViewModel()
        vm.currentStep = .requestCode
        vm.moveToPreviousStep()
        #expect(vm.currentStep == .requestCode)
    }

    @Test func moveToPreviousStepFromLoggingInIsNoOp() {
        let vm = PasswordResetViewModel()
        vm.currentStep = .loggingIn
        vm.moveToPreviousStep()
        #expect(vm.currentStep == .loggingIn)
    }

    @Test func moveToPreviousStepFromSuccessIsNoOp() {
        let vm = PasswordResetViewModel()
        vm.currentStep = .success
        vm.moveToPreviousStep()
        #expect(vm.currentStep == .success)
    }
}

// MARK: - Reset and Clear Tests

@MainActor
struct PasswordResetViewModelResetTests {

    @Test func resetClearsAllState() {
        let vm = PasswordResetViewModel()
        vm.email = "test@example.com"
        vm.code = "123456"
        vm.newPassword = "password123"
        vm.confirmPassword = "password123"
        vm.resetToken = "token"
        vm.errorMessage = "error"
        vm.successMessage = "success"
        vm.currentStep = .resetPassword
        vm.isLoading = true

        vm.reset()

        #expect(vm.email == "")
        #expect(vm.code == "")
        #expect(vm.newPassword == "")
        #expect(vm.confirmPassword == "")
        #expect(vm.resetToken == nil)
        #expect(vm.errorMessage == nil)
        #expect(vm.successMessage == nil)
        #expect(vm.currentStep == .requestCode)
        #expect(vm.isLoading == false)
    }

    @Test func clearErrorNilsOutErrorMessage() {
        let vm = PasswordResetViewModel()
        vm.errorMessage = "Something went wrong"
        vm.clearError()
        #expect(vm.errorMessage == nil)
    }

    @Test func clearSuccessNilsOutSuccessMessage() {
        let vm = PasswordResetViewModel()
        vm.successMessage = "Code sent!"
        vm.clearSuccess()
        #expect(vm.successMessage == nil)
    }
}

// MARK: - Client-Side Validation Tests (verifyResetCode / resetPassword gates)

@MainActor
struct PasswordResetViewModelValidationTests {

    @Test func verifyResetCodeWithEmptyCodeSetsError() {
        let vm = PasswordResetViewModel()
        vm.code = ""
        vm.verifyResetCode()
        #expect(vm.errorMessage == "Code is required")
    }

    @Test func verifyResetCodeWithNonNumericCodeSetsError() {
        let vm = PasswordResetViewModel()
        vm.code = "abcdef"
        vm.verifyResetCode()
        #expect(vm.errorMessage == "Code must be 6 digits")
    }

    @Test func resetPasswordWithEmptyPasswordSetsError() {
        let vm = PasswordResetViewModel()
        vm.newPassword = ""
        vm.resetPassword()
        #expect(vm.errorMessage == "Password is required")
    }

    @Test func resetPasswordWithWeakPasswordSetsError() {
        let vm = PasswordResetViewModel()
        vm.newPassword = "abcdefgh"  // no number
        vm.resetPassword()
        #expect(vm.errorMessage == "Password must contain at least one number")
    }

    @Test func resetPasswordWithMismatchedPasswordsSetsError() {
        let vm = PasswordResetViewModel()
        vm.newPassword = "abc12345"
        vm.confirmPassword = "xyz12345"
        vm.resetPassword()
        #expect(vm.errorMessage == "Passwords do not match")
    }

    @Test func resetPasswordWithNilTokenSetsError() {
        let vm = PasswordResetViewModel()
        vm.newPassword = "abc12345"
        vm.confirmPassword = "abc12345"
        vm.resetToken = nil
        vm.resetPassword()
        #expect(vm.errorMessage == "Invalid reset token. Please start over.")
    }
}
