package space.nstart.pcp_tgu_service.service

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Service
import org.springframework.web.server.ResponseStatusException
import space.nstart.pcp_tgu_service.domain.PlanDecision
import space.nstart.pcp_tgu_service.dto.PlanDecisionMessage
import space.nstart.pcp_tgu_service.dto.PlanExecutionFeedbackMessage
import space.nstart.pcp_tgu_service.entity.PlanIssueAttemptStatus
import space.nstart.pcp_tgu_service.repository.PlanIssueAttemptRepository
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

/**
 * Test-only helper: генерирует decision event для последней (живой) attempt persisted plan.
 */
@ConditionalOnProperty(prefix = "tgu.test-controller", name = ["enabled"], havingValue = "true")
@Service
class TestPlanDecisionService(
    private val plannedPlanRepository: PlannedPlanRepository,
    private val planIssueAttemptRepository: PlanIssueAttemptRepository,
    private val handlePlanDecisionUseCase: HandlePlanDecisionUseCase
) {
    /**
     * Создаёт synthetic decision event и проводит его через тот же use case, что Kafka consumer.
     * Решение адресуется последней attempt плана напрямую — выдач по КА может быть несколько разом,
     * единого active-слота больше нет.
     */
    fun generateDecision(planId: UUID, decision: PlanDecision, reason: String?): PlanDecisionMessage {
        val plan = plannedPlanRepository.findById(planId).orElse(null)
            ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Plan with planId=$planId was not found")

        val attempt = planIssueAttemptRepository.findTopByPlanIdOrderByAttemptNoDesc(planId)
            ?: throw ResponseStatusException(
                HttpStatus.CONFLICT,
                "Plan $planId has no issue attempt to decide on"
            )
        if (attempt.status !in ACTIVE_ATTEMPT_STATUSES) {
            throw ResponseStatusException(
                HttpStatus.CONFLICT,
                "Attempt ${attempt.attemptId} is already terminal with status=${attempt.status}"
            )
        }

        val message = PlanDecisionMessage(
            eventId = UUID.randomUUID(),
            spacecraftId = plan.spacecraftId,
            planId = plan.planId,
            attemptId = attempt.attemptId,
            decision = decision,
            decisionTime = UtcDateTimes.now(),
            reason = reason?.takeIf { it.isNotBlank() } ?: DEFAULT_REASON
        )
        handlePlanDecisionUseCase.handle(message)
        return message
    }

    /**
     * Создаёт synthetic событие «план заложен» и проводит его через тот же use case, что Kafka
     * consumer ([HandlePlanDecisionUseCase.handleLayinConfirmed]) — для ручной проверки перехода
     * AWAITING_LAYIN → LAID_IN из UI.
     */
    fun generateLayinConfirmed(planId: UUID, reason: String?): PlanExecutionFeedbackMessage {
        val plan = plannedPlanRepository.findById(planId).orElse(null)
            ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Plan with planId=$planId was not found")

        val message = PlanExecutionFeedbackMessage(
            eventId = UUID.randomUUID(),
            spacecraftId = plan.spacecraftId,
            planId = plan.planId,
            occurredAt = UtcDateTimes.now(),
            reason = reason?.takeIf { it.isNotBlank() } ?: DEFAULT_REASON
        )
        handlePlanDecisionUseCase.handleLayinConfirmed(message)
        return message
    }

    private companion object {
        val ACTIVE_ATTEMPT_STATUSES = setOf(PlanIssueAttemptStatus.STARTING, PlanIssueAttemptStatus.STARTED)
        const val DEFAULT_REASON = "TEST_CONTROLLER"
    }
}
