package de.krisenvorrat.app.data.export

import de.krisenvorrat.app.data.db.dao.CategoryDao
import de.krisenvorrat.app.data.db.dao.ItemDao
import de.krisenvorrat.app.data.db.dao.LocationDao
import de.krisenvorrat.app.data.db.dao.SettingsDao
import de.krisenvorrat.app.data.db.entity.CategoryEntity
import de.krisenvorrat.app.data.db.entity.ItemEntity
import de.krisenvorrat.app.data.db.entity.LocationEntity
import de.krisenvorrat.app.data.db.entity.SettingsEntity
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import java.time.LocalDate

internal class FakeCategoryDao : CategoryDao {
    private val items = mutableListOf<CategoryEntity>()
    private val flow = MutableStateFlow<List<CategoryEntity>>(emptyList())

    private fun emit() { flow.value = items.toList() }

    override suspend fun insert(category: CategoryEntity) = throw UnsupportedOperationException()
    override suspend fun update(category: CategoryEntity) = throw UnsupportedOperationException()
    override suspend fun delete(category: CategoryEntity) = throw UnsupportedOperationException()
    override fun getAll(): Flow<List<CategoryEntity>> = flow
    override suspend fun getById(id: Int): CategoryEntity? = throw UnsupportedOperationException()

    override suspend fun upsertAll(categories: List<CategoryEntity>) {
        categories.forEach { cat ->
            val idx = items.indexOfFirst { it.id == cat.id }
            if (idx >= 0) items[idx] = cat else items.add(cat)
        }
        emit()
    }

    fun getItems(): List<CategoryEntity> = items.toList()
}

internal class FakeLocationDao : LocationDao {
    private val items = mutableListOf<LocationEntity>()
    private val flow = MutableStateFlow<List<LocationEntity>>(emptyList())

    private fun emit() { flow.value = items.toList() }

    override suspend fun insert(location: LocationEntity) = throw UnsupportedOperationException()
    override suspend fun update(location: LocationEntity) = throw UnsupportedOperationException()
    override suspend fun delete(location: LocationEntity) = throw UnsupportedOperationException()
    override fun getAll(): Flow<List<LocationEntity>> = flow
    override suspend fun getById(id: Int): LocationEntity? = throw UnsupportedOperationException()

    override suspend fun upsertAll(locations: List<LocationEntity>) {
        locations.forEach { loc ->
            val idx = items.indexOfFirst { it.id == loc.id }
            if (idx >= 0) items[idx] = loc else items.add(loc)
        }
        emit()
    }

    fun getItems(): List<LocationEntity> = items.toList()
}

internal class FakeItemDao : ItemDao {
    private val items = mutableListOf<ItemEntity>()
    private val flow = MutableStateFlow<List<ItemEntity>>(emptyList())

    private fun emit() { flow.value = items.toList() }

    override suspend fun insert(item: ItemEntity) = throw UnsupportedOperationException()
    override suspend fun update(item: ItemEntity) = throw UnsupportedOperationException()
    override suspend fun delete(item: ItemEntity) = throw UnsupportedOperationException()
    override fun getAll(): Flow<List<ItemEntity>> = flow
    override suspend fun getById(id: String): ItemEntity? = throw UnsupportedOperationException()
    override fun getByCategory(categoryId: Int): Flow<List<ItemEntity>> = throw UnsupportedOperationException()
    override fun getByLocation(locationId: Int): Flow<List<ItemEntity>> = throw UnsupportedOperationException()
    override fun getExpiringSoonByCutoff(cutoff: LocalDate): Flow<List<ItemEntity>> = throw UnsupportedOperationException()

    override suspend fun upsertAll(items: List<ItemEntity>) {
        items.forEach { item ->
            val idx = this.items.indexOfFirst { it.id == item.id }
            if (idx >= 0) this.items[idx] = item else this.items.add(item)
        }
        emit()
    }

    override suspend fun countByCategoryId(categoryId: Int): Int = throw UnsupportedOperationException()
    override suspend fun updateCategoryId(fromId: Int, toId: Int) = throw UnsupportedOperationException()
    override suspend fun countByLocationId(locationId: Int): Int = throw UnsupportedOperationException()
    override suspend fun updateLocationId(fromId: Int, toId: Int) = throw UnsupportedOperationException()
    override suspend fun getLastUsedLocationId(): Int? = throw UnsupportedOperationException()

    override suspend fun deleteByIds(ids: List<String>) {
        items.removeAll { it.id in ids }
        emit()
    }

    fun getItems(): List<ItemEntity> = items.toList()
}

internal class FakeSettingsDao : SettingsDao {
    private val items = mutableListOf<SettingsEntity>()
    private val flow = MutableStateFlow<List<SettingsEntity>>(emptyList())

    private fun emit() { flow.value = items.toList() }

    override suspend fun upsert(setting: SettingsEntity) = throw UnsupportedOperationException()
    override suspend fun getValue(key: String): String? = throw UnsupportedOperationException()
    override fun observeValue(key: String): Flow<String?> = throw UnsupportedOperationException()
    override fun getAll(): Flow<List<SettingsEntity>> = flow

    override suspend fun upsertAll(settings: List<SettingsEntity>) {
        settings.forEach { setting ->
            val idx = items.indexOfFirst { it.key == setting.key }
            if (idx >= 0) items[idx] = setting else items.add(setting)
        }
        emit()
    }

    fun getItems(): List<SettingsEntity> = items.toList()
}

internal val passThroughTransaction = DatabaseTransaction { block -> block() }

internal fun buildItemEntity(id: String = "item1") = ItemEntity(
    id = id,
    name = "Konserve",
    categoryId = 1,
    quantity = 2.0,
    unit = "Stk",
    unitPrice = 1.5,
    kcalPerKg = null,
    expiryDate = null,
    locationId = 1,
    notes = "",
    lastUpdated = 0L
)
