diff --git a/app/src/main/java/com/x8bit/bitwarden/data/tools/generator/repository/GeneratorRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/tools/generator/repository/GeneratorRepositoryImpl.kt
index 601b2cc9a..e57ab041d 100644
--- a/app/src/main/java/com/x8bit/bitwarden/data/tools/generator/repository/GeneratorRepositoryImpl.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/data/tools/generator/repository/GeneratorRepositoryImpl.kt
@@ -25,6 +25,7 @@ import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.onStart
+import java.time.Instant
 import javax.inject.Singleton
 
 /**
@@ -67,7 +68,11 @@ class GeneratorRepositoryImpl(
             }
             .onEach { encryptedPasswordHistoryListResult ->
                 mutablePasswordHistoryStateFlow.value = encryptedPasswordHistoryListResult.fold(
-                    onSuccess = { LocalDataState.Loaded(it) },
+                    onSuccess = {
+                        LocalDataState.Loaded(
+                            it.sortedByDescending { history -> history.lastUsedDate },
+                        )
+                    },
                     onFailure = { LocalDataState.Error(it) },
                 )
             }
@@ -78,7 +83,14 @@ class GeneratorRepositoryImpl(
         generatorSdkSource
             .generatePassword(passwordGeneratorRequest)
             .fold(
-                onSuccess = { GeneratedPasswordResult.Success(it) },
+                onSuccess = { generatedPassword ->
+                    val passwordHistoryView = PasswordHistoryView(
+                        password = generatedPassword,
+                        lastUsedDate = Instant.now(),
+                    )
+                    storePasswordHistory(passwordHistoryView)
+                    GeneratedPasswordResult.Success(generatedPassword)
+                },
                 onFailure = { GeneratedPasswordResult.InvalidRequest },
             )
 
@@ -88,7 +100,14 @@ class GeneratorRepositoryImpl(
         generatorSdkSource
             .generatePassphrase(passphraseGeneratorRequest)
             .fold(
-                onSuccess = { GeneratedPassphraseResult.Success(it) },
+                onSuccess = { generatedPassphrase ->
+                    val passwordHistoryView = PasswordHistoryView(
+                        password = generatedPassphrase,
+                        lastUsedDate = Instant.now(),
+                    )
+                    storePasswordHistory(passwordHistoryView)
+                    GeneratedPassphraseResult.Success(generatedPassphrase)
+                },
                 onFailure = { GeneratedPassphraseResult.InvalidRequest },
             )
 
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryScreen.kt
index f922b4b72..ebb5d79cb 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryScreen.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryScreen.kt
@@ -28,11 +28,14 @@ import androidx.compose.ui.res.stringResource
 import androidx.compose.foundation.lazy.items
 import androidx.compose.material3.CircularProgressIndicator
 import androidx.compose.material3.HorizontalDivider
+import androidx.compose.ui.platform.ClipboardManager
+import androidx.compose.ui.platform.LocalClipboardManager
 import androidx.compose.ui.unit.dp
 import androidx.hilt.navigation.compose.hiltViewModel
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.x8bit.bitwarden.R
 import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
+import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
 import com.x8bit.bitwarden.ui.platform.components.BitwardenOverflowActionItem
 import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
 import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
@@ -48,6 +51,7 @@ import kotlinx.collections.immutable.persistentListOf
 fun PasswordHistoryScreen(
     onNavigateBack: () -> Unit,
     viewModel: PasswordHistoryViewModel = hiltViewModel(),
+    clipboardManager: ClipboardManager = LocalClipboardManager.current,
 ) {
     val state by viewModel.stateFlow.collectAsStateWithLifecycle()
     val context = LocalContext.current
@@ -56,6 +60,11 @@ fun PasswordHistoryScreen(
     EventsEffect(viewModel = viewModel) { event ->
         when (event) {
             PasswordHistoryEvent.NavigateBack -> onNavigateBack.invoke()
+
+            is PasswordHistoryEvent.CopyTextToClipboard -> {
+                clipboardManager.setText(event.text.toAnnotatedString())
+            }
+
             is PasswordHistoryEvent.ShowToast -> {
                 Toast.makeText(context, event.message, Toast.LENGTH_SHORT).show()
             }
@@ -189,7 +198,7 @@ private fun PasswordHistoryError(
         contentAlignment = Alignment.Center,
     ) {
         Text(
-            text = state.message,
+            text = state.message.invoke(),
             style = MaterialTheme.typography.bodyMedium,
         )
         Spacer(modifier = Modifier.navigationBarsPadding())
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryViewModel.kt
index 76891803f..69d1a0a8b 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryViewModel.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryViewModel.kt
@@ -1,9 +1,22 @@
 package com.x8bit.bitwarden.ui.tools.feature.generator.passwordhistory
 
 import android.os.Parcelable
+import androidx.lifecycle.viewModelScope
+import com.bitwarden.core.PasswordHistoryView
+import com.x8bit.bitwarden.R
+import com.x8bit.bitwarden.data.platform.repository.model.LocalDataState
+import com.x8bit.bitwarden.data.tools.generator.repository.GeneratorRepository
 import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
+import com.x8bit.bitwarden.ui.platform.base.util.Text
+import com.x8bit.bitwarden.ui.platform.base.util.asText
 import com.x8bit.bitwarden.ui.tools.feature.generator.passwordhistory.PasswordHistoryState.GeneratedPassword
+import com.x8bit.bitwarden.ui.tools.feature.generator.util.toFormattedPattern
 import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
 import kotlinx.parcelize.Parcelize
 import javax.inject.Inject
 
@@ -12,16 +25,61 @@ import javax.inject.Inject
  */
 @HiltViewModel
 @Suppress("TooManyFunctions")
