package at.procon.ted.startup;

import at.procon.ted.config.TedProcessorProperties;
import at.procon.ted.model.entity.VectorizationStatus;
import at.procon.ted.repository.ProcurementDocumentRepository;
import at.procon.dip.runtime.condition.ConditionalOnRuntimeMode;
import at.procon.dip.runtime.config.RuntimeMode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.camel.ProducerTemplate;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.UUID;

/**
 * Startup runner that processes all pending and failed vectorizations on application start.
 *
 * This ensures that any documents that were saved but not yet vectorized
 * or failed during vectorization (e.g., due to service restart or embedding service issues)
 * are immediately queued for (re-)vectorization.
 *
 * Memory efficient: Only loads document IDs, not full entities.
 * Processes in batches to avoid holding database connections for too long.
 *
 * @author Martin.Schweitzer@procon.co.at and claude.ai
 */
@Component
@ConditionalOnRuntimeMode(RuntimeMode.LEGACY)
@RequiredArgsConstructor
@Slf4j
public class VectorizationStartupRunner implements ApplicationRunner {

    private final ProcurementDocumentRepository documentRepository;
    private final ProducerTemplate producerTemplate;
    private final TedProcessorProperties properties;

    private static final int BATCH_SIZE = 1000;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        if (!properties.getVectorization().isEnabled()) {
            log.info("Vectorization is disabled, skipping startup processing");
            return;
        }

        log.info("Checking for pending and failed vectorizations on startup...");

        try {
            int successCount = 0;
            int queueFailedCount = 0;

            // Process PENDING documents first (higher priority)
            successCount += processDocumentsByStatus(VectorizationStatus.PENDING, "PENDING");

            // Then process FAILED documents (retry)
            successCount += processDocumentsByStatus(VectorizationStatus.FAILED, "FAILED");

            if (successCount == 0 && queueFailedCount == 0) {
                log.info("No pending or failed vectorizations found");
                return;
            }

            log.info("Startup vectorization processing completed: {} queued successfully, {} failed to queue",
                    successCount, queueFailedCount);

        } catch (Exception e) {
            log.error("Error during startup vectorization processing: {}", e.getMessage(), e);
        }
    }

    /**
     * Process documents by status in batches to avoid connection leaks.
     */
    private int processDocumentsByStatus(VectorizationStatus status, String statusName) {
        int successCount = 0;
        int page = 0;
        List<UUID> documentIds;

        do {
            // Load batch of document IDs (memory efficient - only IDs, not full entities)
            Pageable pageable = PageRequest.of(page, BATCH_SIZE);
            documentIds = documentRepository.findIdsByVectorizationStatus(status, pageable);

            if (documentIds.isEmpty()) {
                break;
            }

            if (page == 0) {
                log.info("Found {} documents with status {}, processing in batches of {}...",
                        documentIds.size(), statusName, BATCH_SIZE);
            }

            // Queue each document for vectorization
            for (UUID documentId : documentIds) {
                try {
                    producerTemplate.sendBodyAndHeader("direct:vectorize", null, "documentId", documentId);
                    successCount++;
                } catch (Exception e) {
                    log.warn("Failed to queue {} document {} for vectorization: {}",
                            statusName, documentId, e.getMessage());
                }
            }

            page++;

        } while (documentIds.size() == BATCH_SIZE);

        return successCount;
    }
}
