package at.procon.eventhub.dto;

import com.fasterxml.jackson.databind.JsonNode;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.OffsetDateTime;
import java.util.UUID;

/**
 * Normalized acquisition event.
 *
 * It is a point event: it has exactly one occurredAt timestamp. Duration/end
 * time are not part of the generic EventHub event contract. If a source row
 * describes an interval, the acquisition mapper may emit multiple point events.
 */
public record EventHubEventDto(
        UUID eventId,

        /** Stable id of this imported/source event record. */
        @NotBlank String externalSourceEventId,

        /** Source-side driver reference. No internal driver id is required during acquisition. */
        @Valid DriverRefDto driverRef,

        /** Source-side vehicle reference. VIN can be absent when only driver-card data is available. */
        @Valid VehicleRefDto vehicleRef,

        @NotNull OffsetDateTime occurredAt,
        OffsetDateTime receivedPartnerAt,
        OffsetDateTime receivedHubAt,

        @NotNull EventDomain eventDomain,
        @NotNull EventType eventType,
        @NotNull EventLifecycle lifecycle,

        Long odometerM,
        @Valid GeoPointDto position,

        /** Normalized semantic details depending on eventDomain/eventType. */
        @Valid EventDetailsDto eventDetails,

        /** Optional reference to the original source package/card/VU download containing this source record. */
        @Valid SourcePackageRefDto sourcePackageRef,

        /** Raw/provider-specific payload, stored as real JSON and not as encoded JSON string. */
        JsonNode payload,

        boolean manualEntry,

        /** Package/source context used by Camel acquisition routes for grouping and batching. */
        @Valid EventHubPackageRequest packageInfo
) {
    public EventHubEventDto {
        boolean hasDriver = driverRef != null && driverRef.hasAnyReference();
        boolean hasVehicle = vehicleRef != null && vehicleRef.hasAnyReference();
        if (!hasDriver && !hasVehicle) {
            throw new IllegalArgumentException("driverRef or vehicleRef with at least one identifier must be set");
        }
    }

    public EventHubEventDto withEventId(UUID newEventId) {
        return new EventHubEventDto(
                newEventId,
                externalSourceEventId,
                driverRef,
                vehicleRef,
                occurredAt,
                receivedPartnerAt,
                receivedHubAt,
                eventDomain,
                eventType,
                lifecycle,
                odometerM,
                position,
                eventDetails,
                sourcePackageRef,
                payload,
                manualEntry,
                packageInfo
        );
    }

    public EventHubEventDto withReceivedHubAt(OffsetDateTime value) {
        return new EventHubEventDto(
                eventId,
                externalSourceEventId,
                driverRef,
                vehicleRef,
                occurredAt,
                receivedPartnerAt,
                value,
                eventDomain,
                eventType,
                lifecycle,
                odometerM,
                position,
                eventDetails,
                sourcePackageRef,
                payload,
                manualEntry,
                packageInfo
        );
    }

    public EventHubEventDto withPackageInfo(EventHubPackageRequest value) {
        return new EventHubEventDto(
                eventId,
                externalSourceEventId,
                driverRef,
                vehicleRef,
                occurredAt,
                receivedPartnerAt,
                receivedHubAt,
                eventDomain,
                eventType,
                lifecycle,
                odometerM,
                position,
                eventDetails,
                sourcePackageRef,
                payload,
                manualEntry,
                value
        );
    }
}
