import XCTest

/// Comprehensive registration flow tests with strict, failure-first assertions
/// Tests verify both positive AND negative conditions to ensure robust validation
final class Suite1_RegistrationTests: BaseUITestCase {
    override var completeOnboarding: Bool { true }
    override var relaunchBetweenTests: Bool { true }


    // Test user credentials - using timestamp to ensure unique users
    private var testUsername: String {
        return "testuser_\(Int(Date().timeIntervalSince1970))"
    }
    private var testEmail: String {
        return "test_\(Int(Date().timeIntervalSince1970))@example.com"
    }
    private let testPassword = "Pass1234"

    /// Fixed test verification code - Go API uses this code when DEBUG=true
    private let testVerificationCode = "123456"

    override func setUpWithError() throws {
        // Force clean app launch — registration tests leave sheet state that persists
        app.terminate()
        try super.setUpWithError()

        let loginScreen = app.textFields[AccessibilityIdentifiers.Authentication.usernameField]
        if !loginScreen.waitForExistence(timeout: 3) {
            ensureLoggedOut()
        }
        XCTAssertTrue(loginScreen.waitForExistence(timeout: 10), "PRECONDITION FAILED: Must start on login screen")
    }

    override func tearDownWithError() throws {
        ensureLoggedOut()
        try super.tearDownWithError()
    }

    // MARK: - Strict Helper Methods

    private func ensureLoggedOut() {
        UITestHelpers.ensureLoggedOut(app: app)
    }

    /// Navigate to registration screen with strict verification
    /// Note: Registration is presented as a sheet, so login screen elements still exist underneath
    private func navigateToRegistration() {
            let welcomeText = app.textFields[AccessibilityIdentifiers.Authentication.usernameField]
            XCTAssertTrue(welcomeText.exists, "PRECONDITION: Must be on login screen to navigate to registration")

            let signUpButton = app.buttons[AccessibilityIdentifiers.Authentication.signUpButton].firstMatch
            XCTAssertTrue(signUpButton.waitForExistence(timeout: 5), "Sign Up button must exist on login screen")

            // Sign Up button may be offscreen at bottom of ScrollView
            if !signUpButton.isHittable {
                let scrollView = app.scrollViews.firstMatch
                if scrollView.exists {
                    signUpButton.scrollIntoView(in: scrollView)
                }
            }

            signUpButton.tap()
            
            // STRICT: Verify registration screen appeared (shown as sheet)
            // Note: Login screen still exists underneath the sheet, so we verify registration elements instead
            let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
            XCTAssertTrue(usernameField.waitForExistence(timeout: 5), "Registration username field must appear")
            XCTAssertTrue(waitForElementToBeHittable(usernameField, timeout: 5), "Registration username field must be tappable")

            // Keep action buttons visible for strict assertions and interactions.
            let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
            if createAccountButton.exists && !createAccountButton.isHittable {
                let scrollView = app.scrollViews.firstMatch
                if scrollView.exists {
                    createAccountButton.scrollIntoView(in: scrollView, maxSwipes: 5)
                }
            }
            
            // STRICT: The Sign Up button should no longer be hittable (covered by sheet)
            XCTAssertFalse(signUpButton.isHittable, "Login Sign Up button should be covered by registration sheet")
    }

    /// Dismisses iOS Strong Password suggestion overlay
    private func dismissStrongPasswordSuggestion() {
        let chooseOwnPassword = app.buttons["Choose My Own Password"]
        if chooseOwnPassword.waitForExistence(timeout: 1) {
            chooseOwnPassword.tap()
            return
        }

        let notNowButton = app.buttons["Not Now"]
        if notNowButton.exists && notNowButton.isHittable {
            notNowButton.tap()
            return
        }

        // Dismiss by tapping elsewhere
        let strongPasswordText = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Strong Password'")).firstMatch
        if strongPasswordText.exists {
            app.tap()
        }
    }

