package de.krisenvorrat.server

import de.krisenvorrat.server.db.DatabaseFactory
import de.krisenvorrat.server.model.InventoryStatsDto
import de.krisenvorrat.shared.model.CategoryDto
import de.krisenvorrat.shared.model.InventoryDto
import de.krisenvorrat.shared.model.ItemDto
import de.krisenvorrat.shared.model.LocationDto
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.server.config.*
import io.ktor.server.testing.*
import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test

class InventoryStatsTest {

    private val json = Json { ignoreUnknownKeys = true }
    private val adminToken = createTestAccessToken(
        userId = TEST_ADMIN_ID,
        username = TEST_ADMIN_USERNAME,
        isAdmin = true
    )
    private val userToken = createTestAccessToken(
        userId = TEST_USER_ID,
        username = TEST_USERNAME,
        isAdmin = false
    )

    private fun testApp(block: suspend ApplicationTestBuilder.() -> Unit) = testApplication {
        environment {
            config = MapApplicationConfig(*testMapConfig().toTypedArray())
        }
        application {
            DatabaseFactory.init(
                jdbcUrl = "jdbc:h2:mem:stats_test_${System.nanoTime()};DB_CLOSE_DELAY=-1",
                driver = "org.h2.Driver",
                adminPassword = "test-admin-pw"
            )
            configurePlugins()
        }
        block()
    }

    @Test
    fun test_getStats_asAdmin_returnsStats() = testApp {
        // When
        val response = client.get("/api/admin/stats") { bearerAuth(adminToken) }

        // Then
        assertEquals(HttpStatusCode.OK, response.status)
        val stats = json.decodeFromString<InventoryStatsDto>(response.bodyAsText())
        assertEquals(0L, stats.totalItems)
        assertEquals(0L, stats.totalLocations)
        assertEquals(0L, stats.totalCategories)
        assertNull(stats.lastUpdated)
        assertEquals(0L, stats.recentTransactions)
    }

    @Test
    fun test_getStats_asNonAdmin_returns403() = testApp {
        // When
        val response = client.get("/api/admin/stats") { bearerAuth(userToken) }

        // Then
        assertEquals(HttpStatusCode.Forbidden, response.status)
    }

    @Test
    fun test_getStats_noToken_returns401() = testApp {
        // When
        val response = client.get("/api/admin/stats")

        // Then
        assertEquals(HttpStatusCode.Unauthorized, response.status)
    }

    @Test
    fun test_getStats_withInventoryData_returnsCorrectCounts() = testApp {
        // Given – upload inventory data
        val inventory = InventoryDto(
            categories = listOf(
                CategoryDto(id = 1, name = "Konserven"),
                CategoryDto(id = 2, name = "Getränke")
            ),
            locations = listOf(
                LocationDto(id = 1, name = "Keller"),
                LocationDto(id = 2, name = "Speisekammer"),
                LocationDto(id = 3, name = "Garage")
            ),
            items = listOf(
                ItemDto(id = "i1", name = "Dosenbrot", categoryId = 1, quantity = 5.0, unit = "Stk",
                    unitPrice = 3.99, kcalPerKg = null, expiryDate = null, locationId = 1, notes = "",
                    lastUpdated = System.currentTimeMillis()),
                ItemDto(id = "i2", name = "Wasser", categoryId = 2, quantity = 10.0, unit = "L",
                    unitPrice = 0.5, kcalPerKg = null, expiryDate = null, locationId = 2, notes = "",
                    lastUpdated = System.currentTimeMillis())
            ),
            settings = emptyList()
        )
        val putResponse = client.put("/api/inventory") {
            bearerAuth(createTestAccessToken(userId = TEST_ADMIN_ID, username = TEST_ADMIN_USERNAME, isAdmin = true))
            contentType(ContentType.Application.Json)
            setBody(Json.encodeToString(InventoryDto.serializer(), inventory))
        }
        assertEquals(HttpStatusCode.OK, putResponse.status)

        // When
        val response = client.get("/api/admin/stats") { bearerAuth(adminToken) }

        // Then
        assertEquals(HttpStatusCode.OK, response.status)
        val stats = json.decodeFromString<InventoryStatsDto>(response.bodyAsText())
        assertEquals(2L, stats.totalItems)
        assertEquals(3L, stats.totalLocations)
        assertEquals(2L, stats.totalCategories)
        assertEquals(2L, stats.recentTransactions)
    }
}
