package at.procon.eventhub.tachographfilesession.service;

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

import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
import at.procon.eventhub.tachographfilesession.model.TachographFileSessionMetadata;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import org.junit.jupiter.api.Test;

class DriverCardXmlExtractionServiceTest {

    private final TachographXmlParser parser = new TachographXmlParser();
    private final DriverCardXmlExtractionService service = new DriverCardXmlExtractionService(
            new DriverKeyFactory(),
            new VehicleKeyFactory()
    );

    @Test
    void extractsDriverCardVehiclesAndActivities() {
        TachographFileSession session = service.extract(
                parser.parse(DriverCardXmlSamples.validDriverCardXml()),
                new TachographFileSessionMetadata(
                        "default",
                        "legalrequirements-drivercard",
                        "sample",
                        "sample.ddd",
                        "abc",
                        10,
                        "42",
                        "def",
                        true,
                        null
                ),
                Instant.now(),
                Instant.now().plus(4, ChronoUnit.HOURS)
        );

        assertThat(session.driversByKey()).hasSize(1);
        DriverExtractionSession driver = session.driversByKey().values().iterator().next();
        assertThat(driver.driverKey()).isEqualTo("12:12345678901200");
        assertThat(driver.driver().surname()).isEqualTo("Muster");
        assertThat(driver.driverCard().sourceDriverCardId()).isEqualTo("CARD:12:12345678901200");
        assertThat(driver.vehicleRegistrations()).hasSize(2);
        assertThat(driver.vehicles()).hasSize(2);
        assertThat(driver.cardVehicleUsageIntervals()).hasSize(2);
        assertThat(driver.cardActivityIntervals()).hasSize(3);
        assertThat(driver.cardActivityIntervals().get(0).registrationKey()).isEqualTo("12:W-12345A");
        assertThat(driver.cardActivityIntervals().get(1).to()).isEqualTo(driver.cardVehicleUsageIntervals().get(0).to().plusSeconds(1));
        assertThat(driver.cardActivityIntervals().get(2).registrationKey()).isEqualTo("12:W-54321B");
        assertThat(driver.supportEvents()).hasSize(5);
        assertThat(driver.supportEvents()).extracting("eventDomain")
                .containsExactly("PLACE", "POSITION", "SPECIFIC_CONDITION", "BORDER_CROSSING", "LOAD_UNLOAD");
        assertThat(driver.supportEvents().get(2).eventType()).isEqualTo("FERRY_TRAIN");
        assertThat(driver.supportEvents().get(2).eventLifecycle()).isEqualTo("BEGIN");
        assertThat(driver.supportEvents().get(3).countryFrom()).isEqualTo("12");
        assertThat(driver.supportEvents().get(4).operation()).isEqualTo("UNLOAD");
    }

    @Test
    void extractsActivitiesWhenTimeOfChangeHasNoOffset() {
        TachographFileSession session = service.extract(
                parser.parse(DriverCardXmlSamples.validDriverCardXmlWithLocalActivityTimes()),
                new TachographFileSessionMetadata(
                        "default",
                        "legalrequirements-drivercard",
                        "sample",
                        "sample.ddd",
                        "abc",
                        10,
                        "42",
                        "def",
                        true,
                        null
                ),
                Instant.now(),
                Instant.now().plus(4, ChronoUnit.HOURS)
        );

        DriverExtractionSession driver = session.driversByKey().values().iterator().next();
        assertThat(driver.cardActivityIntervals()).hasSize(3);
        assertThat(driver.cardActivityIntervals())
                .extracting(interval -> interval.from().toString())
                .contains("2026-04-01T08:00Z", "2026-04-01T12:00Z");
    }

    @Test
    void keepsLastOpenVehicleUseRecordWithoutSynthesizingActivityTail() {
        TachographFileSession session = service.extract(
                parser.parse(DriverCardXmlSamples.driverCardXmlWithOpenVehicleUseRecord()),
                new TachographFileSessionMetadata(
                        "default",
                        "legalrequirements-drivercard",
                        "sample",
                        "sample.ddd",
                        "abc",
                        10,
                        "42",
                        "def",
                        true,
                        null
                ),
                Instant.now(),
                Instant.now().plus(4, ChronoUnit.HOURS)
        );

        DriverExtractionSession driver = session.driversByKey().values().iterator().next();
        assertThat(driver.cardVehicleUsageIntervals()).hasSize(2);
        assertThat(driver.cardVehicleUsageIntervals().get(1).to()).isNull();
        assertThat(driver.cardActivityIntervals()).hasSize(3);
        assertThat(driver.cardActivityIntervals().get(2).registrationKey()).isEqualTo("12:W-54321B");
        assertThat(driver.supportEvents()).hasSize(5);
        assertThat(driver.supportEvents().stream()
                .filter(event -> "12:W-54321B".equals(event.registrationKey()))
                .map(event -> event.eventDomain() + ":" + event.eventType()))
                .containsExactly("BORDER_CROSSING:BORDER_OUTBOUND", "LOAD_UNLOAD:UNLOAD");
    }

    @Test
    void ignoresSupportEventsWhenVehicleRegistrationIsUnknown() {
        String xml = DriverCardXmlSamples.validDriverCardXml()
                .replace("<vehicleRegNumber>W-12345A</vehicleRegNumber>", "<vehicleRegNumber></vehicleRegNumber>")
                .replace("<vehicleRegNumber>W-54321B</vehicleRegNumber>", "<vehicleRegNumber></vehicleRegNumber>");

        TachographFileSession session = service.extract(
                parser.parse(xml),
                new TachographFileSessionMetadata(
                        "default",
                        "legalrequirements-drivercard",
                        "sample",
                        "sample.ddd",
                        "abc",
                        10,
                        "42",
                        "def",
                        true,
                        null
                ),
                Instant.now(),
                Instant.now().plus(4, ChronoUnit.HOURS)
        );

        DriverExtractionSession driver = session.driversByKey().values().iterator().next();
        assertThat(driver.cardVehicleUsageIntervals()).hasSize(2);
        assertThat(driver.cardVehicleUsageIntervals()).extracting("registrationKey")
                .containsOnly("12:UNKNOWN");
        assertThat(driver.supportEvents()).isEmpty();
    }

    @Test
    void usesCanonicalCardNumberForDriverIdentityAndKeepsFullCardNumberAsEvidence() {
        String xml = DriverCardXmlSamples.validDriverCardXml()
                .replace("<driverIdentification>123456789012</driverIdentification>", "<driverIdentification>12345678901234</driverIdentification>")
                .replace("<cardReplacementIndex>0</cardReplacementIndex>", "<cardReplacementIndex>5</cardReplacementIndex>")
                .replace("<cardRenewalIndex>0</cardRenewalIndex>", "<cardRenewalIndex>7</cardRenewalIndex>");

        TachographFileSession session = service.extract(
                parser.parse(xml),
                new TachographFileSessionMetadata(
                        "default",
                        "legalrequirements-drivercard",
                        "sample",
                        "sample.ddd",
                        "abc",
                        10,
                        "42",
                        "def",
                        true,
                        null
                ),
                Instant.now(),
                Instant.now().plus(4, ChronoUnit.HOURS)
        );

        DriverExtractionSession driver = session.driversByKey().values().iterator().next();
        assertThat(driver.driverKey()).isEqualTo("12:12345678901234");
        assertThat(driver.driverCard().cardNumber()).isEqualTo("12345678901234");
        assertThat(driver.driverCard().fullCardNumber()).isEqualTo("1234567890123457");
        assertThat(driver.driverCard().sourceDriverCardId()).isEqualTo("CARD:12:12345678901234");
    }
}
