package com.github.nullptroma.wallenc.usecases

import com.github.nullptroma.wallenc.domain.datatypes.TextSecretEntryRecord
import com.github.nullptroma.wallenc.usecases.fakes.FakeStorage
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test

class StorageDomainUseCasesTest {

    @Test
    fun twoFaCrudWorksAndPersists() = runTest {
        val storage = FakeStorage()
        val useCase = ManageTwoFaTokensUseCase()

        val created = useCase.create(
            storageInfo = storage,
            issuer = "GitHub",
            account = "user@example.com",
            secret = "SECRET",
            notes = "primary",
        )
        assertNotNull(created.id)
        assertEquals(1, useCase.observe(storage).first().size)

        val updated = useCase.update(
            storageInfo = storage,
            token = created.copy(issuer = "GitHubUpdated"),
        )
        assertTrue(updated)
        assertEquals("GitHubUpdated", useCase.get(storage, created.id)?.issuer)

        val removed = useCase.delete(storage, created.id)
        assertTrue(removed)
        assertTrue(useCase.observe(storage).first().isEmpty())
    }

    @Test
    fun twoFaInvalidJsonFallsBackToEmptyList() = runTest {
        val storage = FakeStorage().apply {
            setDomainFile(StorageDomainDataFiles.TWO_FA_TOKENS_FILE, "not-json")
        }
        val useCase = ManageTwoFaTokensUseCase()
        assertTrue(useCase.observe(storage).first().isEmpty())
    }

    @Test
    fun textSecretsCrudWorksWithOptionalLabels() = runTest {
        val storage = FakeStorage()
        val useCase = ManageTextSecretsUseCase()

        val created = useCase.create(
            storageInfo = storage,
            title = "Server Credentials",
            items = listOf(
                TextSecretEntryRecord(label = "username", value = "admin"),
                TextSecretEntryRecord(label = null, value = "password"),
            ),
        )
        assertEquals(1, useCase.observe(storage).first().size)

        val updated = useCase.update(
            storageInfo = storage,
            secret = created.copy(
                title = "Prod Credentials",
                items = created.items + TextSecretEntryRecord(label = "url", value = "https://x.dev"),
            ),
        )
        assertTrue(updated)
        val loaded = useCase.get(storage, created.id)
        assertEquals("Prod Credentials", loaded?.title)
        assertEquals(3, loaded?.items?.size)

        val deleted = useCase.delete(storage, created.id)
        assertTrue(deleted)
        assertNull(useCase.get(storage, created.id))
    }

    @Test
    fun textSecretsInvalidJsonFallsBackToEmptyList() = runTest {
        val storage = FakeStorage().apply {
            setDomainFile(StorageDomainDataFiles.TEXT_SECRETS_FILE, "{broken")
        }
        val useCase = ManageTextSecretsUseCase()
        assertTrue(useCase.observe(storage).first().isEmpty())
    }
}