-class PasswordHistoryViewModel @Inject constructor() :
-    BaseViewModel<PasswordHistoryState, PasswordHistoryEvent, PasswordHistoryAction>(
-        initialState = PasswordHistoryState(PasswordHistoryState.ViewState.Loading),
-    ) {
+class PasswordHistoryViewModel @Inject constructor(
+    private val generatorRepository: GeneratorRepository,
+) : BaseViewModel<PasswordHistoryState, PasswordHistoryEvent, PasswordHistoryAction>(
+    initialState = PasswordHistoryState(PasswordHistoryState.ViewState.Loading),
+) {
+
+    init {
+        generatorRepository
+            .passwordHistoryStateFlow
+            .map { PasswordHistoryAction.Internal.UpdatePasswordHistoryReceive(it) }
+            .onEach(::sendAction)
+            .launchIn(viewModelScope)
+    }
 
     override fun handleAction(action: PasswordHistoryAction) {
         when (action) {
             PasswordHistoryAction.CloseClick -> handleCloseClick()
             is PasswordHistoryAction.PasswordCopyClick -> handleCopyClick(action.password)
             PasswordHistoryAction.PasswordClearClick -> handlePasswordHistoryClearClick()
+            is PasswordHistoryAction.Internal.UpdatePasswordHistoryReceive -> {
+                handleUpdatePasswordHistoryReceive(action)
+            }
+        }
+    }
+
+    private fun handleUpdatePasswordHistoryReceive(
+        action: PasswordHistoryAction.Internal.UpdatePasswordHistoryReceive,
+    ) {
+        val newState = when (val state = action.state) {
+            is LocalDataState.Loading -> PasswordHistoryState.ViewState.Loading
+
+            is LocalDataState.Error -> {
+                PasswordHistoryState.ViewState.Error(R.string.an_error_has_occurred.asText())
+            }
+
+            is LocalDataState.Loaded -> {
+                val passwords = state.data.map { passwordHistoryView ->
+                    GeneratedPassword(
+                        password = passwordHistoryView.password,
+                        date = passwordHistoryView.lastUsedDate.toFormattedPattern(
+                            pattern = "MM/dd/yy h:mm a",
+                        ),
+                    )
+                }
+
+                if (passwords.isEmpty()) {
+                    PasswordHistoryState.ViewState.Empty
+                } else {
+                    PasswordHistoryState.ViewState.Content(passwords)
+                }
+            }
+        }
+
+        mutableStateFlow.update {
+            it.copy(viewState = newState)
         }
     }
 
@@ -32,19 +90,13 @@ class PasswordHistoryViewModel @Inject constructor() :
     }
 
     private fun handlePasswordHistoryClearClick() {
-        sendEvent(
-            event = PasswordHistoryEvent.ShowToast(
-                message = "Not yet implemented.",
-            ),
-        )
+        viewModelScope.launch {
+            generatorRepository.clearPasswordHistory()
+        }
     }
 
     private fun handleCopyClick(password: GeneratedPassword) {
-        sendEvent(
-            event = PasswordHistoryEvent.ShowToast(
-                message = "Not yet implemented.",
-            ),
-        )
+        sendEvent(PasswordHistoryEvent.CopyTextToClipboard(password.password))
     }
 }
 