    /// Wait for element to disappear - CRITICAL for strict testing
    private func waitForElementToDisappear(_ element: XCUIElement, timeout: TimeInterval) -> Bool {
        let expectation = XCTNSPredicateExpectation(
            predicate: NSPredicate(format: "exists == false"),
            object: element
        )
        let result = XCTWaiter.wait(for: [expectation], timeout: timeout)
        return result == .completed
    }

    /// Wait for element to become hittable (visible AND interactive)
    private func waitForElementToBeHittable(_ element: XCUIElement, timeout: TimeInterval) -> Bool {
        let expectation = XCTNSPredicateExpectation(
            predicate: NSPredicate(format: "isHittable == true"),
            object: element
        )
        let result = XCTWaiter.wait(for: [expectation], timeout: timeout)
        return result == .completed
    }

    /// Verification screen readiness check based on stable accessibility IDs.
    private func waitForVerificationScreen(timeout: TimeInterval) -> Bool {
        let authCodeField = app.textFields[AccessibilityIdentifiers.Authentication.verificationCodeField]
        let onboardingCodeField = app.textFields[AccessibilityIdentifiers.Onboarding.verificationCodeField]
        let authVerifyButton = app.buttons[AccessibilityIdentifiers.Authentication.verifyButton]
        let onboardingVerifyButton = app.buttons[AccessibilityIdentifiers.Onboarding.verifyButton]
        return authCodeField.waitForExistence(timeout: timeout)
            || onboardingCodeField.waitForExistence(timeout: timeout)
            || authVerifyButton.waitForExistence(timeout: timeout)
            || onboardingVerifyButton.waitForExistence(timeout: timeout)
    }

    private func verificationCodeField() -> XCUIElement {
        let authCodeField = app.textFields[AccessibilityIdentifiers.Authentication.verificationCodeField]
        if authCodeField.exists {
            return authCodeField
        }
        return app.textFields[AccessibilityIdentifiers.Onboarding.verificationCodeField]
    }

    private func verificationButton() -> XCUIElement {
        let authVerifyButton = app.buttons[AccessibilityIdentifiers.Authentication.verifyButton]
        if authVerifyButton.exists {
            return authVerifyButton
        }
        let onboardingVerifyButton = app.buttons[AccessibilityIdentifiers.Onboarding.verifyButton]
        if onboardingVerifyButton.exists {
            return onboardingVerifyButton
        }
        return app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Verify'")).firstMatch
    }

    /// Submit the registration form after filling it. Uses keyboard "Go" button
    /// or falls back to dismissing keyboard and tapping the register button.
    private func submitRegistrationForm() {
        let goButton = app.keyboards.buttons["Go"]
        if goButton.waitForExistence(timeout: 2) && goButton.isHittable {
            goButton.tap()
            return
        }
        // Fallback: dismiss keyboard, then tap register button
        dismissKeyboard()
        let registerButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
        registerButton.waitForExistenceOrFail(timeout: 5)
        if !registerButton.isHittable {
            let scrollView = app.scrollViews.firstMatch
            if scrollView.exists { registerButton.scrollIntoView(in: scrollView) }
        }
        registerButton.forceTap()
    }

