package space.nstart.pcp_tgu_service.service

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.mockito.ArgumentMatchers
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.doThrow
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.springframework.http.HttpStatus
import org.springframework.web.server.ResponseStatusException
import space.nstart.pcp_tgu_service.entity.PlannedPlanEntity
import space.nstart.pcp_tgu_service.entity.PlannedPlanStatus
import space.nstart.pcp_tgu_service.integration.api.MissionPlaningClient
import space.nstart.pcp_tgu_service.repository.PlannedPlanRepository
import java.time.LocalDateTime
import java.util.Optional
import java.util.UUID

class DeleteDraftUseCaseTest {

    private val store = linkedMapOf<UUID, PlannedPlanEntity>()
    private val repo = mock(PlannedPlanRepository::class.java).also { repo ->
        `when`(repo.findById(anyUuid())).thenAnswer { inv -> Optional.ofNullable(store[inv.arguments[0]]) }
        doAnswer { inv -> store.remove((inv.arguments[0] as PlannedPlanEntity).planId); null }
            .`when`(repo).delete(anyNonNull())
    }
    private val client = mock(MissionPlaningClient::class.java)
    private val useCase = DeleteDraftUseCase(repo, client)

    @Test
    fun `deletes the DRAFT row and its cloned mission`() {
        val draft = plan(PlannedPlanStatus.DRAFT)
        store[draft.planId] = draft

        useCase.deleteDraft(draft.planId)

        assertFalse(store.containsKey(draft.planId))
        verify(client).deleteMission(draft.planId)
    }

    @Test
    fun `unknown plan yields 404`() {
        val ex = assertThrows<ResponseStatusException> { useCase.deleteDraft(UUID.randomUUID()) }
        assertEquals(HttpStatus.NOT_FOUND, ex.statusCode)
        verify(client, never()).deleteMission(anyUuid())
    }

    @Test
    fun `refuses to delete a non-DRAFT plan with 422 and touches nothing`() {
        val live = plan(PlannedPlanStatus.AWAITING_LAYIN)
        store[live.planId] = live

        val ex = assertThrows<ResponseStatusException> { useCase.deleteDraft(live.planId) }

        assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, ex.statusCode)
        assertTrue(store.containsKey(live.planId))
        verify(client, never()).deleteMission(anyUuid())
    }

    @Test
    fun `a failed mission delete still removes the DRAFT row (best-effort)`() {
        val draft = plan(PlannedPlanStatus.DRAFT)
        store[draft.planId] = draft
        doThrow(RuntimeException("mission-planing down")).`when`(client).deleteMission(anyUuid())

        useCase.deleteDraft(draft.planId)

        assertFalse(store.containsKey(draft.planId))
    }

    private fun plan(status: PlannedPlanStatus): PlannedPlanEntity =
        PlannedPlanEntity(
            planId = UUID.randomUUID(),
            spacecraftId = "25544",
            startTime = LocalDateTime.now().plusHours(3),
            endTime = LocalDateTime.now().plusHours(4),
            kppId = "KPP-1",
            status = status
        )

    @Suppress("UNCHECKED_CAST")
    private fun <T> anyNonNull(): T { ArgumentMatchers.any<T>(); return null as T }
    private fun anyUuid(): UUID { ArgumentMatchers.any<UUID>(); return UUID.randomUUID() }
}
