package dev.m1sk9.lunaticChat.paper.command.impl.lc.channel

import dev.m1sk9.lunaticChat.engine.chat.channel.Channel
import dev.m1sk9.lunaticChat.engine.chat.channel.ChannelRole
import dev.m1sk9.lunaticChat.engine.command.CommandResult
import dev.m1sk9.lunaticChat.paper.LunaticChat
import dev.m1sk9.lunaticChat.paper.TestUtils
import dev.m1sk9.lunaticChat.paper.chat.channel.ChannelManager
import dev.m1sk9.lunaticChat.paper.chat.channel.ChannelMembershipManager
import dev.m1sk9.lunaticChat.paper.command.core.CommandContext
import dev.m1sk9.lunaticChat.paper.i18n.LanguageManager
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.unmockkStatic
import io.mockk.verify
import org.bukkit.Bukkit
import org.bukkit.OfflinePlayer
import java.util.UUID
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertIs

class ChannelOwnershipCommandTest {
    private val testUUID = UUID.fromString("00000001-0000-0000-0000-000000000000")
    private val targetUUID = UUID.fromString("00000002-0000-0000-0000-000000000000")
    private val channelId = "test-ch"

    private val plugin = mockk<LunaticChat>(relaxed = true)
    private val channelManager = mockk<ChannelManager>(relaxed = true)
    private val membershipManager = mockk<ChannelMembershipManager>(relaxed = true)
    private val languageManager = mockk<LanguageManager>(relaxed = true)

    private val command = ChannelOwnershipCommand(plugin, channelManager, membershipManager, languageManager)

    @BeforeTest
    fun setUp() {
        mockkStatic(Bukkit::class)
        every { languageManager.getMessage(any(), any()) } returns "test message"
    }

    @AfterTest
    fun tearDown() {
        unmockkStatic(Bukkit::class)
    }

    private fun createContext(): CommandContext {
        val mockPlayer = TestUtils.createMockPlayer(uuid = testUUID, name = "Player1")
        val ctx = mockk<CommandContext>(relaxed = true)
        every { ctx.requirePlayer() } returns mockPlayer
        return ctx
    }

    private fun setupOfflinePlayer(
        hasPlayedBefore: Boolean = true,
        isOnline: Boolean = false,
    ): OfflinePlayer {
        val offlinePlayer = mockk<OfflinePlayer>(relaxed = true)
        every { offlinePlayer.uniqueId } returns targetUUID
        every { offlinePlayer.hasPlayedBefore() } returns hasPlayedBefore
        every { offlinePlayer.isOnline } returns isOnline
        every { offlinePlayer.name } returns "TargetPlayer"
        every { Bukkit.getOfflinePlayer(any<String>()) } returns offlinePlayer
        return offlinePlayer
    }

    @Test
    fun `execute should transfer ownership successfully`() {
        val ctx = createContext()
        every { channelManager.getPlayerChannel(testUUID) } returns channelId
        every { membershipManager.getMemberRoleOrNull(testUUID, channelId) } returns ChannelRole.OWNER
        setupOfflinePlayer()
        every { membershipManager.getMemberRoleOrNull(targetUUID, channelId) } returns ChannelRole.MEMBER

        val updatedChannel = Channel(id = channelId, name = "Test Channel", ownerId = targetUUID, createdAt = 1000L)
        every { channelManager.updateChannelOwner(channelId, targetUUID) } returns Result.success(updatedChannel)
        every { Bukkit.getPlayer(any<String>()) } returns null

        val result = command.execute(ctx, "TargetPlayer")

        assertIs<CommandResult.SuccessWithMessage>(result)
        verify { channelManager.updateChannelOwner(channelId, targetUUID) }
    }

    @Test
    fun `execute should return Failure when transferring to self`() {
        val ctx = createContext()
        every { channelManager.getPlayerChannel(testUUID) } returns channelId
        every { membershipManager.getMemberRoleOrNull(testUUID, channelId) } returns ChannelRole.OWNER

        val offlinePlayer = mockk<OfflinePlayer>(relaxed = true)
        every { offlinePlayer.uniqueId } returns testUUID
        every { offlinePlayer.hasPlayedBefore() } returns true
        every { offlinePlayer.isOnline } returns false
        every { offlinePlayer.name } returns "Player1"
        every { Bukkit.getOfflinePlayer(any<String>()) } returns offlinePlayer

        val result = command.execute(ctx, "Player1")

        assertIs<CommandResult.Failure>(result)
    }

    @Test
    fun `execute should return Failure when target not member`() {
        val ctx = createContext()
        every { channelManager.getPlayerChannel(testUUID) } returns channelId
        every { membershipManager.getMemberRoleOrNull(testUUID, channelId) } returns ChannelRole.OWNER
        setupOfflinePlayer()
        every { membershipManager.getMemberRoleOrNull(targetUUID, channelId) } returns null

        val result = command.execute(ctx, "TargetPlayer")

        assertIs<CommandResult.Failure>(result)
    }

    @Test
    fun `execute should return Failure when not owner`() {
        val ctx = createContext()
        every { channelManager.getPlayerChannel(testUUID) } returns channelId
        every { membershipManager.getMemberRoleOrNull(testUUID, channelId) } returns ChannelRole.MODERATOR

        val result = command.execute(ctx, "TargetPlayer")

        assertIs<CommandResult.Failure>(result)
    }

    @Test
    fun `execute should return Failure when player not found`() {
        val ctx = createContext()
        every { channelManager.getPlayerChannel(testUUID) } returns channelId
        every { membershipManager.getMemberRoleOrNull(testUUID, channelId) } returns ChannelRole.OWNER
        setupOfflinePlayer(hasPlayedBefore = false, isOnline = false)

        val result = command.execute(ctx, "TargetPlayer")

        assertIs<CommandResult.Failure>(result)
    }
}