    /// Dismiss keyboard safely by tapping a neutral area.
    private func dismissKeyboard() {
        guard app.keyboards.firstMatch.exists else { return }
        // Try toolbar Done button first
        let doneButton = app.toolbars.buttons["Done"]
        if doneButton.exists && doneButton.isHittable {
            doneButton.tap()
            _ = app.keyboards.firstMatch.waitForNonExistence(timeout: 2)
            return
        }
        // Try navigation bar (works on most screens)
        let navBar = app.navigationBars.firstMatch
        if navBar.exists && navBar.isHittable {
            navBar.tap()
            _ = app.keyboards.firstMatch.waitForNonExistence(timeout: 2)
            return
        }
        // Fallback: tap top-center of the app
        app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.1)).tap()
        _ = app.keyboards.firstMatch.waitForNonExistence(timeout: 2)
    }

    /// Fill registration form with given credentials.
    /// Uses Return key (\n) to trigger SwiftUI's .onSubmit / @FocusState field
    /// transitions. Direct field taps fail on iOS 26 when transitioning from
    /// TextField to SecureTextField (keyboard never appears).
    private func fillRegistrationForm(username: String, email: String, password: String, confirmPassword: String) {
        // iOS 26 bug: SecureTextField won't gain keyboard focus when tapped directly.
        // Workaround: toggle password visibility first to convert SecureField → TextField.
        let scrollView = app.scrollViews.firstMatch
        if scrollView.exists { scrollView.swipeUp() }

        let toggleButtons = app.buttons.matching(NSPredicate(format: "label == 'Toggle password visibility'"))
        for i in 0..<toggleButtons.count {
            let toggle = toggleButtons.element(boundBy: i)
            if toggle.exists && toggle.isHittable { toggle.tap() }
        }

        // Don't swipeDown — it dismisses the sheet. focusAndType() auto-scrolls via tap().
        let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
        let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
        let passwordField = app.textFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
        let confirmPasswordField = app.textFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]

        usernameField.focusAndType(username, app: app)
        emailField.focusAndType(email, app: app)
        passwordField.focusAndType(password, app: app)
        confirmPasswordField.focusAndType(confirmPassword, app: app)
    }

    // MARK: - 1. UI/Element Tests (no backend, pure UI verification)

    func test01_registrationScreenElements() {
        navigateToRegistration()

        // STRICT: All form elements must exist AND be hittable
        let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
        let emailField = app.textFields[AccessibilityIdentifiers.Authentication.registerEmailField]
        let passwordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerPasswordField]
        let confirmPasswordField = app.secureTextFields[AccessibilityIdentifiers.Authentication.registerConfirmPasswordField]
        let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
        let cancelButton = app.buttons[AccessibilityIdentifiers.Authentication.registerCancelButton]

        XCTAssertTrue(usernameField.exists && usernameField.isHittable, "Username field must be visible and tappable")
        XCTAssertTrue(emailField.exists && emailField.isHittable, "Email field must be visible and tappable")
        XCTAssertTrue(passwordField.exists && passwordField.isHittable, "Password field must be visible and tappable")
        XCTAssertTrue(confirmPasswordField.exists && confirmPasswordField.isHittable, "Confirm password field must be visible and tappable")
        XCTAssertTrue(createAccountButton.exists && createAccountButton.isHittable, "Create Account button must be visible and tappable")
        XCTAssertTrue(cancelButton.exists && cancelButton.isHittable, "Cancel button must be visible and tappable")

        // NEGATIVE CHECK: Should NOT see verification screen elements as hittable
        let verifyTitle = app.staticTexts["Verify Your Email"]
        XCTAssertFalse(verifyTitle.exists && verifyTitle.isHittable, "Verification screen should NOT be visible on registration form")

        // NEGATIVE CHECK: Login Sign Up button should not be hittable (covered by sheet)
        let loginSignUpButton = app.buttons[AccessibilityIdentifiers.Authentication.signUpButton].firstMatch
        // Note: The button might still exist but should not be hittable due to sheet coverage
        if loginSignUpButton.exists {
            XCTAssertFalse(loginSignUpButton.isHittable, "Login screen's Sign Up button should be covered by registration sheet")
        }
    }

    func test02_cancelRegistration() {
        navigateToRegistration()

        // Capture that we're on registration screen
        let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
        XCTAssertTrue(usernameField.isHittable, "PRECONDITION: Must be on registration screen")

        let cancelButton = app.buttons[AccessibilityIdentifiers.Authentication.registerCancelButton]
        XCTAssertTrue(cancelButton.isHittable, "Cancel button must be tappable")
        dismissKeyboard()
        cancelButton.tap()

        // STRICT: Registration sheet must dismiss - username field should no longer be hittable
        XCTAssertTrue(waitForElementToDisappear(usernameField, timeout: 5), "Registration form must disappear after cancel")

        // STRICT: Login screen must now be interactive again
        let welcomeText = app.textFields[AccessibilityIdentifiers.Authentication.usernameField]
        XCTAssertTrue(welcomeText.waitForExistence(timeout: 5), "Login screen must be visible after cancel")

        // STRICT: Sign Up button should be hittable again (sheet dismissed)
        let signUpButton = app.buttons[AccessibilityIdentifiers.Authentication.signUpButton].firstMatch
        XCTAssertTrue(waitForElementToBeHittable(signUpButton, timeout: 5), "Sign Up button must be tappable after cancel")
    }

    // MARK: - 2. Client-Side Validation Tests (no API calls, fail locally)

    func test03_registrationWithEmptyFields() {
        navigateToRegistration()

        let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
        XCTAssertTrue(createAccountButton.isHittable, "Create Account button must be tappable")

        // Capture current state
        let verifyTitle = app.staticTexts["Verify Your Email"]
        XCTAssertFalse(verifyTitle.exists, "PRECONDITION: Should not be on verification screen")

        dismissKeyboard()
        createAccountButton.tap()

        // STRICT: Must show error message
        let errorPredicate = NSPredicate(format: "label CONTAINS[c] 'required' OR label CONTAINS[c] 'Username'")
        let errorMessage = app.staticTexts.containing(errorPredicate).firstMatch
        XCTAssertTrue(errorMessage.waitForExistence(timeout: 3), "Error message must appear for empty fields")

        // NEGATIVE CHECK: Should NOT navigate away from registration
//        XCTAssertFalse(verifyTitle.exists, "Should NOT navigate to verification screen with empty fields")

        // STRICT: Registration form should still be visible and interactive
//        let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
//        XCTAssertTrue(usernameField.isHittable, "Username field should still be tappable after error")
    }

    func test04_registrationWithInvalidEmail() {
        navigateToRegistration()

        fillRegistrationForm(
            username: "testuser",
            email: "invalid-email",  // Invalid format
            password: testPassword,
            confirmPassword: testPassword
        )

        let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
        dismissKeyboard()
        createAccountButton.tap()

        // STRICT: Must show email-specific error
        let errorPredicate = NSPredicate(format: "label CONTAINS[c] 'email' OR label CONTAINS[c] 'invalid'")
        let errorMessage = app.staticTexts.containing(errorPredicate).firstMatch
        XCTAssertTrue(errorMessage.waitForExistence(timeout: 3), "Error message must appear for invalid email format")

        // NEGATIVE CHECK: Should NOT proceed to verification
        let verifyTitle = app.staticTexts["Verify Your Email"]
        XCTAssertFalse(verifyTitle.exists, "Should NOT navigate to verification with invalid email")
    }

    func test05_registrationWithMismatchedPasswords() {
        navigateToRegistration()

        fillRegistrationForm(
            username: "testuser",
            email: "test@example.com",
            password: "Password123!",
            confirmPassword: "DifferentPassword123!"  // Mismatched
        )

        let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
        dismissKeyboard()
        createAccountButton.tap()

        // STRICT: Must show password mismatch error
        let errorPredicate = NSPredicate(format: "label CONTAINS[c] 'match' OR label CONTAINS[c] 'password'")
        let errorMessage = app.staticTexts.containing(errorPredicate).firstMatch
        XCTAssertTrue(errorMessage.waitForExistence(timeout: 3), "Error message must appear for mismatched passwords")

        // NEGATIVE CHECK: Should NOT proceed to verification
        let verifyTitle = app.staticTexts["Verify Your Email"]
        XCTAssertFalse(verifyTitle.exists, "Should NOT navigate to verification with mismatched passwords")
    }

    func test06_registrationWithWeakPassword() {
        navigateToRegistration()

        fillRegistrationForm(
            username: "testuser",
            email: "test@example.com",
            password: "weak",  // Too weak
            confirmPassword: "weak"
        )

        let createAccountButton = app.buttons[AccessibilityIdentifiers.Authentication.registerButton]
        dismissKeyboard()
        createAccountButton.tap()

        // STRICT: Must show password strength error
        let errorPredicate = NSPredicate(format: "label CONTAINS[c] 'password' OR label CONTAINS[c] 'character' OR label CONTAINS[c] 'strong' OR label CONTAINS[c] '8'")
        let errorMessage = app.staticTexts.containing(errorPredicate).firstMatch
        XCTAssertTrue(errorMessage.waitForExistence(timeout: 3), "Error message must appear for weak password")

        // NEGATIVE CHECK: Should NOT proceed
        let verifyTitle = app.staticTexts["Verify Your Email"]
        XCTAssertFalse(verifyTitle.exists, "Should NOT navigate to verification with weak password")
    }

    // MARK: - 3. Full Registration Flow Tests (creates new users - MUST RUN BEFORE tests that need existing users)

    func test07_successfulRegistrationAndVerification() {
        let username = testUsername
        let email = testEmail

        // Use the same proven flow as tests 09-12
        navigateToRegistration()
        fillRegistrationForm(
            username: username,
            email: email,
            password: testPassword,
            confirmPassword: testPassword
        )

        submitRegistrationForm()

        // Wait for verification screen to appear (registration form may still exist underneath)
        XCTAssertTrue(waitForVerificationScreen(timeout: 15), "Verification screen must appear after registration")

        // NEGATIVE CHECK: Tab bar should NOT be hittable while on verification
        let tabBar = app.tabBars.firstMatch
        if tabBar.exists {
            XCTAssertFalse(tabBar.isHittable, "Tab bar should NOT be interactive while verification is required")
        }

        // Enter verification code — the verification screen auto-submits when 6 digits are typed.
        // IMPORTANT: Do NOT use focusAndType() here — it taps the nav bar to dismiss the keyboard,
        // which can accidentally hit the logout button in the toolbar.
        let codeField = verificationCodeField()
        XCTAssertTrue(codeField.waitForExistence(timeout: 5), "Verification code field must exist")
        codeField.tap()
        _ = app.keyboards.firstMatch.waitForExistence(timeout: 3)
        codeField.typeText(testVerificationCode)

        // Auto-submit: typing 6 digits triggers verifyEmail() and navigates to main app.
        // Wait for the main app to appear (RootView sets ui.root.mainTabs when showing MainTabView).
        let mainTabs = app.otherElements["ui.root.mainTabs"]
        let mainAppAppeared = mainTabs.waitForExistence(timeout: 15)

        if !mainAppAppeared {
            // Diagnostic: capture what's on screen
            let screenshot = XCTAttachment(screenshot: app.screenshot())
            screenshot.name = "post-verification-no-main-tabs"
            screenshot.lifetime = .keepAlways
            add(screenshot)

            // Check if we're stuck on verification screen or login
            let stillOnVerify = codeField.exists
            let onLogin = app.textFields[AccessibilityIdentifiers.Authentication.usernameField].exists
            XCTFail("Main app did not appear after verification. StillOnVerify=\(stillOnVerify), OnLogin=\(onLogin)")
            return
        }

        // STRICT: Tab bar must exist and be interactive
        XCTAssertTrue(app.tabBars.firstMatch.waitForExistence(timeout: 5), "Tab bar must exist in main app")

        // NEGATIVE CHECK: Verification screen should be completely gone
        XCTAssertFalse(codeField.exists, "Verification code field must NOT exist after successful verification")

        // Cleanup: Logout via profile tab → settings → logout
        dismissKeyboard()
        ensureLoggedOut()
    }

    // MARK: - 4. Server-Side Validation Tests (NOW a user exists from test07)

