package io.sentry.util.network

import io.sentry.ILogger
import java.util.LinkedHashMap
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertTrue
import org.junit.Test
import org.mockito.kotlin.mock

class NetworkDetailCaptureUtilsTest {

  @Test
  fun `createResponse uses originalByteCount when bodySize is unknown`() {
    val logger = mock<ILogger>()
    val jsonBytes = """{"key":"value"}""".toByteArray()

    val result =
      NetworkDetailCaptureUtils.createResponse(
        jsonBytes,
        -1L,
        true,
        { bytes ->
          NetworkBodyParser.fromBytes(bytes, "application/json", null, bytes.size, logger)
        },
        emptyList(),
        { emptyMap() },
      )

    assertEquals(jsonBytes.size.toLong(), result.size)
  }

  @Test
  fun `createResponse keeps explicit bodySize when available`() {
    val logger = mock<ILogger>()
    val jsonBytes = """{"key":"value"}""".toByteArray()

    val result =
      NetworkDetailCaptureUtils.createResponse(
        jsonBytes,
        42L,
        true,
        { bytes ->
          NetworkBodyParser.fromBytes(bytes, "application/json", null, bytes.size, logger)
        },
        emptyList(),
        { emptyMap() },
      )

    assertEquals(42L, result.size)
  }

  @Test
  fun `createResponse keeps null bodySize when body capture is off`() {
    val result =
      NetworkDetailCaptureUtils.createResponse(
        "unused",
        null,
        false,
        { null },
        emptyList(),
        { emptyMap() },
      )

    assertNull(result.size)
  }

  @Test
  fun `getCaptureHeaders should match headers case-insensitively`() {
    // Setup: allHeaders with mixed case keys
    val allHeaders =
      LinkedHashMap<String, String>().apply {
        put("Content-Type", "application/json")
        put("Authorization", "Bearer token123")
        put("X-Custom-Header", "custom-value")
        put("accept", "application/json")
      }

    // Test: allowedHeaders with different casing
    val allowedHeaders = listOf("content-type", "AUTHORIZATION", "x-custom-header", "ACCEPT")

    val result = NetworkDetailCaptureUtils.getCaptureHeaders(allHeaders, allowedHeaders)

    // All headers should be matched despite case differences
    assertEquals(4, result.size)

    // Original casing should be preserved in output
    assertEquals("application/json", result["Content-Type"])
    assertEquals("Bearer token123", result["Authorization"])
    assertEquals("custom-value", result["X-Custom-Header"])
    assertEquals("application/json", result["accept"])

    // Verify keys maintain original casing from allHeaders
    assertTrue(result.containsKey("Content-Type"))
    assertTrue(result.containsKey("Authorization"))
    assertTrue(result.containsKey("X-Custom-Header"))
    assertTrue(result.containsKey("accept"))
  }

  @Test
  fun `getCaptureHeaders should handle null allHeaders`() {
    val allowedHeaders = listOf("content-type")

    val result = NetworkDetailCaptureUtils.getCaptureHeaders(null, allowedHeaders)

    assertTrue(result.isEmpty())
  }

  @Test
  fun `getCaptureHeaders should handle empty allowedHeaders`() {
    val allHeaders = mapOf("Content-Type" to "application/json")
    val allowedHeaders = emptyList<String>()

    val result = NetworkDetailCaptureUtils.getCaptureHeaders(allHeaders, allowedHeaders)

    assertTrue(result.isEmpty())
  }

  @Test
  fun `getCaptureHeaders should only capture allowed headers`() {
    val allHeaders =
      mapOf(
        "Content-Type" to "application/json",
        "Authorization" to "Bearer token123",
        "X-Unwanted-Header" to "should-not-appear",
      )

    val allowedHeaders = listOf("content-type", "authorization")

    val result = NetworkDetailCaptureUtils.getCaptureHeaders(allHeaders, allowedHeaders)

    assertEquals(2, result.size)
    assertEquals("application/json", result["Content-Type"])
    assertEquals("Bearer token123", result["Authorization"])

    // Unwanted header should not be present
    assertTrue(!result.containsKey("X-Unwanted-Header"))
  }

  @Test
  fun `getCaptureHeaders should handle null elements in allowedHeaders`() {
    val allHeaders =
      mapOf(
        "Content-Type" to "application/json",
        "Authorization" to "Bearer token123",
        "X-Custom-Header" to "custom-value",
      )

    // allowedHeaders contains null elements which should be ignored
    val allowedHeaders = listOf(null, "content-type", null, "authorization", null)

    val result = NetworkDetailCaptureUtils.getCaptureHeaders(allHeaders, allowedHeaders)

    // Only non-null allowed headers should be matched
    assertEquals(2, result.size)
    assertEquals("application/json", result["Content-Type"])
    assertEquals("Bearer token123", result["Authorization"])

    // X-Custom-Header should not be present as it's not in the allowed list
    assertTrue(!result.containsKey("X-Custom-Header"))
  }
}
