package com.bytelyst.platform

import kotlinx.coroutines.test.runTest
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

class BLFeatureFlagClientTest {

    private lateinit var server: MockWebServer
    private lateinit var config: BLPlatformConfig

    @BeforeEach
    fun setup() {
        server = MockWebServer()
        server.start()
        config = BLPlatformConfig(
            productId = "testapp",
            baseUrl = server.url("/api").toString().trimEnd('/'),
            applicationId = "com.test.app",
        )
    }

    @AfterEach
    fun teardown() {
        server.shutdown()
    }

    @Test
    fun `isEnabled returns false before init`() {
        val client = BLFeatureFlagClient(config)
        assertFalse(client.isEnabled("any_flag"))
    }

    @Test
    fun `getAllFlags returns empty map before init`() {
        val client = BLFeatureFlagClient(config)
        assertTrue(client.getAllFlags().isEmpty())
    }

    @Test
    fun `refresh fetches flags from server`() = runTest {
        server.enqueue(
            MockResponse()
                .setBody("""{"flags":{"dark_mode":true,"beta_feature":false}}""")
                .setResponseCode(200)
        )

        val client = BLFeatureFlagClient(config)
        client.refresh()

        assertTrue(client.isEnabled("dark_mode"))
        assertFalse(client.isEnabled("beta_feature"))
        assertFalse(client.isEnabled("unknown_flag"))
    }

    @Test
    fun `getAllFlags returns current flags after refresh`() = runTest {
        server.enqueue(
            MockResponse()
                .setBody("""{"flags":{"a":true,"b":false}}""")
                .setResponseCode(200)
        )

        val client = BLFeatureFlagClient(config)
        client.refresh()

        val flags = client.getAllFlags()
        assertEquals(2, flags.size)
        assertTrue(flags["a"] == true)
        assertTrue(flags["b"] == false)
    }

    @Test
    fun `keeps existing flags on server error`() = runTest {
        // First: successful fetch
        server.enqueue(
            MockResponse()
                .setBody("""{"flags":{"feature_x":true}}""")
                .setResponseCode(200)
        )
        // Second: server error
        server.enqueue(MockResponse().setResponseCode(500))

        val client = BLFeatureFlagClient(config)
        client.refresh()
        assertTrue(client.isEnabled("feature_x"))

        client.refresh()
        // Should still have the old flags
        assertTrue(client.isEnabled("feature_x"))
    }

    @Test
    fun `sends platform query parameter`() = runTest {
        server.enqueue(
            MockResponse()
                .setBody("""{"flags":{}}""")
                .setResponseCode(200)
        )

        val client = BLFeatureFlagClient(config)
        client.refresh()

        val recorded = server.takeRequest()
        assertTrue(recorded.path!!.contains("platform=android"))
    }

    @Test
    fun `sends X-Product-Id header`() = runTest {
        server.enqueue(
            MockResponse()
                .setBody("""{"flags":{}}""")
                .setResponseCode(200)
        )

        val client = BLFeatureFlagClient(config)
        client.refresh()

        val recorded = server.takeRequest()
        assertEquals("testapp", recorded.getHeader("X-Product-Id"))
    }

    @Test
    fun `stop cancels polling`() {
        val client = BLFeatureFlagClient(config, pollIntervalMs = 100_000L)
        client.init()
        client.stop()
        // No assertions needed — verifies stop() doesn't throw
    }
}
