package de.krisenvorrat.app.data.db.dao

import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import de.krisenvorrat.app.data.db.KrisenvorratDatabase
import de.krisenvorrat.app.data.db.entity.CategoryEntity
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
internal class CategoryDaoTest {

    private lateinit var db: KrisenvorratDatabase
    private lateinit var dao: CategoryDao

    @Before
    fun setup() {
        db = Room.inMemoryDatabaseBuilder(
            ApplicationProvider.getApplicationContext(),
            KrisenvorratDatabase::class.java
        ).allowMainThreadQueries().build()
        dao = db.categoryDao()
    }

    @After
    fun teardown() {
        db.close()
    }

    @Test
    fun test_insert_emptyDb_getAllReturnsOneItem() = runBlocking {
        // Given
        val category = CategoryEntity(name = "Lebensmittel")

        // When
        dao.insert(category)

        // Then
        val result = dao.getAll().first()
        assertEquals(1, result.size)
        assertEquals("Lebensmittel", result.first().name)
    }

    @Test
    fun test_update_existingCategory_nameIsChanged() = runBlocking {
        // Given
        dao.insert(CategoryEntity(name = "Alt"))
        val inserted = dao.getAll().first().first()

        // When
        dao.update(inserted.copy(name = "Neu"))

        // Then
        val updated = dao.getById(inserted.id)
        assertEquals("Neu", updated?.name)
    }

    @Test
    fun test_delete_existingCategory_getAllReturnsEmpty() = runBlocking {
        // Given
        dao.insert(CategoryEntity(name = "Temp"))
        val inserted = dao.getAll().first().first()

        // When
        dao.delete(inserted)

        // Then
        val result = dao.getAll().first()
        assertEquals(0, result.size)
    }

    @Test
    fun test_getById_nonExistentId_returnsNull() = runBlocking {
        // Given / When
        val result = dao.getById(999)

        // Then
        assertNull(result)
    }

    @Test
    fun test_getAll_multipleCategories_returnsAll() = runBlocking {
        // Given
        dao.insert(CategoryEntity(name = "Lebensmittel"))
        dao.insert(CategoryEntity(name = "Hygiene"))
        dao.insert(CategoryEntity(name = "Medizin"))

        // When
        val result = dao.getAll().first()

        // Then
        assertEquals(3, result.size)
    }
}
