package at.procon.dip.domain.ted.startup;

import at.procon.dip.domain.ted.config.TedProjectionProperties;
import at.procon.dip.domain.ted.repository.TedNoticeProjectionRepository;
import at.procon.dip.domain.ted.service.TedLotDocumentMaterializationService;
import at.procon.dip.domain.ted.service.TedNoticeProjectionService;
import at.procon.dip.runtime.condition.ConditionalOnRuntimeMode;
import at.procon.dip.runtime.config.RuntimeMode;
import at.procon.ted.repository.ProcurementDocumentRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;

/**
 * Optional startup backfill for Phase 3 TED projections and optional TED lot documents.
 */
@Component
@ConditionalOnRuntimeMode(RuntimeMode.NEW)
@RequiredArgsConstructor
@Slf4j
public class TedProjectionStartupRunner implements ApplicationRunner {

    private static final int STARTUP_BACKFILL_BATCH_SIZE = 1000;

    private final TedProjectionProperties properties;
    private final ProcurementDocumentRepository procurementDocumentRepository;
    private final TedNoticeProjectionRepository projectionRepository;
    private final TedNoticeProjectionService projectionService;
    private final TedLotDocumentMaterializationService lotDocumentMaterializationService;

    @Override
    public void run(ApplicationArguments args) {
        if (!properties.isEnabled()) {
            return;
        }

        if (properties.isStartupBackfillEnabled()) {
            backfillNoticeProjections();
        }

        if (properties.getLotDocuments().isEnabled() && properties.getLotDocuments().isStartupBackfillEnabled()) {
            backfillLotDocuments();
        }
    }

    private void backfillNoticeProjections() {
        int limit = properties.getStartupBackfillLimit();
        log.info("Phase 3 startup backfill enabled - ensuring TED projections for {} documents", describeLimit(limit));

        int synced = 0;
        int processed = 0;
        int pageNumber = 0;
        Sort sort = Sort.by(Sort.Direction.ASC, "createdAt");

        while (limit <= 0 || processed < limit) {
            int pageSize = pageSizeFor(limit, processed);
            var page = procurementDocumentRepository.findAll(PageRequest.of(pageNumber++, pageSize, sort));
            if (page.isEmpty()) {
                break;
            }

            for (var legacyDocument : page.getContent()) {
                processed++;
                if (projectionRepository.existsByLegacyProcurementDocumentId(legacyDocument.getId())) {
                    continue;
                }
                projectionService.registerOrRefreshProjection(legacyDocument);
                synced++;
            }

            if (!page.hasNext()) {
                break;
            }
        }

        log.info("Phase 3 startup backfill completed - synced {} TED projections", synced);
    }

    private void backfillLotDocuments() {
        int limit = properties.getLotDocuments().getStartupBackfillLimit();
        log.info("TED lot document startup backfill enabled - materializing lots for {} projections", describeLimit(limit));

        int lotDocuments = 0;
        int processed = 0;
        int pageNumber = 0;
        Sort sort = Sort.by(Sort.Direction.ASC, "createdAt");

        while (limit <= 0 || processed < limit) {
            int pageSize = pageSizeFor(limit, processed);
            var page = projectionRepository.findAll(PageRequest.of(pageNumber++, pageSize, sort));
            if (page.isEmpty()) {
                break;
            }

            for (var projection : page.getContent()) {
                processed++;
                lotDocuments += lotDocumentMaterializationService.materializeProjectionLots(projection.getId());
            }

            if (!page.hasNext()) {
                break;
            }
        }

        log.info("TED lot document startup backfill completed - materialized/updated {} lot documents", lotDocuments);
    }

    private int pageSizeFor(int limit, int processed) {
        if (limit <= 0) {
            return STARTUP_BACKFILL_BATCH_SIZE;
        }
        return Math.min(STARTUP_BACKFILL_BATCH_SIZE, limit - processed);
    }

    private String describeLimit(int limit) {
        return limit > 0 ? "up to " + limit : "all available";
    }
}
