package at.procon.eventhub.tachographfilesession.service;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;

import at.procon.eventhub.config.EventHubProperties;
import at.procon.eventhub.tachographfilesession.dto.CreateTachographFileSessionResponse;
import at.procon.eventhub.tachographfilesession.model.ExtractionStats;
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
import at.procon.eventhub.tachographfilesession.model.TachographFileSessionMetadata;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.Map;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.mock.web.MockMultipartFile;

class TachographFileSessionServiceTest {

    @Test
    void createsAndLoadsSession() {
        EventHubProperties properties = new EventHubProperties();
        TachographFileSessionRepository repository = new InMemoryTachographFileSessionRepository(properties);
        LegalRequirementsClient client = Mockito.mock(LegalRequirementsClient.class);
        TachographXmlParser parser = Mockito.mock(TachographXmlParser.class);
        DriverCardXmlExtractionService driverCardExtractor = Mockito.mock(DriverCardXmlExtractionService.class);
        VehicleUnitXmlExtractionService vehicleUnitExtractor = Mockito.mock(VehicleUnitXmlExtractionService.class);
        TachographFileSessionService service = new TachographFileSessionService(
                properties,
                repository,
                client,
                parser,
                driverCardExtractor,
                vehicleUnitExtractor
        );

        MockMultipartFile file = new MockMultipartFile("file", "sample.ddd", "application/octet-stream", "abc".getBytes(StandardCharsets.UTF_8));
        when(client.uploadTachographFile(any(), eq("sample.ddd"))).thenReturn(new LegalRequirementsUploadResult("42", "<DriverCard/>"));
        TachographXmlParser.ParsedTachographXml parsed = Mockito.mock(TachographXmlParser.ParsedTachographXml.class);
        when(parsed.rootElementName()).thenReturn("DriverCard");
        when(parser.parse("<DriverCard/>")).thenReturn(parsed);
        TachographFileSession extracted = new TachographFileSession(
                UUID.randomUUID(),
                new TachographFileSessionMetadata("default", "legalrequirements-drivercard", "sample", "sample.ddd", "a", 3, "42", "b", true, null),
                Map.of(),
                new ExtractionStats(0, 0, 0, 0, 0, 0),
                java.util.List.of(),
                Instant.now(),
                Instant.now().plusSeconds(10)
        );
        when(driverCardExtractor.extract(eq(parsed), any(), any(), any())).thenReturn(extracted);

        CreateTachographFileSessionResponse response = service.createSession(file, null, null, "sample");

        assertThat(response.session().sessionId()).isEqualTo(extracted.sessionId());
        assertThat(service.getSession(extracted.sessionId()).sessionId()).isEqualTo(extracted.sessionId());
    }

    @Test
    void rejectsOversizedFileBeforeUpload() {
        EventHubProperties properties = new EventHubProperties();
        properties.getTachographFileSession().setMaxFileSizeBytes(1024);
        TachographFileSessionRepository repository = new InMemoryTachographFileSessionRepository(properties);
        LegalRequirementsClient client = Mockito.mock(LegalRequirementsClient.class);
        TachographXmlParser parser = Mockito.mock(TachographXmlParser.class);
        DriverCardXmlExtractionService driverCardExtractor = Mockito.mock(DriverCardXmlExtractionService.class);
        VehicleUnitXmlExtractionService vehicleUnitExtractor = Mockito.mock(VehicleUnitXmlExtractionService.class);
        TachographFileSessionService service = new TachographFileSessionService(
                properties,
                repository,
                client,
                parser,
                driverCardExtractor,
                vehicleUnitExtractor
        );

        MockMultipartFile file = new MockMultipartFile("file", "sample.ddd", "application/octet-stream", new byte[1025]);

        assertThatThrownBy(() -> service.createSession(file, null, null, "sample"))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("size limit");

        verifyNoInteractions(client, parser, driverCardExtractor, vehicleUnitExtractor);
    }

    @Test
    void usesVehicleUnitDefaultsAndExtractorForVehicleUnitXml() {
        EventHubProperties properties = new EventHubProperties();
        TachographFileSessionRepository repository = new InMemoryTachographFileSessionRepository(properties);
        LegalRequirementsClient client = Mockito.mock(LegalRequirementsClient.class);
        TachographXmlParser parser = Mockito.mock(TachographXmlParser.class);
        DriverCardXmlExtractionService driverCardExtractor = Mockito.mock(DriverCardXmlExtractionService.class);
        VehicleUnitXmlExtractionService vehicleUnitExtractor = Mockito.mock(VehicleUnitXmlExtractionService.class);
        TachographFileSessionService service = new TachographFileSessionService(
                properties,
                repository,
                client,
                parser,
                driverCardExtractor,
                vehicleUnitExtractor
        );

        MockMultipartFile file = new MockMultipartFile("file", "vu.ddd", "application/octet-stream", "vu".getBytes(StandardCharsets.UTF_8));
        when(client.uploadTachographFile(any(), eq("vu.ddd"))).thenReturn(new LegalRequirementsUploadResult("77", "<VehicleUnit/>"));
        TachographXmlParser.ParsedTachographXml parsed = Mockito.mock(TachographXmlParser.ParsedTachographXml.class);
        when(parsed.rootElementName()).thenReturn("VehicleUnit");
        when(parser.parse("<VehicleUnit/>")).thenReturn(parsed);
        TachographFileSession extracted = new TachographFileSession(
                UUID.randomUUID(),
                new TachographFileSessionMetadata("default", "legalrequirements-vehicleunit", "vu", "vu.ddd", "a", 2, "77", "b", false, null),
                Map.of(),
                new ExtractionStats(0, 0, 0, 0, 0, 0),
                java.util.List.of(),
                Instant.now(),
                Instant.now().plusSeconds(10)
        );
        when(vehicleUnitExtractor.extract(eq(parsed), any(), any(), any())).thenReturn(extracted);

        CreateTachographFileSessionResponse response = service.createSession(file, null, null, "vu");

        assertThat(response.session().driverCardFile()).isFalse();
        assertThat(response.session().sourceInstanceKey()).isEqualTo("legalrequirements-vehicleunit");
    }
}
