package com.rssuper.database

import android.content.Context
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import com.rssuper.database.daos.FeedItemDao
import com.rssuper.database.entities.FeedItemEntity
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Before
import org.junit.Test
import java.util.Date

class FeedItemDaoTest {
    
    private lateinit var database: RssDatabase
    private lateinit var dao: FeedItemDao
    
    @Before
    fun createDb() {
        val context = ApplicationProvider.getApplicationContext<Context>()
        database = Room.inMemoryDatabaseBuilder(
            context,
            RssDatabase::class.java
        )
            .allowMainThreadQueries()
            .build()
        dao = database.feedItemDao()
    }
    
    @After
    fun closeDb() {
        database.close()
    }
    
    @Test
    fun insertAndGetItem() = runTest {
        val item = createTestItem("1", "sub1")
        
        dao.insertItem(item)
        
        val result = dao.getItemById("1")
        assertNotNull(result)
        assertEquals("1", result?.id)
        assertEquals("Test Item", result?.title)
    }
    
    @Test
    fun getItemsBySubscription() = runTest {
        val item1 = createTestItem("1", "sub1")
        val item2 = createTestItem("2", "sub1")
        val item3 = createTestItem("3", "sub2")
        
        dao.insertItems(listOf(item1, item2, item3))
        
        val result = dao.getItemsBySubscription("sub1").first()
        assertEquals(2, result.size)
    }
    
    @Test
    fun getItemsBySubscriptions() = runTest {
        val item1 = createTestItem("1", "sub1")
        val item2 = createTestItem("2", "sub2")
        val item3 = createTestItem("3", "sub3")
        
        dao.insertItems(listOf(item1, item2, item3))
        
        val result = dao.getItemsBySubscriptions(listOf("sub1", "sub2")).first()
        assertEquals(2, result.size)
    }
    
    @Test
    fun getUnreadItems() = runTest {
        val unread = createTestItem("1", "sub1", isRead = false)
        val read = createTestItem("2", "sub1", isRead = true)
        
        dao.insertItems(listOf(unread, read))
        
        val result = dao.getUnreadItems().first()
        assertEquals(1, result.size)
        assertEquals("1", result[0].id)
    }
    
    @Test
    fun getStarredItems() = runTest {
        val starred = createTestItem("1", "sub1", isStarred = true)
        val notStarred = createTestItem("2", "sub1", isStarred = false)
        
        dao.insertItems(listOf(starred, notStarred))
        
        val result = dao.getStarredItems().first()
        assertEquals(1, result.size)
        assertEquals("1", result[0].id)
    }
    
    @Test
    fun getItemsAfterDate() = runTest {
        val oldDate = Date(System.currentTimeMillis() - 86400000 * 2)
        val newDate = Date(System.currentTimeMillis() - 86400000)
        val today = Date()
        
        val oldItem = createTestItem("1", "sub1", published = oldDate)
        val newItem = createTestItem("2", "sub1", published = newDate)
        val todayItem = createTestItem("3", "sub1", published = today)
        
        dao.insertItems(listOf(oldItem, newItem, todayItem))
        
        val result = dao.getItemsAfterDate(newDate).first()
        assertEquals(1, result.size)
        assertEquals("3", result[0].id)
    }
    
    @Test
    fun getUnreadCount() = runTest {
        val unread1 = createTestItem("1", "sub1", isRead = false)
        val unread2 = createTestItem("2", "sub1", isRead = false)
        val read = createTestItem("3", "sub1", isRead = true)
        
        dao.insertItems(listOf(unread1, unread2, read))
        
        val count = dao.getUnreadCount("sub1").first()
        assertEquals(2, count)
    }
    
    @Test
    fun getTotalUnreadCount() = runTest {
        val unread1 = createTestItem("1", "sub1", isRead = false)
        val unread2 = createTestItem("2", "sub2", isRead = false)
        val read = createTestItem("3", "sub1", isRead = true)
        
        dao.insertItems(listOf(unread1, unread2, read))
        
        val count = dao.getTotalUnreadCount().first()
        assertEquals(2, count)
    }
    
