package com.pubnub.api.endpoints.channel_groups

import com.github.tomakehurst.wiremock.client.WireMock.*
import com.pubnub.api.BaseTest
import com.pubnub.api.PubNubError
import com.pubnub.api.assertPnException
import com.pubnub.api.enums.PNOperationType
import com.pubnub.api.enums.PNStatusCategory
import org.awaitility.Awaitility
import org.hamcrest.core.IsEqual
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger

class RemoveChannelChannelGroupEndpointTest : BaseTest() {

    @Test
    fun testSyncSuccess() {
        stubFor(
            get(urlPathEqualTo("/v1/channel-registration/sub-key/mySubscribeKey/channel-group/groupA"))
                .willReturn(
                    aResponse().withBody(
                        "{\"status\": 200, \"message\": \"OK\", \"payload\": {}, " +
                                "\"service\": \"ChannelGroups\"}"
                    )
                )
        )

        pubnub.removeChannelsFromChannelGroup().apply {
            channelGroup = "groupA"
            channels = arrayListOf("ch1", "ch2")
        }.sync()!!
    }

    @Test
    fun testSyncMissingGroup() {
        stubFor(
            get(urlPathEqualTo("/v1/channel-registration/sub-key/mySubscribeKey/channel-group/groupA"))
                .willReturn(
                    aResponse().withBody(
                        "{\"status\": 200, \"message\": \"OK\", \"payload\": {}, " +
                                "\"service\": \"ChannelGroups\"}"
                    )
                )
        )

        try {
            pubnub.removeChannelsFromChannelGroup().apply {
                channels = arrayListOf("ch1", "ch2")
            }.sync()!!
        } catch (e: Exception) {
            assertPnException(PubNubError.GROUP_MISSING, e)
        }
    }

    @Test
    fun testSyncMissingChannel() {
        stubFor(
            get(urlPathEqualTo("/v1/channel-registration/sub-key/mySubscribeKey/channel-group/groupA"))
                .willReturn(
                    aResponse().withBody(
                        "{\"status\": 200, \"message\": \"OK\", \"payload\": {}, " +
                                "\"service\": \"ChannelGroups\"}"
                    )
                )
        )

        try {
            pubnub.removeChannelsFromChannelGroup().apply {
                channelGroup = "groupA"
            }.sync()!!
        } catch (e: Exception) {
            assertPnException(PubNubError.CHANNEL_MISSING, e)
        }
    }

    @Test
    fun testIsAuthRequiredSuccessSync() {
        stubFor(
            get(urlPathEqualTo("/v1/channel-registration/sub-key/mySubscribeKey/channel-group/groupA"))
                .willReturn(
                    aResponse().withBody(
                        "{\"status\": 200, \"message\": \"OK\", \"payload\": {}, " +
                                "\"service\": \"ChannelGroups\"}"
                    )
                )
        )

        pubnub.configuration.authKey = "myKey"

        pubnub.removeChannelsFromChannelGroup().apply {
            channelGroup = "groupA"
            channels = arrayListOf("ch1", "ch2")
        }.sync()!!

        val requests = findAll(getRequestedFor(urlMatching("/.*")))
        assertEquals(1, requests.size)
        assertEquals("myKey", requests[0].queryParameter("auth").firstValue())
    }

    @Test
    fun testOperationTypeSuccessAsync() {
        stubFor(
            get(urlPathEqualTo("/v1/channel-registration/sub-key/mySubscribeKey/channel-group/groupA"))
                .willReturn(
                    aResponse().withBody(
                        "{\"status\": 200, \"message\": \"OK\", \"payload\": {}, " +
                                "\"service\": \"ChannelGroups\"}"
                    )
                )
        )

        val atomic = AtomicInteger(0)

        pubnub.removeChannelsFromChannelGroup().apply {
            channelGroup = "groupA"
            channels = arrayListOf("ch1", "ch2")
        }.async { _, status ->
            Assertions.assertFalse(status.error)
            assertEquals(PNOperationType.PNRemoveChannelsFromGroupOperation, status.operation)
            assertEquals(PNStatusCategory.PNAcknowledgmentCategory, status.category)
            Assertions.assertTrue(status.affectedChannels == listOf("ch1", "ch2"))
            Assertions.assertTrue(status.affectedChannelGroups == listOf("groupA"))
            atomic.incrementAndGet()
        }

        Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAtomic(atomic, IsEqual.equalTo(1))
    }

}