//    func test08_registrationWithExistingUsername() {
//        // NOTE: test07 created a user, so now we can test duplicate username rejection
//        // We use 'testuser' which should be seeded, OR we could use the username from test07
//        navigateToRegistration()
//
//        fillRegistrationForm(
//            username: "testuser",  // Existing username (seeded in test DB)
//            email: "newemail_\(Int(Date().timeIntervalSince1970))@example.com",
//            password: testPassword,
//            confirmPassword: testPassword
//        )
//
//        dismissKeyboard()
//        app.buttons[AccessibilityIdentifiers.Authentication.registerButton].tap()
//
//        // STRICT: Must show "already exists" error
//        let errorPredicate = NSPredicate(format: "label CONTAINS[c] 'exists' OR label CONTAINS[c] 'already' OR label CONTAINS[c] 'taken'")
//        let errorMessage = app.staticTexts.containing(errorPredicate).firstMatch
//        XCTAssertTrue(errorMessage.waitForExistence(timeout: 5), "Error message must appear for existing username")
//
//        // NEGATIVE CHECK: Should NOT proceed to verification
//        let verifyTitle = app.staticTexts["Verify Your Email"]
//        XCTAssertFalse(verifyTitle.exists, "Should NOT navigate to verification with existing username")
//
//        // STRICT: Should still be on registration form
//        let usernameField = app.textFields[AccessibilityIdentifiers.Authentication.registerUsernameField]
//        XCTAssertTrue(usernameField.exists && usernameField.isHittable, "Registration form should still be active")
//    }

    // MARK: - 5. Verification Screen Tests

    func test09_registrationWithInvalidVerificationCode() {
        let username = testUsername
        let email = testEmail

        navigateToRegistration()
        fillRegistrationForm(
            username: username,
            email: email,
            password: testPassword,
            confirmPassword: testPassword
        )

        submitRegistrationForm()

        // Wait for verification screen
        XCTAssertTrue(waitForVerificationScreen(timeout: 10), "Must navigate to verification screen")

        // Enter INVALID code — auto-submits at 6 digits
        // Don't use focusAndType() — it taps nav bar which can hit the logout button
        let codeField = verificationCodeField()
        XCTAssertTrue(codeField.waitForExistence(timeout: 5))
        codeField.tap()
        _ = app.keyboards.firstMatch.waitForExistence(timeout: 3)
        codeField.typeText("000000")  // Wrong code → auto-submit → API error

        // STRICT: Error message must appear (auto-submit verifies with wrong code)
        let errorPredicate = NSPredicate(format: "label CONTAINS[c] 'invalid' OR label CONTAINS[c] 'error' OR label CONTAINS[c] 'incorrect' OR label CONTAINS[c] 'wrong' OR label CONTAINS[c] 'expired'")
        let errorMessage = app.staticTexts.containing(errorPredicate).firstMatch
        XCTAssertTrue(errorMessage.waitForExistence(timeout: 10), "Error message MUST appear for invalid verification code")
    }

    func test10_verificationCodeFieldValidation() {
        let username = testUsername
        let email = testEmail

        navigateToRegistration()
        fillRegistrationForm(
            username: username,
            email: email,
            password: testPassword,
            confirmPassword: testPassword
        )

        submitRegistrationForm()

        XCTAssertTrue(waitForVerificationScreen(timeout: 10))

        // Enter incomplete code (only 3 digits — won't trigger auto-submit)
        // Don't use focusAndType() — it taps nav bar which can hit the logout button
        let codeField = verificationCodeField()
        XCTAssertTrue(codeField.waitForExistence(timeout: 5))
        codeField.tap()
        _ = app.keyboards.firstMatch.waitForExistence(timeout: 3)
        codeField.typeText("123")  // Incomplete

        // STRICT: Must still be on verification screen (3 digits won't auto-submit)
        XCTAssertTrue(codeField.exists, "Must remain on verification screen with incomplete code")

        // NEGATIVE CHECK: Should NOT have navigated to main app
        let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
        if residencesTab.exists {
            XCTAssertFalse(residencesTab.isHittable, "Tab bar MUST NOT be accessible with incomplete verification")
        }
    }

    func test11_appRelaunchWithUnverifiedUser() {
        // This test verifies: user kills app on verification screen, relaunches, should see verification again

        let username = testUsername
        let email = testEmail

        navigateToRegistration()
        fillRegistrationForm(
            username: username,
            email: email,
            password: testPassword,
            confirmPassword: testPassword
        )

        submitRegistrationForm()

        // Wait for verification screen
        XCTAssertTrue(waitForVerificationScreen(timeout: 20), "Must reach verification screen")

        // Relaunch WITHOUT --reset-state so the unverified session persists.
        // Keep --ui-testing and --disable-animations but remove --reset-state and --complete-onboarding.
        app.terminate()
        app.launchArguments = ["--ui-testing", "--disable-animations"]
        app.launch()

        // Wait for app to fully initialize
        app.otherElements["ui.app.ready"].waitForExistenceOrFail(timeout: 15)

        // STRICT: After relaunch, unverified user MUST see verification screen, NOT main app
        let authCodeFieldAfterRelaunch = app.textFields[AccessibilityIdentifiers.Authentication.verificationCodeField]
        let onboardingCodeFieldAfterRelaunch = app.textFields[AccessibilityIdentifiers.Onboarding.verificationCodeField]
        let loginScreen = app.textFields[AccessibilityIdentifiers.Authentication.usernameField]
        let tabBar = app.tabBars.firstMatch

        // Wait for one of the expected screens to appear
        _ = authCodeFieldAfterRelaunch.waitForExistence(timeout: 10)
            || onboardingCodeFieldAfterRelaunch.waitForExistence(timeout: 5)
            || loginScreen.waitForExistence(timeout: 5)

        // User should NEVER be on main app with unverified email
        if tabBar.exists && tabBar.isHittable {
            XCTFail("CRITICAL: Unverified user should NOT have access to main app after relaunch. Tab bar is hittable!")
        }

        // Acceptable states: verification screen OR login screen (if token expired)
        let onVerificationScreen =
            (authCodeFieldAfterRelaunch.exists && authCodeFieldAfterRelaunch.isHittable)
            || (onboardingCodeFieldAfterRelaunch.exists && onboardingCodeFieldAfterRelaunch.isHittable)
        let onLoginScreen = loginScreen.exists && loginScreen.isHittable

        XCTAssertTrue(onVerificationScreen || onLoginScreen,
                      "After relaunch, unverified user must be on verification screen or login screen, NOT main app")

        // Cleanup: logout from whatever screen we're on
        if onVerificationScreen {
            let logoutButton = app.buttons[AccessibilityIdentifiers.Authentication.verificationLogoutButton]
            if logoutButton.waitForExistence(timeout: 3) && logoutButton.isHittable {
                dismissKeyboard()
                logoutButton.tap()
            }
        }
    }

    func test12_logoutFromVerificationScreen() {
        let username = testUsername
        let email = testEmail

        navigateToRegistration()
        fillRegistrationForm(
            username: username,
            email: email,
            password: testPassword,
            confirmPassword: testPassword
        )

        submitRegistrationForm()

        // Wait for verification screen
        XCTAssertTrue(waitForVerificationScreen(timeout: 10), "Must navigate to verification screen")

        // STRICT: Logout button must exist and be tappable (uses dedicated verify screen ID)
        let logoutButton = app.buttons[AccessibilityIdentifiers.Authentication.verificationLogoutButton]
        XCTAssertTrue(logoutButton.waitForExistence(timeout: 5), "Logout button MUST exist on verification screen")
        logoutButton.waitUntilHittable(timeout: 5)
        logoutButton.tap()

        // STRICT: Verification screen must disappear
        let codeField = verificationCodeField()
        XCTAssertTrue(waitForElementToDisappear(codeField, timeout: 5), "Verification screen must disappear after logout")

        // STRICT: Must return to login screen
        let welcomeText = app.textFields[AccessibilityIdentifiers.Authentication.usernameField]
        XCTAssertTrue(welcomeText.waitForExistence(timeout: 5), "Must return to login screen after logout")
        XCTAssertTrue(welcomeText.isHittable, "Login screen must be interactive")

        // NEGATIVE CHECK: Verification screen elements should be gone
        XCTAssertFalse(codeField.exists, "Verification code field should NOT exist after logout")
    }
}

// MARK: - XCUIElement Extension

extension XCUIElement {
    var hasKeyboardFocus: Bool {
        return (value(forKey: "hasKeyboardFocus") as? Bool) ?? false
    }
}
