package space.nstart.pcp_tgu_service.service

import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.server.ResponseStatusException
import space.nstart.pcp_tgu_service.entity.PlannedPlanStatus
import space.nstart.pcp_tgu_service.repository.PlannedPlanRepository
import java.time.LocalDateTime
import java.util.UUID
import space.nstart.pcp.pcp_types_lib.utils.UtcDateTimes

/**
 * «Снять с учёта» / «Вернуть на учёт» терминально-негативный план.
 *
 * Оператор деактивирует отменённый/неудавшийся план, чтобы он перестал считаться проблемой и
 * красить индикатор КА. Это чисто косметико-статистический флаг (`dismissed_at`): статус плана
 * и состояние цепочки ([SpacecraftPlanningStateEntity]) НЕ трогаются — план остаётся в истории
 * со своим терминальным статусом, цепочка не возобновляется и не паузится. Операция обратима
 * ([restore]).
 *
 * Снимать с учёта разрешено только терминально-негативные статусы ([DISMISSIBLE_STATUSES]). Живые
 * выдачи, успешный LAID_IN, DRAFT и виртуальный PLANNED этот путь не трогает (422) — у них «снятие
 * с учёта» не имеет смысла.
 */
@Service
class DismissPlanUseCase(
    private val plannedPlanRepository: PlannedPlanRepository
) {
    private val log = LoggerFactory.getLogger(javaClass)

    @Transactional
    fun dismiss(planId: UUID) {
        val plan = plannedPlanRepository.findById(planId)
            .orElseThrow { ResponseStatusException(HttpStatus.NOT_FOUND, "Plan $planId not found") }
        if (plan.status !in DISMISSIBLE_STATUSES) {
            throw ResponseStatusException(
                HttpStatus.UNPROCESSABLE_ENTITY,
                "План $planId в статусе ${plan.status} нельзя снять с учёта — только терминально-негативные " +
                    "($DISMISSIBLE_STATUSES)"
            )
        }
        if (plan.dismissedAt != null) {
            log.info("План {} уже снят с учёта ({}) — идемпотентно", planId, plan.dismissedAt)
            return
        }
        plan.dismissedAt = UtcDateTimes.now()
        plan.updatedAt = UtcDateTimes.now()
        plannedPlanRepository.save(plan)
        log.info("План {} (status={}) снят с учёта", planId, plan.status)
    }

    @Transactional
    fun restore(planId: UUID) {
        val plan = plannedPlanRepository.findById(planId)
            .orElseThrow { ResponseStatusException(HttpStatus.NOT_FOUND, "Plan $planId not found") }
        if (plan.dismissedAt == null) {
            log.info("План {} уже на учёте — идемпотентно", planId)
            return
        }
        plan.dismissedAt = null
        plan.updatedAt = UtcDateTimes.now()
        plannedPlanRepository.save(plan)
        log.info("План {} (status={}) возвращён на учёт", planId, plan.status)
    }

    private companion object {
        /** Терминально-негативные статусы, которые оператор может снять с учёта. */
        val DISMISSIBLE_STATUSES = setOf(
            PlannedPlanStatus.REJECTED,
            PlannedPlanStatus.START_AMBIGUOUS,
            PlannedPlanStatus.LAYIN_FAILED,
            PlannedPlanStatus.NOT_ACCEPTED,
            PlannedPlanStatus.SUPERSEDED
        )
    }
}