    @Test
    fun updateItem() = runTest {
        val item = createTestItem("1", "sub1")
        
        dao.insertItem(item)
        
        val updated = item.copy(title = "Updated Title")
        dao.updateItem(updated)
        
        val result = dao.getItemById("1")
        assertEquals("Updated Title", result?.title)
    }
    
    @Test
    fun deleteItem() = runTest {
        val item = createTestItem("1", "sub1")
        
        dao.insertItem(item)
        dao.deleteItem(item)
        
        val result = dao.getItemById("1")
        assertNull(result)
    }
    
    @Test
    fun deleteItemById() = runTest {
        val item = createTestItem("1", "sub1")
        
        dao.insertItem(item)
        dao.deleteItemById("1")
        
        val result = dao.getItemById("1")
        assertNull(result)
    }
    
    @Test
    fun deleteItemsBySubscription() = runTest {
        val item1 = createTestItem("1", "sub1")
        val item2 = createTestItem("2", "sub1")
        val item3 = createTestItem("3", "sub2")
        
        dao.insertItems(listOf(item1, item2, item3))
        dao.deleteItemsBySubscription("sub1")
        
        val sub1Items = dao.getItemsBySubscription("sub1").first()
        val sub2Items = dao.getItemsBySubscription("sub2").first()
        
        assertEquals(0, sub1Items.size)
        assertEquals(1, sub2Items.size)
    }
    
    @Test
    fun markAsRead() = runTest {
        val item = createTestItem("1", "sub1", isRead = false)
        
        dao.insertItem(item)
        dao.markAsRead("1")
        
        val result = dao.getItemById("1")
        assertEquals(true, result?.isRead)
    }
    
    @Test
    fun markAsUnread() = runTest {
        val item = createTestItem("1", "sub1", isRead = true)
        
        dao.insertItem(item)
        dao.markAsUnread("1")
        
        val result = dao.getItemById("1")
        assertEquals(false, result?.isRead)
    }
    
    @Test
    fun markAsStarred() = runTest {
        val item = createTestItem("1", "sub1", isStarred = false)
        
        dao.insertItem(item)
        dao.markAsStarred("1")
        
        val result = dao.getItemById("1")
        assertEquals(true, result?.isStarred)
    }
    
    @Test
    fun markAsUnstarred() = runTest {
        val item = createTestItem("1", "sub1", isStarred = true)
        
        dao.insertItem(item)
        dao.markAsUnstarred("1")
        
        val result = dao.getItemById("1")
        assertEquals(false, result?.isStarred)
    }
    
    @Test
    fun markAllAsRead() = runTest {
        val item1 = createTestItem("1", "sub1", isRead = false)
        val item2 = createTestItem("2", "sub1", isRead = false)
        val item3 = createTestItem("3", "sub2", isRead = false)
        
        dao.insertItems(listOf(item1, item2, item3))
        dao.markAllAsRead("sub1")
        
        val sub1Items = dao.getItemsBySubscription("sub1").first()
        val sub2Items = dao.getItemsBySubscription("sub2").first()
        
        assertEquals(true, sub1Items[0].isRead)
        assertEquals(true, sub1Items[1].isRead)
        assertEquals(false, sub2Items[0].isRead)
    }
    
    @Test
    fun getItemsPaginated() = runTest {
        for (i in 1..10) {
            val item = createTestItem(i.toString(), "sub1")
            dao.insertItem(item)
        }
        
        val firstPage = dao.getItemsPaginated("sub1", 5, 0)
        val secondPage = dao.getItemsPaginated("sub1", 5, 5)
        
        assertEquals(5, firstPage.size)
        assertEquals(5, secondPage.size)
    }
    
    private fun createTestItem(
        id: String,
        subscriptionId: String,
        title: String = "Test Item",
        isRead: Boolean = false,
        isStarred: Boolean = false,
        published: Date = Date()
    ): FeedItemEntity {
        return FeedItemEntity(
            id = id,
            subscriptionId = subscriptionId,
            title = title,
            link = "https://example.com/$id",
            description = "Test description",
            content = "Test content",
            author = "Test Author",
            published = published,
            updated = published,
            categories = "Tech,News",
            enclosureUrl = null,
            enclosureType = null,
            enclosureLength = null,
            guid = "guid-$id",
            isRead = isRead,
            isStarred = isStarred
        )
    }
}
