package at.procon.dip.embedding.startup;

import at.procon.dip.embedding.config.EmbeddingProperties;
import at.procon.dip.embedding.service.RepresentationEmbeddingOrchestrator;
import at.procon.dip.embedding.service.ScopedEmbeddingEnqueueResult;
import at.procon.dip.embedding.service.ScopedEmbeddingEnqueueService;
import at.procon.dip.runtime.condition.ConditionalOnRuntimeMode;
import at.procon.dip.runtime.config.RuntimeMode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@ConditionalOnRuntimeMode(RuntimeMode.NEW)
@RequiredArgsConstructor
@Order(Ordered.LOWEST_PRECEDENCE)
@Slf4j
public class EmbeddingStartupRunner implements ApplicationRunner {

    private final EmbeddingProperties properties;
    private final ScopedEmbeddingEnqueueService enqueueService;
    private final RepresentationEmbeddingOrchestrator orchestrator;

    @Override
    public void run(ApplicationArguments args) {
        EmbeddingProperties.StartupProperties startup = properties.getStartup();
        if (!properties.isEnabled() || startup == null) {
            return;
        }

        if (startup.isEnqueueMissingEnabled()) {
            enqueueMissing(startup);
        }

        if (startup.isProcessReadyEnabled()) {
            processReadyJobs();
        }
    }

    private void enqueueMissing(EmbeddingProperties.StartupProperties startup) {
        int batchSize = Math.max(1, startup.getBatchSize());
        long max = startup.getMaxRepresentationsPerRun();
        long remaining = max > 0 ? max : Long.MAX_VALUE;
        int pageNumber = 0;
        long matched = 0;
        long queued = 0;

        log.info("Startup embedding enqueue enabled (documentType={}, representationType={}, builderKey={}, primaryOnly={}, force={}, modelKey={}, maxRepresentationsPerRun={})",
                startup.getDocumentType(), startup.getRepresentationType(), startup.getBuilderKey(), startup.isPrimaryOnly(),
                startup.isForce(), startup.getModelKey(), max > 0 ? max : "unbounded");

        while (remaining > 0) {
            int requested = (int) Math.min(batchSize, remaining);
            ScopedEmbeddingEnqueueResult result = enqueueService.enqueueByDocumentType(
                    startup.getDocumentType(),
                    startup.getRepresentationType(),
                    startup.getBuilderKey(),
                    startup.isPrimaryOnly(),
                    startup.getModelKey(),
                    startup.isForce(),
                    pageNumber,
                    requested
            );

            matched += result.matchedRepresentations();
            queued += result.jobsQueuedOrAlreadyActive();
            remaining -= result.matchedRepresentations();

            if (result.matchedRepresentations() < requested) {
                break;
            }
            pageNumber++;
        }

        log.info("Startup embedding enqueue completed - matched {} representation(s), queued/already-active {} job(s)",
                matched, queued);
    }

    private void processReadyJobs() {
        if (!properties.getJobs().isEnabled()) {
            log.warn("Startup embedding processing was requested but dip.embedding.jobs.enabled=false; queued jobs will not be processed by the NEW embedding job subsystem");
            return;
        }

        int processed = orchestrator.processNextReadyBatch();
        log.info("Startup embedding processing completed - processed {} ready job(s)", processed);
    }
}