@@ -76,7 +128,7 @@ data class PasswordHistoryState(
          * @property message The error message to be displayed.
          */
         @Parcelize
-        data class Error(val message: String) : ViewState()
+        data class Error(val message: Text) : ViewState()
 
         /**
          * Empty state for the password history screen.
@@ -122,6 +174,11 @@ sealed class PasswordHistoryEvent {
      * Event to navigate back to the previous screen.
      */
     data object NavigateBack : PasswordHistoryEvent()
+
+    /**
+     * Copies text to the clipboard.
+     */
+    data class CopyTextToClipboard(val text: String) : PasswordHistoryEvent()
 }
 
 /**
@@ -145,4 +202,17 @@ sealed class PasswordHistoryAction {
      * Action when the close button is clicked.
      */
     data object CloseClick : PasswordHistoryAction()
+
+    /**
+     * Models actions that the [PasswordHistoryViewModel] itself might send.
+     */
+    sealed class Internal : PasswordHistoryAction() {
+
+        /**
+         * Indicates a password history update is received.
+         */
+        data class UpdatePasswordHistoryReceive(
+            val state: LocalDataState<List<PasswordHistoryView>>,
+        ) : Internal()
+    }
 }
diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/util/InstantExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/util/InstantExtensions.kt
new file mode 100644
index 000000000..da4580c55
--- /dev/null
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/util/InstantExtensions.kt
@@ -0,0 +1,17 @@
+package com.x8bit.bitwarden.ui.tools.feature.generator.util
+
+import java.time.Instant
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+import java.util.TimeZone
+
+/**
+ * Converts the [Instant] to a formatted string based on the provided pattern and time zone.
+ */
+fun Instant.toFormattedPattern(
+    pattern: String,
+    zone: ZoneId = TimeZone.getDefault().toZoneId(),
+): String {
+    val formatter = DateTimeFormatter.ofPattern(pattern).withZone(zone)
+    return formatter.format(this)
+}
diff --git a/app/src/test/java/com/x8bit/bitwarden/data/tools/generator/repository/GeneratorRepositoryTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/tools/generator/repository/GeneratorRepositoryTest.kt
index b708ab6c0..d8fafb336 100644
--- a/app/src/test/java/com/x8bit/bitwarden/data/tools/generator/repository/GeneratorRepositoryTest.kt
+++ b/app/src/test/java/com/x8bit/bitwarden/data/tools/generator/repository/GeneratorRepositoryTest.kt
@@ -25,20 +25,21 @@ import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPassph
 import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPasswordResult
 import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
 import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
-import io.mockk.clearMocks
 import io.mockk.coEvery
 import io.mockk.coVerify
 import io.mockk.every
 import io.mockk.just
 import io.mockk.mockk
+import io.mockk.mockkStatic
 import io.mockk.runs
+import io.mockk.unmockkStatic
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runTest
+import org.junit.jupiter.api.AfterEach
 import org.junit.jupiter.api.Assertions.assertEquals
 import org.junit.jupiter.api.Assertions.assertNull
 import org.junit.jupiter.api.Assertions.assertTrue
-import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
 import java.time.Instant
 
