import XCTest

enum TestFlows {
    @discardableResult
    static func navigateToLoginFromOnboarding(app: XCUIApplication) -> LoginScreenObject {
        let login = LoginScreenObject(app: app)

        // If already on standalone login screen, return immediately.
        // Use a generous timeout — the app may still be rendering after launch.
        if app.textFields[UITestID.Auth.usernameField].waitForExistence(timeout: 10)
            || app.otherElements[UITestID.Root.login].waitForExistence(timeout: 3) {
            login.waitForLoad()
            return login
        }

        // Check if onboarding is actually present before trying to navigate from it
        let onboardingRoot = app.otherElements[UITestID.Root.onboarding]
        if onboardingRoot.waitForExistence(timeout: 5) {
            // Navigate from onboarding welcome
            let welcome = OnboardingWelcomeScreen(app: app)
            welcome.waitForLoad()
            welcome.tapAlreadyHaveAccount()
            login.waitForLoad()
            return login
        }

        // Fallback: use ensureOnLoginScreen which handles all edge cases
        UITestHelpers.ensureOnLoginScreen(app: app)
        login.waitForLoad()
        return login
    }

    @discardableResult
    static func navigateStartFreshToCreateAccount(
        app: XCUIApplication,
        residenceName: String = "UI Test Residence"
    ) -> OnboardingCreateAccountScreen {
        let welcome = OnboardingWelcomeScreen(app: app)
        welcome.waitForLoad()
        welcome.tapStartFresh()

        let valueProps = OnboardingValuePropsScreen(app: app)
        valueProps.waitForLoad()
        valueProps.tapContinue()

        let nameResidence = OnboardingNameResidenceScreen(app: app)
        nameResidence.waitForLoad()
        nameResidence.enterResidenceName(residenceName)
        nameResidence.tapContinue()

        let createAccount = OnboardingCreateAccountScreen(app: app)
        createAccount.waitForLoad()
        return createAccount
    }

    /// Type credentials into the login screen and tap login.
    /// Assumes the app is already showing the login screen.
    static func loginWithCredentials(app: XCUIApplication, username: String, password: String) {
        let login = LoginScreenObject(app: app)
        login.waitForLoad()
        login.enterUsername(username)
        login.enterPassword(password)

        let loginButton = app.buttons[UITestID.Auth.loginButton]
        loginButton.waitUntilHittable(timeout: 10).tap()
    }

    /// Drive the full forgot password → verify code → reset password flow using the debug code.
    static func completeForgotPasswordFlow(
        app: XCUIApplication,
        email: String,
        newPassword: String,
        confirmPassword: String? = nil
    ) throws {
        let confirm = confirmPassword ?? newPassword

        // Step 1: Enter email on forgot password screen
        let forgotScreen = ForgotPasswordScreen(app: app)
        forgotScreen.waitForLoad()
        forgotScreen.enterEmail(email)
        forgotScreen.tapSendCode()

        // Step 2: Enter debug verification code
        let verifyScreen = VerifyResetCodeScreen(app: app)
        verifyScreen.waitForLoad()
        verifyScreen.enterCode(TestAccountAPIClient.debugVerificationCode)
        verifyScreen.tapVerify()

        // Step 3: Enter new password
        let resetScreen = ResetPasswordScreen(app: app)
        try resetScreen.waitForLoad()
        resetScreen.enterNewPassword(newPassword)
        resetScreen.enterConfirmPassword(confirm)
        resetScreen.tapReset()
    }

    @discardableResult
    static func openRegisterFromLogin(app: XCUIApplication) -> RegisterScreenObject {
        let login: LoginScreenObject
        // Wait for login screen elements instead of instantaneous .exists checks
        if app.textFields[UITestID.Auth.usernameField].waitForExistence(timeout: 10)
            || app.otherElements[UITestID.Root.login].waitForExistence(timeout: 3) {
            login = LoginScreenObject(app: app)
            login.waitForLoad()
        } else {
            login = navigateToLoginFromOnboarding(app: app)
        }
        login.tapSignUp()

        let register = RegisterScreenObject(app: app)
        register.waitForLoad()
        return register
    }
}
