package at.procon.eventhub.tachograph.service;

import at.procon.eventhub.config.EventHubProperties;
import at.procon.eventhub.dto.EventSourceDto;
import at.procon.eventhub.dto.ImportCursorStateDto;
import at.procon.eventhub.dto.ImportScopeDto;
import at.procon.eventhub.importing.ImportPlanItemDto;
import at.procon.eventhub.importing.ImportTimeChunkDto;
import at.procon.eventhub.importing.extraction.AbstractJdbcExtractionBatchExecutor;
import at.procon.eventhub.importing.extraction.ExtractionDefinition;
import at.procon.eventhub.importing.persistence.ImportCursorRepository;
import at.procon.eventhub.service.EventHubIngestionService;
import at.procon.eventhub.tachograph.dto.TachographExtractionBatchResultDto;
import at.procon.eventhub.tachograph.dto.TachographImportRequest;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.apache.camel.ProducerTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;

@Service
@ConditionalOnBean(name = "tachographNamedParameterJdbcTemplate")
@ConditionalOnExpression("T(org.springframework.util.StringUtils).hasText('${eventhub.tachograph.datasource.jdbc-url:}')")
public class JdbcTachographExtractionBatchExecutor
        extends AbstractJdbcExtractionBatchExecutor<TachographImportRequest, TachographExtractionBatchResultDto>
        implements TachographExtractionBatchExecutor {

    private final TachographExtractionDefinitionRegistry definitionRegistry;

    public JdbcTachographExtractionBatchExecutor(
            @Qualifier("tachographNamedParameterJdbcTemplate") NamedParameterJdbcTemplate tachographJdbcTemplate,
            EventHubIngestionService ingestionService,
            ProducerTemplate producerTemplate,
            EventHubProperties eventHubProperties,
            ResourceLoader resourceLoader,
            TachographExtractionDefinitionRegistry definitionRegistry,
            ImportCursorRepository importCursorRepository
    ) {
        super(tachographJdbcTemplate, ingestionService, producerTemplate, eventHubProperties, resourceLoader, importCursorRepository);
        this.definitionRegistry = definitionRegistry;
    }

    @Override
    protected Optional<ExtractionDefinition<TachographImportRequest>> findDefinition(String code) {
        return definitionRegistry.findByCode(code);
    }

    @Override
    protected Map<String, Object> parameters(
            TachographImportRequest request,
            ImportScopeDto scope,
            ImportCursorStateDto cursor
    ) {
        Map<String, Object> params = super.parameters(request, scope, cursor);
        params.put("occurredFrom", utcLocalDateTime(scope == null ? null : scope.occurredFrom()));
        params.put("occurredTo", utcLocalDateTime(scope == null ? null : scope.occurredTo()));
        params.put("lastSourcePackageImportedAt", utcLocalDateTime(cursor == null ? null : cursor.lastSourcePackageImportedAt()));
        params.put("lastSourceRowUpdatedAt", utcLocalDateTime(cursor == null ? null : cursor.lastSourceRowUpdatedAt()));
        params.put("lastOccurredTo", utcLocalDateTime(cursor == null ? null : cursor.lastOccurredTo()));
        return params;
    }

    @Override
    protected TachographExtractionBatchResultDto resultFor(
            UUID packageId,
            ImportPlanItemDto planItem,
            ImportTimeChunkDto chunk,
            ImportCursorStateDto cursor,
            ExtractedEventStats stats
    ) {
        return new TachographExtractionBatchResultDto(
                packageId,
                planItem.extractionCode(),
                planItem.sourceKind(),
                stats.eventsMapped(),
                stats.eventsMapped(),
                eventsInsertedOrSubmitted(stats),
                0,
                true,
                lastSourcePackageImportedAt(stats, cursor),
                lastSourcePackageId(stats, cursor),
                null,
                chunk.occurredTo(),
                stats.eventTypeCounts()
        );
    }

    @Override
    protected EventSourceDto eventSourceFor(TachographImportRequest request, ImportPlanItemDto planItem) {
        String sourceKey = switch (planItem.sourceKind()) {
            case "VEHICLE_UNIT" -> "TACHOGRAPH_VEHICLE_UNIT";
            case "DRIVER_CARD" -> "TACHOGRAPH_DRIVER_CARD";
            default -> request.eventSource().sourceKey();
        };
        return new EventSourceDto(
                request.eventSource().providerKey(),
                planItem.sourceKind(),
                sourceKey,
                request.eventSource().sourceInstanceKey(),
                request.eventSource().tenantProviderSettingKey(),
                request.eventSource().externalFleetKey()
        );
    }

    @Override
    protected String providerPackagePrefix() {
        return "TACHOGRAPH";
    }

    private LocalDateTime utcLocalDateTime(OffsetDateTime value) {
        return value == null ? null : value.withOffsetSameInstant(ZoneOffset.UTC).toLocalDateTime();
    }
}