@@ -50,6 +51,7 @@ class GeneratorRepositoryTest {
     private val generatorDiskSource: GeneratorDiskSource = mockk()
     private val authDiskSource: AuthDiskSource = mockk {
         every { userStateFlow } returns mutableUserStateFlow
+        every { userState } returns null
     }
     private val passwordHistoryDiskSource: PasswordHistoryDiskSource = mockk()
     private val vaultSdkSource: VaultSdkSource = mockk()
@@ -64,13 +66,19 @@ class GeneratorRepositoryTest {
         dispatcherManager = dispatcherManager,
     )
 
-    @BeforeEach
-    fun setUp() {
-        clearMocks(generatorSdkSource)
+    @AfterEach
+    fun tearDown() {
+        unmockkStatic(Instant::class)
     }
 
     @Test
-    fun `generatePassword should emit Success result with the generated password`() = runTest {
+    fun `generatePassword should emit Success result and store the generated password`() = runTest {
+        val fixedInstant = Instant.parse("2021-01-01T00:00:00Z")
+
+        mockkStatic(Instant::class)
+        every { Instant.now() } returns fixedInstant
+
+        val userId = "testUserId"
         val request = PasswordGeneratorRequest(
             lowercase = true,
             uppercase = true,
@@ -83,15 +91,30 @@ class GeneratorRepositoryTest {
             minNumber = null,
             minSpecial = null,
         )
-        val expectedResult = "GeneratedPassword123!"
-        coEvery {
-            generatorSdkSource.generatePassword(request)
-        } returns Result.success(expectedResult)
+        val generatedPassword = "GeneratedPassword123!"
+        val encryptedPasswordHistory =
+            PasswordHistory(password = generatedPassword, lastUsedDate = Instant.now())
+
+        coEvery { authDiskSource.userState?.activeUserId } returns userId
+
+        coEvery { generatorSdkSource.generatePassword(request) } returns
+            Result.success(generatedPassword)
+
+        coEvery { vaultSdkSource.encryptPasswordHistory(any()) } returns
+            Result.success(encryptedPasswordHistory)
+
+        coEvery { passwordHistoryDiskSource.insertPasswordHistory(any()) } just runs
 
         val result = repository.generatePassword(request)
 
-        assertEquals(expectedResult, (result as GeneratedPasswordResult.Success).generatedString)
+        assertEquals(generatedPassword, (result as GeneratedPasswordResult.Success).generatedString)
         coVerify { generatorSdkSource.generatePassword(request) }
+
+        coVerify {
+            passwordHistoryDiskSource.insertPasswordHistory(
+                encryptedPasswordHistory.toPasswordHistoryEntity(userId),
+            )
+        }
     }
 
     @Test
@@ -118,23 +141,47 @@ class GeneratorRepositoryTest {
     }
 
     @Test
-    fun `generatePassphrase should emit Success result with the generated passphrase`() = runTest {
-        val request = PassphraseGeneratorRequest(
-            numWords = 5.toUByte(),
-            capitalize = true,
-            includeNumber = true,
-            wordSeparator = '-'.toString(),
-        )
-        val expectedResult = "Generated-Passphrase-123!"
-        coEvery {
-            generatorSdkSource.generatePassphrase(request)
-        } returns Result.success(expectedResult)
+    fun `generatePassphrase should emit Success result and store the generated passphrase`() =
+        runTest {
+            val fixedInstant = Instant.parse("2021-01-01T00:00:00Z")
+            mockkStatic(Instant::class)
+            every { Instant.now() } returns fixedInstant
 
-        val result = repository.generatePassphrase(request)
+            val userId = "testUserId"
+            val request = PassphraseGeneratorRequest(
+                numWords = 5.toUByte(),
+                capitalize = true,
+                includeNumber = true,
+                wordSeparator = "-",
+            )
+            val generatedPassphrase = "Generated-Passphrase-123"
+            val encryptedPasswordHistory =
+                PasswordHistory(password = generatedPassphrase, lastUsedDate = Instant.now())
 
-        assertEquals(expectedResult, (result as GeneratedPassphraseResult.Success).generatedString)
-        coVerify { generatorSdkSource.generatePassphrase(request) }
-    }
+            coEvery { authDiskSource.userState?.activeUserId } returns userId
+
+            coEvery { generatorSdkSource.generatePassphrase(request) } returns
+                Result.success(generatedPassphrase)
+
+            coEvery { vaultSdkSource.encryptPasswordHistory(any()) } returns
+                Result.success(encryptedPasswordHistory)
+
+            coEvery { passwordHistoryDiskSource.insertPasswordHistory(any()) } just runs
+
+            val result = repository.generatePassphrase(request)
+
+            assertEquals(
+                generatedPassphrase,
+                (result as GeneratedPassphraseResult.Success).generatedString,
+            )
+            coVerify { generatorSdkSource.generatePassphrase(request) }
+            coVerify { vaultSdkSource.encryptPasswordHistory(any()) }
+            coVerify {
+                passwordHistoryDiskSource.insertPasswordHistory(
+                    encryptedPasswordHistory.toPasswordHistoryEntity(userId),
+                )
+            }
+        }
 
     @Suppress("MaxLineLength")
     @Test
@@ -278,25 +325,25 @@ class GeneratorRepositoryTest {
             val encryptedPasswordHistoryEntities = listOf(
                 PasswordHistoryEntity(
                     userId = USER_STATE.activeUserId,
-                    encryptedPassword = "encryptedPassword1",
-                    generatedDateTimeMs = Instant.parse("2021-01-01T00:00:00Z").toEpochMilli(),
+                    encryptedPassword = "encryptedPassword2",
+                    generatedDateTimeMs = Instant.parse("2021-01-02T00:00:00Z").toEpochMilli(),
                 ),
                 PasswordHistoryEntity(
                     userId = USER_STATE.activeUserId,
-                    encryptedPassword = "encryptedPassword2",
-                    generatedDateTimeMs = Instant.parse("2021-01-02T00:00:00Z").toEpochMilli(),
+                    encryptedPassword = "encryptedPassword1",
+                    generatedDateTimeMs = Instant.parse("2021-01-01T00:00:00Z").toEpochMilli(),
                 ),
             )
 
             val decryptedPasswordHistoryList = listOf(
-                PasswordHistoryView(
-                    password = "password1",
-                    lastUsedDate = Instant.parse("2021-01-01T00:00:00Z"),
-                ),
                 PasswordHistoryView(
                     password = "password2",
                     lastUsedDate = Instant.parse("2021-01-02T00:00:00Z"),
                 ),
+                PasswordHistoryView(
+                    password = "password1",
+                    lastUsedDate = Instant.parse("2021-01-01T00:00:00Z"),
+                ),
             )
 
             coEvery {
diff --git a/app/src/test/java/com/x8bit/bitwarden/data/tools/generator/repository/util/FakeGeneratorRepository.kt b/app/src/test/java/com/x8bit/bitwarden/data/tools/generator/repository/util/FakeGeneratorRepository.kt
index cfb2dce0a..d61b05d20 100644
--- a/app/src/test/java/com/x8bit/bitwarden/data/tools/generator/repository/util/FakeGeneratorRepository.kt
+++ b/app/src/test/java/com/x8bit/bitwarden/data/tools/generator/repository/util/FakeGeneratorRepository.kt
@@ -74,4 +74,19 @@ class FakeGeneratorRepository : GeneratorRepository {
     fun setMockGeneratePassphraseResult(result: GeneratedPassphraseResult) {
         generatePassphraseResult = result
     }
+
+    /**
+     * Checks if a specific password is in the history.
+     */
+    fun isPasswordStoredInHistory(password: String): Boolean {
+        val passwordHistoryList = mutablePasswordHistoryStateFlow.value.data.orEmpty()
+        return passwordHistoryList.any { it.password == password }
+    }
+
+    /**
+     * Emits specified state to the passwordHistoryStateFlow.
+     */
+    fun emitPasswordHistoryState(state: LocalDataState<List<PasswordHistoryView>>) {
+        mutablePasswordHistoryStateFlow.value = state
+    }
 }
diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryScreenTest.kt
index 232e68432..3eacb9fec 100644
--- a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryScreenTest.kt
+++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryScreenTest.kt
@@ -5,6 +5,7 @@ import androidx.compose.ui.test.onNodeWithContentDescription
 import androidx.compose.ui.test.onNodeWithText
 import androidx.compose.ui.test.performClick
 import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
+import com.x8bit.bitwarden.ui.platform.base.util.asText
 import io.mockk.every
 import io.mockk.mockk
 import io.mockk.verify
@@ -49,7 +50,9 @@ class PasswordHistoryScreenTest : BaseComposeTest() {
     @Test
     fun `Error state should display error message`() {
         val errorMessage = "Error occurred"
-        updateState(PasswordHistoryState(PasswordHistoryState.ViewState.Error(errorMessage)))
+        updateState(
+            PasswordHistoryState(PasswordHistoryState.ViewState.Error(errorMessage.asText())),
+        )
         composeTestRule.onNodeWithText(errorMessage).assertIsDisplayed()
     }
 
diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryViewModelTest.kt
index 128961cd7..8f488bdfc 100644
--- a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryViewModelTest.kt
+++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/passwordhistory/PasswordHistoryViewModelTest.kt
@@ -1,10 +1,18 @@
 package com.x8bit.bitwarden.ui.tools.feature.generator.passwordhistory
 
 import app.cash.turbine.test
+import com.bitwarden.core.PasswordHistoryView
+import com.x8bit.bitwarden.data.platform.repository.model.LocalDataState
+import com.x8bit.bitwarden.data.tools.generator.repository.util.FakeGeneratorRepository
+import com.x8bit.bitwarden.R
 import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
+import com.x8bit.bitwarden.ui.platform.base.util.asText
+import com.x8bit.bitwarden.ui.tools.feature.generator.util.toFormattedPattern
 import kotlinx.coroutines.test.runTest
 import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertTrue
 import org.junit.jupiter.api.Test
+import java.time.Instant
 
 class PasswordHistoryViewModelTest : BaseViewModelTest() {
 
@@ -18,6 +26,77 @@ class PasswordHistoryViewModelTest : BaseViewModelTest() {
         }
     }
 
+    @Test
+    fun `when repository emits Loading state the state updates correctly`() = runTest {
+        val fakeRepository = FakeGeneratorRepository().apply {
+            emitPasswordHistoryState(LocalDataState.Loading)
+        }
+        val viewModel = PasswordHistoryViewModel(generatorRepository = fakeRepository)
+
+        viewModel.stateFlow.test {
+            val expectedState = PasswordHistoryState(PasswordHistoryState.ViewState.Loading)
+            val actualState = awaitItem()
+            assertEquals(expectedState, actualState)
+        }
+    }
+
+    @Test
+    fun `when repository emits Error state the state updates correctly`() = runTest {
+        val fakeRepository = FakeGeneratorRepository().apply {
+            emitPasswordHistoryState(LocalDataState.Error(Exception("An error has occurred.")))
+        }
+        val viewModel = PasswordHistoryViewModel(generatorRepository = fakeRepository)
+
+        viewModel.stateFlow.test {
+            val expectedState = PasswordHistoryState(
+                PasswordHistoryState.ViewState.Error(R.string.an_error_has_occurred.asText()),
+            )
+            val actualState = awaitItem()
+            assertEquals(expectedState, actualState)
+        }
+    }
+
+    @Test
+    fun `when repository emits Empty state the state updates correctly`() = runTest {
+        val fakeRepository = FakeGeneratorRepository().apply {
+            emitPasswordHistoryState(LocalDataState.Loaded(emptyList()))
+        }
+        val viewModel = PasswordHistoryViewModel(generatorRepository = fakeRepository)
+
+        viewModel.stateFlow.test {
+            val expectedState = PasswordHistoryState(PasswordHistoryState.ViewState.Empty)
+            val actualState = awaitItem()
+            assertEquals(expectedState, actualState)
+        }
+    }
+
+    @Test
+    fun `when password history updates the state updates correctly`() = runTest {
+        val fakeRepository = FakeGeneratorRepository()
+        val viewModel = PasswordHistoryViewModel(generatorRepository = fakeRepository)
+
+        val passwordHistoryView = PasswordHistoryView("password", Instant.now())
+        fakeRepository.storePasswordHistory(passwordHistoryView)
+
+        val expectedState = PasswordHistoryState(
+            viewState = PasswordHistoryState.ViewState.Content(
+                passwords = listOf(
+                    PasswordHistoryState.GeneratedPassword(
+                        password = "password",
+                        date = passwordHistoryView.lastUsedDate.toFormattedPattern(
+                            pattern = "MM/dd/yy h:mm a",
+                        ),
+                    ),
+                ),
+            ),
+        )
+
+        viewModel.stateFlow.test {
+            val actualState = awaitItem()
+            assertEquals(expectedState, actualState)
+        }
+    }
+
     @Test
     fun `CloseClick action should emit NavigateBack event`() = runTest {
         val viewModel = createViewModel()
@@ -29,37 +108,44 @@ class PasswordHistoryViewModelTest : BaseViewModelTest() {
     }
 
     @Test
-    fun `PasswordCopyClick action should emit password copied ShowToast event`() = runTest {
+    fun `PasswordCopyClick action should emit CopyTextToClipboard event`() = runTest {
         val viewModel = createViewModel()
+        val generatedPassword = PasswordHistoryState.GeneratedPassword(
+            password = "testPassword",
+            date = "01/01/23",
+        )
 
         viewModel.eventFlow.test {
             viewModel.actionChannel.trySend(
-                PasswordHistoryAction.PasswordCopyClick(
-                    PasswordHistoryState.GeneratedPassword(password = "Password", date = "Date"),
-                ),
+                PasswordHistoryAction.PasswordCopyClick(generatedPassword),
+            )
+            assertEquals(
+                PasswordHistoryEvent.CopyTextToClipboard(generatedPassword.password),
+                awaitItem(),
             )
-            assertEquals(PasswordHistoryEvent.ShowToast("Not yet implemented."), awaitItem())
         }
     }
 
     @Test
-    fun `PasswordClearClick action should emit password history cleared ShowToast event`() =
-        runTest {
-            val viewModel = createViewModel()
+    fun `PasswordClearClick action should update to Empty ViewState`() = runTest {
+        val fakeRepository = FakeGeneratorRepository()
+        val viewModel = PasswordHistoryViewModel(generatorRepository = fakeRepository)
 
-            viewModel.eventFlow.test {
-                viewModel.actionChannel.trySend(PasswordHistoryAction.PasswordClearClick)
-                assertEquals(
-                    PasswordHistoryEvent.ShowToast("Not yet implemented."),
-                    awaitItem(),
-                )
-            }
-        }
+        val passwordHistoryView = PasswordHistoryView("password", Instant.now())
+        fakeRepository.storePasswordHistory(passwordHistoryView)
+
+        viewModel.actionChannel.trySend(PasswordHistoryAction.PasswordClearClick)
+
+        assertTrue(fakeRepository.passwordHistoryStateFlow.value is LocalDataState.Loaded)
+        assertTrue(
+            (fakeRepository.passwordHistoryStateFlow.value as LocalDataState.Loaded).data.isEmpty(),
+        )
+    }
 
     //region Helper Functions
 
     private fun createViewModel(): PasswordHistoryViewModel {
-        return PasswordHistoryViewModel()
+        return PasswordHistoryViewModel(generatorRepository = FakeGeneratorRepository())
     }
 
     //endregion Helper Functions
diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/util/InstantExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/util/InstantExtensionsTest.kt
new file mode 100644
index 000000000..e1c4f6cab
--- /dev/null
+++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/generator/util/InstantExtensionsTest.kt
@@ -0,0 +1,20 @@
+package com.x8bit.bitwarden.ui.tools.feature.generator.util
+
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+import java.time.Instant
+import java.time.ZoneId
+
+class InstantExtensionsTest {
+
+    @Test
+    fun `toFormattedPattern should return correctly formatted string`() {
+        val instant = Instant.parse("2023-12-10T15:30:00Z")
+        val pattern = "MM/dd/yyyy hh:mm a"
+        val zone = ZoneId.of("UTC")
+        val expectedFormattedString = "12/10/2023 03:30 PM"
+        val formattedString = instant.toFormattedPattern(pattern, zone)
+
+        assertEquals(expectedFormattedString, formattedString)
+    }
+}