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.io.StringReader;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import javax.xml.parsers.DocumentBuilderFactory;
import org.junit.jupiter.api.Test;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

class VehicleUnitXmlExtractionServiceTest {

    private final VehicleUnitXmlExtractionService service = new VehicleUnitXmlExtractionService(
            new DriverKeyFactory(),
            new VehicleKeyFactory()
    );

    @Test
    void extractsVehicleUnitDriverSessionsFromCardInsertionWithdrawalData() throws Exception {
        TachographFileSession session = service.extract(
                new TachographXmlParser.ParsedTachographXml(document(VehicleUnitXmlSamples.vehicleUnitXml()), "VehicleUnit"),
                new TachographFileSessionMetadata(
                        "default",
                        "legalrequirements-vehicleunit",
                        "sample-vu",
                        "sample-vu.ddd",
                        "abc",
                        10,
                        "42",
                        "def",
                        false,
                        null
                ),
                Instant.now(),
                Instant.now().plus(4, ChronoUnit.HOURS)
        );

        assertThat(session.driversByKey()).hasSize(2);
        DriverExtractionSession firstDriver = session.driversByKey().get("12:12345678901200");
        DriverExtractionSession secondDriver = session.driversByKey().get("12:99999999999911");
        assertThat(firstDriver).isNotNull();
        assertThat(secondDriver).isNotNull();

        assertThat(firstDriver.driver().surname()).isEqualTo("Muster");
        assertThat(firstDriver.vehicleRegistrations()).extracting("registrationKey").containsExactly("12:W-1000V");
        assertThat(firstDriver.vehicles()).extracting("vehicleKey").containsExactly("VINVU123456789012");
        assertThat(firstDriver.cardVehicleUsageIntervals()).hasSize(1);
        assertThat(firstDriver.cardVehicleUsageIntervals().get(0).from().toString()).isEqualTo("2026-04-01T08:00Z");
        assertThat(firstDriver.cardVehicleUsageIntervals().get(0).to().toString()).isEqualTo("2026-04-01T11:00Z");
        assertThat(firstDriver.cardActivityIntervals()).hasSize(2);
        assertThat(firstDriver.cardActivityIntervals().get(0).activityType()).isEqualTo("WORK");
        assertThat(firstDriver.cardActivityIntervals().get(1).activityType()).isEqualTo("DRIVE");
        assertThat(firstDriver.supportEvents()).hasSize(1);
        assertThat(firstDriver.supportEvents().get(0).eventDomain()).isEqualTo("PLACE");
        assertThat(firstDriver.supportEvents().get(0).eventType()).isEqualTo("BEGIN_DAILY_WORK_PERIOD");
        assertThat(firstDriver.supportEvents().get(0).country()).isEqualTo("12");
        assertThat(firstDriver.supportEvents().get(0).latitude()).isNotNull();

        assertThat(secondDriver.cardVehicleUsageIntervals()).hasSize(1);
        assertThat(secondDriver.cardVehicleUsageIntervals().get(0).to()).isNull();
        assertThat(secondDriver.cardActivityIntervals()).hasSize(1);
        assertThat(secondDriver.cardActivityIntervals().get(0).from().toString()).isEqualTo("2026-04-02T07:30Z");
        assertThat(secondDriver.supportEvents()).hasSize(2);
        assertThat(secondDriver.supportEvents()).extracting("eventDomain").containsExactly("POSITION", "SPECIFIC_CONDITION");
        assertThat(secondDriver.supportEvents().get(0).latitude()).isNotNull();
        assertThat(secondDriver.supportEvents().get(1).code()).isEqualTo("1");

        assertThat(session.warnings()).isEmpty();
    }

    @Test
    void extractsActivitiesWhenVuTimeOfChangeHasNoOffset() throws Exception {
        TachographFileSession session = service.extract(
                new TachographXmlParser.ParsedTachographXml(document(VehicleUnitXmlSamples.vehicleUnitXmlWithLocalActivityTimes()), "VehicleUnit"),
                new TachographFileSessionMetadata(
                        "default",
                        "legalrequirements-vehicleunit",
                        "sample-vu",
                        "sample-vu.ddd",
                        "abc",
                        10,
                        "42",
                        "def",
                        false,
                        null
                ),
                Instant.now(),
                Instant.now().plus(4, ChronoUnit.HOURS)
        );

        DriverExtractionSession firstDriver = session.driversByKey().get("12:12345678901200");
        DriverExtractionSession secondDriver = session.driversByKey().get("12:99999999999911");
        assertThat(firstDriver.cardActivityIntervals().get(0).from().toString()).isEqualTo("2026-04-01T08:00Z");
        assertThat(secondDriver.cardActivityIntervals().get(0).from().toString()).isEqualTo("2026-04-02T07:30Z");
    }

    @Test
    void keepsOpenVuCardUsageRecordWithoutClosingItAtDownloadPeriodEnd() throws Exception {
        TachographFileSession session = service.extract(
                new TachographXmlParser.ParsedTachographXml(document(VehicleUnitXmlSamples.vehicleUnitXml()), "VehicleUnit"),
                new TachographFileSessionMetadata(
                        "default",
                        "legalrequirements-vehicleunit",
                        "sample-vu",
                        "sample-vu.ddd",
                        "abc",
                        10,
                        "42",
                        "def",
                        false,
                        null
                ),
                Instant.now(),
                Instant.now().plus(4, ChronoUnit.HOURS)
        );

        DriverExtractionSession secondDriver = session.driversByKey().get("12:99999999999911");
        assertThat(secondDriver.cardVehicleUsageIntervals()).hasSize(1);
        assertThat(secondDriver.cardVehicleUsageIntervals().get(0).from().toString()).isEqualTo("2026-04-02T07:30Z");
        assertThat(secondDriver.cardVehicleUsageIntervals().get(0).to()).isNull();
    }

    private Document document(String xml) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(false);
        return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
    }
}
