package engineer.carrot.warren.warren.handler

import engineer.carrot.warren.kale.irc.message.rfc1459.KickMessage
import engineer.carrot.warren.kale.irc.message.utility.CaseMapping
import engineer.carrot.warren.warren.state.*
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test

class KickHandlerTests {

    lateinit var handler: KickHandler
    lateinit var connectionState: ConnectionState
    lateinit var channelsState: ChannelsState
    val caseMappingState = CaseMappingState(mapping = CaseMapping.RFC1459)

    @Before fun setUp() {
        val lifecycleState = LifecycleState.DISCONNECTED

        connectionState = ConnectionState(server = "test.server", port = 6697, nickname = "test-nick", user = "test-nick", lifecycle = lifecycleState)
        channelsState = emptyChannelsState(caseMappingState)
        handler = KickHandler(connectionState, channelsState.joined, caseMappingState)
    }

    @Test fun test_handle_SingleNick_MultipleUsers_RemovesUserFromChannels() {
        channelsState.joined += ChannelState(name = "#channel", users = generateUsers("someone", "someone-else", mappingState = caseMappingState))
        channelsState.joined += ChannelState(name = "#channel2", users = generateUsers("another-person", "someone-else", mappingState = caseMappingState))

        handler.handle(KickMessage(users = listOf("someone"), channels = listOf("#channel", "#channel2")), mapOf())

        val expectedChannelOneState = ChannelState(name = "#channel", users = generateUsers("someone-else", mappingState = caseMappingState))
        val expectedChannelTwoState = ChannelState(name = "#channel2", users = generateUsers("another-person", "someone-else", mappingState = caseMappingState))
        val expectedChannelsState = channelsStateWith(listOf(expectedChannelOneState, expectedChannelTwoState), caseMappingState)

        assertEquals(channelsState, expectedChannelsState)
    }

    @Test fun test_handle_MultipleNicks_NotSelf_RemovesFromChannel() {
        channelsState.joined += ChannelState(name = "#channel", users = generateUsers("someone", "someone-else", "last-person", mappingState = caseMappingState))

        handler.handle(KickMessage(users = listOf("someone", "someone-else"), channels = listOf("#channel")), mapOf())

        val expectedChannelOneState = ChannelState(name = "#channel", users = generateUsers("last-person", mappingState = caseMappingState))
        val expectedChannelsState = channelsStateWith(listOf(expectedChannelOneState), caseMappingState)

        assertEquals(channelsState, expectedChannelsState)
    }

    @Test fun test_handle_UserNotInChannel_DoesNothing() {
        channelsState.joined += ChannelState(name = "#channel", users = generateUsers("someone", mappingState = caseMappingState))

        handler.handle(KickMessage(users = listOf("nonexistent-user"), channels = listOf("#channel")), mapOf())

        val expectedChannelOneState = ChannelState(name = "#channel", users = generateUsers("someone", mappingState = caseMappingState))
        val expectedChannelsState = channelsStateWith(listOf(expectedChannelOneState), caseMappingState)

        assertEquals(channelsState, expectedChannelsState)
    }

    @Test fun test_handle_KickSelf_LeavesChannel() {
        channelsState.joined += ChannelState(name = "#channel", users = generateUsers("test-nick", mappingState = caseMappingState))

        handler.handle(KickMessage(users = listOf("test-nick"), channels = listOf("#channel")), mapOf())

        val expectedChannelsState = emptyChannelsState(caseMappingState)

        assertEquals(channelsState, expectedChannelsState)
    }

}