package at.procon.eventhub.processing.eventprocessing.support;

import static org.assertj.core.api.Assertions.assertThat;

import at.procon.eventhub.dto.EventDomain;
import at.procon.eventhub.dto.EventHubEventDto;
import at.procon.eventhub.dto.EventLifecycle;
import at.procon.eventhub.dto.EventType;
import at.procon.eventhub.dto.GeoPointDto;
import at.procon.eventhub.dto.VehicleRefDto;
import at.procon.eventhub.dto.VehicleRegistrationRefDto;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.Test;

class RuntimeSupportEvidenceNormalizerTest {

    private final ObjectMapper objectMapper = new ObjectMapper();
    private final RuntimeSupportEvidenceNormalizer normalizer = new RuntimeSupportEvidenceNormalizer(objectMapper);

    @Test
    void normalizesVehicleOnlyIgnitionWithPositionAsTachographPositionSupportEvidence() {
        EventHubEventDto ignition = vehicleOnlyEvent(
                "ignition-on-1",
                EventDomain.IGNITION,
                EventType.IGNITION_ON,
                EventLifecycle.ON,
                "VIN-1",
                "AT:W-1",
                "2026-05-01T21:30:00Z",
                new GeoPointDto(new BigDecimal("48.2082"), new BigDecimal("16.3738"))
        );

        RuntimeSupportEvidenceNormalizationResult result = normalizer.normalizeForTachographDriver(
                "DRIVER-1",
                List.of(ignition)
        );

        assertThat(result.normalizedSupportEvidenceEventCount()).isEqualTo(1);
        EventHubEventDto normalized = result.normalizedEvents().getFirst();
        assertThat(normalized.eventDomain()).isEqualTo(EventDomain.POSITION);
        assertThat(normalized.eventType()).isEqualTo(EventType.POSITION_RECORDED);
        assertThat(normalized.lifecycle()).isEqualTo(EventLifecycle.SNAPSHOT);
        assertThat(normalized.payload().path("raw").path("driverKey").asText()).isEqualTo("DRIVER-1");
        assertThat(normalized.payload().path("raw").path("supportEventType").asText()).isEqualTo("IGNITION_ON");
        assertThat(normalized.payload().path("raw").path("originalEventDomain").asText()).isEqualTo("IGNITION");
        assertThat(normalized.eventDetails().attributes().path("normalizedSupportEvidence").asBoolean()).isTrue();
    }

    @Test
    void keepsTachographSupportDomainButAddsDriverAndNormalizedRawMetadata() {
        EventHubEventDto border = vehicleOnlyEvent(
                "border-1",
                EventDomain.BORDER_CROSSING,
                EventType.BORDER_INBOUND,
                EventLifecycle.INBOUND,
                "VIN-1",
                "AT:W-1",
                "2026-05-01T22:00:00Z",
                new GeoPointDto(new BigDecimal("48.5"), new BigDecimal("16.5"))
        );

        EventHubEventDto normalized = normalizer.normalizeForTachographDriver("DRIVER-1", List.of(border))
                .normalizedEvents()
                .getFirst();

        assertThat(normalized.eventDomain()).isEqualTo(EventDomain.BORDER_CROSSING);
        assertThat(normalized.eventType()).isEqualTo(EventType.BORDER_INBOUND);
        assertThat(normalized.payload().path("raw").path("driverKey").asText()).isEqualTo("DRIVER-1");
        assertThat(normalized.payload().path("raw").path("supportEventType").asText()).isEqualTo("BORDER_INBOUND");
    }

    @Test
    void doesNotNormalizeActivityOrCardUsageEvents() {
        EventHubEventDto cardUsage = new EventHubEventDto(
                UUID.randomUUID(),
                "card-in-1",
                null,
                vehicleRef("VIN-1", "AT:W-1"),
                OffsetDateTime.parse("2026-05-01T08:00:00Z"),
                null,
                OffsetDateTime.parse("2026-05-01T08:00:00Z"),
                EventDomain.DRIVER_CARD,
                EventType.CARD_INSERTED,
                EventLifecycle.INSERT,
                null,
                null,
                null,
                null,
                raw("DRIVER-1", "VIN-1", "AT:W-1"),
                false,
                null
        );

        RuntimeSupportEvidenceNormalizationResult result = normalizer.normalizeForTachographDriver(
                "DRIVER-1",
                List.of(cardUsage)
        );

        assertThat(result.normalizedSupportEvidenceEventCount()).isZero();
        assertThat(result.normalizedEvents().getFirst()).isSameAs(cardUsage);
    }

    private EventHubEventDto vehicleOnlyEvent(
            String externalId,
            EventDomain domain,
            EventType type,
            EventLifecycle lifecycle,
            String vehicleKey,
            String registrationKey,
            String occurredAt,
            GeoPointDto position
    ) {
        return new EventHubEventDto(
                UUID.randomUUID(),
                externalId,
                null,
                vehicleRef(vehicleKey, registrationKey),
                OffsetDateTime.parse(occurredAt),
                null,
                OffsetDateTime.parse(occurredAt),
                domain,
                type,
                lifecycle,
                123_000L,
                position,
                null,
                null,
                raw(null, vehicleKey, registrationKey),
                false,
                null
        );
    }

    private VehicleRefDto vehicleRef(String vehicleKey, String registrationKey) {
        String[] registrationParts = registrationKey.split(":", 2);
        return new VehicleRefDto(
                "VIN:" + vehicleKey,
                vehicleKey,
                "VR:" + registrationKey,
                new VehicleRegistrationRefDto(registrationParts[0], registrationParts[1])
        );
    }

    private JsonNode raw(String driverKey, String vehicleKey, String registrationKey) {
        ObjectNode root = objectMapper.createObjectNode();
        ObjectNode raw = root.putObject("raw");
        if (driverKey != null) {
            raw.put("driverKey", driverKey);
        }
        raw.put("vehicleKey", vehicleKey);
        raw.put("registrationKey", registrationKey);
        raw.put("sourceKind", "TEST");
        return root;
    }
}
