package cn.nianxx.thhotel.workflows.reservation.service.impl;

import cn.nianxx.thhotel.workflows.reservation.common.dto.ReservationTaskSnapshot;
import cn.nianxx.thhotel.workflows.reservation.common.enums.ReservationTaskStatus;
import cn.nianxx.thhotel.workflows.reservation.common.result.ReservationTaskAvailabilityResult;
import cn.nianxx.thhotel.workflows.reservation.repository.ReservationAiWorkflowRepository;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;

/**
 * Reservation 任务实时可处理状态解析器。BLOCKED 不落库，统一按同订单前置任务实时计算。
 */
@Component
public class ReservationTaskAvailabilityResolver {

    private final ReservationAiWorkflowRepository workflowRepository;

    /**
     * 注入工作流持久化边界，用于读取同订单前置队列任务。
     */
    public ReservationTaskAvailabilityResolver(ReservationAiWorkflowRepository workflowRepository) {
        this.workflowRepository = workflowRepository;
    }

    /**
     * 计算任务可处理状态。FAILED 和 COMPLETED 视为前置任务结束，不阻塞后续任务。
     */
    public ReservationTaskAvailabilityResult calculateAvailability(ReservationTaskSnapshot task) {
        if (!Boolean.TRUE.equals(task.queueParticipation())) {
            return calculateAvailability(task, null);
        }
        ReservationTaskSnapshot blockingTask = workflowRepository
                .findQueueTasksBefore(task.hotelId(), task.orderId(), task.executionOrder())
                .stream()
                .filter(this::isBlockingTask)
                .findFirst()
                .orElse(null);
        return calculateAvailability(task, blockingTask);
    }

    /**
     * 批量计算任务可处理状态。调用方需传入目标任务及其同订单完整队列上下文，避免列表接口逐条查询数据库。
     */
    public Map<Long, ReservationTaskAvailabilityResult> calculateAvailabilityByTaskId(
            List<ReservationTaskSnapshot> targetTasks,
            List<ReservationTaskSnapshot> queueContextTasks) {
        if (targetTasks == null || targetTasks.isEmpty()) {
            return Map.of();
        }
        Map<Long, List<ReservationTaskSnapshot>> contextByOrderId = queueContextTasks == null
                ? Map.of()
                : queueContextTasks.stream()
                        .filter(task -> Boolean.TRUE.equals(task.queueParticipation()))
                        .collect(Collectors.groupingBy(ReservationTaskSnapshot::orderId));
        Map<Long, ReservationTaskAvailabilityResult> result = new LinkedHashMap<>();
        for (ReservationTaskSnapshot targetTask : targetTasks) {
            ReservationTaskSnapshot blockingTask = contextByOrderId
                    .getOrDefault(targetTask.orderId(), List.of())
                    .stream()
                    .filter(candidate -> isBefore(candidate, targetTask))
                    .filter(this::isBlockingTask)
                    .sorted(Comparator
                            .comparing(ReservationTaskSnapshot::executionOrder, Comparator.nullsLast(Integer::compareTo))
                            .thenComparing(ReservationTaskSnapshot::id, Comparator.nullsLast(Long::compareTo)))
                    .findFirst()
                    .orElse(null);
            result.put(targetTask.id(), calculateAvailability(targetTask, blockingTask));
        }
        return result;
    }

    /**
     * 根据已知前置阻塞任务生成可处理状态，保证单任务和批量计算规则一致。
     */
    private ReservationTaskAvailabilityResult calculateAvailability(
            ReservationTaskSnapshot task,
            ReservationTaskSnapshot blockingTask) {
        if (!Boolean.TRUE.equals(task.queueParticipation())) {
            return new ReservationTaskAvailabilityResult(false, true, false, false, false, null, null);
        }
        if (blockingTask != null) {
            return new ReservationTaskAvailabilityResult(
                    true,
                    true,
                    false,
                    false,
                    false,
                    blockingTask.id().toString(),
                    "同订单前置任务未完成。");
        }
        boolean pendingConfirm = ReservationTaskStatus.PENDING_CONFIRM.name().equals(task.taskStatus());
        boolean ready = ReservationTaskStatus.READY.name().equals(task.taskStatus());
        return new ReservationTaskAvailabilityResult(false, false, pendingConfirm, pendingConfirm, ready, null, null);
    }

    /**
     * 判断候选任务是否排在目标任务之前；同一执行序号不视为前置任务。
     */
    private boolean isBefore(ReservationTaskSnapshot candidate, ReservationTaskSnapshot targetTask) {
        if (!Objects.equals(targetTask.hotelId(), candidate.hotelId())
                || !Objects.equals(targetTask.orderId(), candidate.orderId())) {
            return false;
        }
        if (candidate.executionOrder() == null || targetTask.executionOrder() == null) {
            return false;
        }
        return candidate.executionOrder() < targetTask.executionOrder();
    }

    /**
     * 判断前置任务是否仍阻塞后续任务。
     */
    private boolean isBlockingTask(ReservationTaskSnapshot task) {
        return !ReservationTaskStatus.COMPLETED.name().equals(task.taskStatus())
                && !ReservationTaskStatus.FAILED.name().equals(task.taskStatus());
    }
}
