package at.procon.eventhub.tachographfilesession.api;

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import at.procon.eventhub.tachographfilesession.dto.CreateTachographFileSessionResponse;
import at.procon.eventhub.tachographfilesession.dto.TachographEsperEventsProcessingRequest;
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverDetailDto;
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingRequest;
import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverSummaryDto;
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionDeleteResponse;
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionListDriversResponse;
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionSummaryDto;
import at.procon.eventhub.tachographfilesession.model.ExtractionStats;
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleTripIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperSupportGeoEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionProcessingService;
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionService;
import java.time.OffsetDateTime;
import java.time.Instant;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;

class TachographFileSessionControllerTest {

    @Test
    void uploadsSessionListsDriversAndDeletes() throws Exception {
        TachographFileSessionService service = org.mockito.Mockito.mock(TachographFileSessionService.class);
        TachographFileSessionProcessingService processingService = org.mockito.Mockito.mock(TachographFileSessionProcessingService.class);
        MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new TachographFileSessionController(service, processingService))
                .setControllerAdvice(new TachographFileSessionExceptionHandler())
                .build();
        UUID sessionId = UUID.randomUUID();
        TachographFileDriverSummaryDto driver = new TachographFileDriverSummaryDto("12:123", "Muster", "Max", "12", "123", 3, 2);
        TachographFileSessionSummaryDto summary = new TachographFileSessionSummaryDto(
                sessionId,
                "default",
                "legalrequirements-drivercard",
                "sample",
                "sample.ddd",
                true,
                "42",
                new ExtractionStats(1, 3, 2, 2, 2, 0),
                List.of(driver),
                List.of(),
                Instant.parse("2026-05-12T10:00:00Z"),
                Instant.parse("2026-05-12T14:00:00Z")
        );
        when(service.createSession(org.mockito.ArgumentMatchers.any(), eq("default"), eq("src"), eq("sample")))
                .thenReturn(new CreateTachographFileSessionResponse(summary));
        when(service.getSession(sessionId)).thenReturn(summary);
        when(service.listDrivers(sessionId)).thenReturn(new TachographFileSessionListDriversResponse(sessionId, List.of(driver)));
        when(service.getDriver(sessionId, "12:123")).thenReturn(new TachographFileDriverDetailDto(sessionId, "12:123", null, null, List.of(), List.of(), List.of(), List.of(), List.of(), List.of()));
        when(processingService.getEsperDriverProcessingResults(
                eq(sessionId),
                eq("12:123"),
                org.mockito.ArgumentMatchers.any(TachographEsperEventsProcessingRequest.class)
        ))
                .thenReturn(new TachographEsperDriverProcessingResultDto(
                        sessionId,
                        "12:123",
                        "DRIVER_CARD",
                        OffsetDateTime.parse("2026-05-12T08:00:00Z"),
                        OffsetDateTime.parse("2026-05-12T12:00:00Z"),
                        OffsetDateTime.parse("2026-05-12T08:30:00Z"),
                        OffsetDateTime.parse("2026-05-12T11:30:00Z"),
                        2,
                        1,
                        1,
                        1,
                        1,
                        1,
                        0,
                        1,
                        0,
                        0,
                        2,
                        1,
                        1,
                        List.of(new TachographEsperActivityIntervalEvent(
                                sessionId,
                                "12:123",
                                "ACT-1",
                                "WORK",
                                "DRIVER",
                                "INSERTED",
                                "SINGLE",
                                "12:REG-1",
                                "VIN-1",
                                "DRIVER_CARD",
                                OffsetDateTime.parse("2026-05-12T08:00:00Z"),
                                OffsetDateTime.parse("2026-05-12T09:00:00Z"),
                                3600L,
                                List.of("ACT-1"),
                                false,
                                false,
                                "RAW_INTERVAL"
                        )),
                        List.of(new TachographEsperActivityIntervalEvent(
                                sessionId,
                                "12:123",
                                "ACT-2",
                                "DRIVE",
                                "DRIVER",
                                "INSERTED",
                                "SINGLE",
                                "12:REG-1",
                                "VIN-1",
                                "DRIVER_CARD",
                                OffsetDateTime.parse("2026-05-12T09:00:00Z"),
                                OffsetDateTime.parse("2026-05-12T10:00:00Z"),
                                3600L,
                                List.of("ACT-2"),
                                false,
                                false,
                                "RAW_INTERVAL"
                        )),
                        List.of(new TachographEsperDrivingInterruptionIntervalEvent(
                                sessionId,
                                "12:123",
                                OffsetDateTime.parse("2026-05-12T10:00:00Z"),
                                OffsetDateTime.parse("2026-05-12T10:30:00Z"),
                                1800L,
                                "ACT-2",
                                "ACT-3",
                                "12:REG-1",
                                "12:REG-2",
                                "VIN-1",
                                "VIN-2"
                        )),
                        List.of(new TachographEsperDrivingInterruptionIntervalEvent(
                                sessionId,
                                "12:123",
                                OffsetDateTime.parse("2026-05-12T10:00:00Z"),
                                OffsetDateTime.parse("2026-05-12T10:30:00Z"),
                                1800L,
                                "ACT-2",
                                "ACT-3",
                                "12:REG-1",
                                "12:REG-2",
                                "VIN-1",
                                "VIN-2"
                        )),
                        List.of(new TachographEsperDrivingInterruptionIntervalEvent(
                                sessionId,
                                "12:123",
                                OffsetDateTime.parse("2026-05-12T10:00:00Z"),
                                OffsetDateTime.parse("2026-05-12T22:00:00Z"),
                                43_200L,
                                "ACT-2",
                                "ACT-3",
                                "12:REG-1",
                                "12:REG-2",
                                "VIN-1",
                                "VIN-2"
                        )),
                        List.of(new TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent(
                                sessionId,
                                "12:123",
                                OffsetDateTime.parse("2026-05-12T10:00:00Z"),
                                OffsetDateTime.parse("2026-05-12T22:00:00Z"),
                                43_200L,
                                43_200L,
                                100.0d,
                                "ACT-2",
                                "ACT-3",
                                "12:REG-1",
                                "12:REG-2",
                                "VIN-1",
                                "VIN-2",
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                "UNKNOWN",
                                null,
                                null
                        )),
                        List.of(),
                        List.of(new TachographEsperPotentialHomeOvernightStayIntervalEvent(
                                sessionId,
                                "12:123",
                                OffsetDateTime.parse("2026-05-12T10:00:00Z"),
                                OffsetDateTime.parse("2026-05-12T22:00:00Z"),
                                43_200L,
                                43_200L,
                                100.0d,
                                "ACT-2",
                                "ACT-3",
                                "12:REG-1",
                                "12:REG-2",
                                "VIN-1",
                                "VIN-2",
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                null,
                                "UNKNOWN",
                                null,
                                null
                        )),
                        List.of(),
                        List.<TachographEsperPotentialInVehicleTripIntervalEvent>of(),
                        List.of(new TachographEsperVehicleUsageIntervalEvent(
                                sessionId,
                                "12:123",
                                "CVU-1",
                                OffsetDateTime.parse("2026-05-12T08:00:00Z"),
                                OffsetDateTime.parse("2026-05-12T10:00:00Z"),
                                7200L,
                                100L,
                                200L,
                                "12:REG-1",
                                "VIN-1",
                                "DRIVER_CARD",
                                List.of("CVU-1")
                        )),
                        List.of(new TachographEsperVuCardAbsentIntervalEvent(
                                sessionId,
                                "12:123",
                                OffsetDateTime.parse("2026-05-12T10:00:01Z"),
                                OffsetDateTime.parse("2026-05-12T11:00:00Z"),
                                3599L,
                                "CVU-1",
                                "CVU-2",
                                "12:REG-1",
                                "12:REG-2",
                                "VIN-1",
                                "VIN-2"
                        )),
                        List.of(new TachographEsperSupportGeoEvent(
                                "SUP-1",
                                "12:123",
                                OffsetDateTime.parse("2026-05-12T10:15:00Z"),
                                "POSITION",
                                "POSITION_RECORDED",
                                "SNAPSHOT",
                                "12:REG-1",
                                "VIN-1",
                                null,
                                null,
                                null,
                                null,
                                null,
                                java.math.BigDecimal.valueOf(48.2082),
                                java.math.BigDecimal.valueOf(16.3738),
                                123L,
                                "path"
                        )),
                        List.of("note")
                ));
        when(processingService.evaluateOperatingPeriods(eq(sessionId), eq("12:123"), org.mockito.ArgumentMatchers.any(TachographOperatingPeriodsProcessingRequest.class)))
                .thenReturn(new TachographOperatingPeriodsProcessingResultDto(
                        sessionId,
                        "12:123",
                        Instant.parse("2026-05-12T08:00:00Z").atOffset(java.time.ZoneOffset.UTC),
                        Instant.parse("2026-05-12T12:00:00Z").atOffset(java.time.ZoneOffset.UTC),
                        Instant.parse("2026-05-12T08:00:00Z").atOffset(java.time.ZoneOffset.UTC),
                        Instant.parse("2026-05-12T12:00:00Z").atOffset(java.time.ZoneOffset.UTC),
                        3,
                        2,
                        2,
                        2,
                        1,
                        7,
                        3,
                        0,
                        0,
                        null,
                        List.of(),
                        List.of(),
                        List.of(),
                        List.of(),
                        List.of()
                ));
        when(service.deleteSession(sessionId)).thenReturn(new TachographFileSessionDeleteResponse(sessionId, true));

        mockMvc.perform(multipart("/api/eventhub/tachograph-file-sessions")
                        .file(new MockMultipartFile("file", "sample.ddd", "application/octet-stream", "abc".getBytes()))
                        .param("tenantKey", "default")
                        .param("sourceInstanceKey", "src")
                        .param("sessionLabel", "sample"))
                .andExpect(status().isCreated())
                .andExpect(jsonPath("$.session.sessionId").value(sessionId.toString()));

        mockMvc.perform(get("/api/eventhub/tachograph-file-sessions/{sessionId}", sessionId))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.sessionId").value(sessionId.toString()));

        mockMvc.perform(get("/api/eventhub/tachograph-file-sessions/{sessionId}/drivers", sessionId))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.drivers[0].driverKey").value("12:123"));

        mockMvc.perform(get("/api/eventhub/tachograph-file-sessions/{sessionId}/drivers/{driverKey}", sessionId, "12:123"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.driverKey").value("12:123"));

        mockMvc.perform(post("/api/eventhub/tachograph-file-sessions/{sessionId}/drivers/{driverKey}/processing/esper-events", sessionId, "12:123")
                        .contentType("application/json")
                        .content("""
                                {
                                  "occurredFrom": "2026-05-12T08:30:00Z",
                                  "occurredTo": "2026-05-12T11:30:00Z",
                                  "significantDrivingMinutes": 3,
                                  "minimumRestPeriodMinutes": 720
                                }
                                """))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.driverKey").value("12:123"))
                .andExpect(jsonPath("$.sourceKind").value("DRIVER_CARD"))
                .andExpect(jsonPath("$.requestedFrom").value("2026-05-12T08:30:00Z"))
                .andExpect(jsonPath("$.requestedTo").value("2026-05-12T11:30:00Z"))
                .andExpect(jsonPath("$.activityIntervalCount").value(2))
                .andExpect(jsonPath("$.drivingInterruptionIntervalCount").value(1))
                .andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervalCount").value(1))
                .andExpect(jsonPath("$.dailyWeeklyRestCandidateIntervalCount").value(1))
                .andExpect(jsonPath("$.dailyWeeklyRestCandidateCoverageIntervalCount").value(1))
                .andExpect(jsonPath("$.unclassifiedDailyWeeklyRestCandidateCoverageIntervalCount").value(0))
                .andExpect(jsonPath("$.potentialHomeOvernightStayIntervalCount").value(1))
                .andExpect(jsonPath("$.potentialInVehicleOvernightStayIntervalCount").value(0))
                .andExpect(jsonPath("$.potentialInVehicleTripIntervalCount").value(0))
                .andExpect(jsonPath("$.vuCardAbsentIntervalCount").value(1))
                .andExpect(jsonPath("$.supportGeoEventCount").value(1))
                .andExpect(jsonPath("$.supportGeoEvents[0].eventId").value("SUP-1"))
                .andExpect(jsonPath("$.drivingInterruptionIntervals[0].previousRegistrationKey").value("12:REG-1"))
                .andExpect(jsonPath("$.drivingInterruptionIntervals[0].nextRegistrationKey").value("12:REG-2"))
                .andExpect(jsonPath("$.drivingInterruptionIntervals[0].previousVehicleKey").value("VIN-1"))
                .andExpect(jsonPath("$.drivingInterruptionIntervals[0].nextVehicleKey").value("VIN-2"))
                .andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervals[0].previousRegistrationKey").value("12:REG-1"))
                .andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervals[0].nextRegistrationKey").value("12:REG-2"))
                .andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervals[0].previousVehicleKey").value("VIN-1"))
                .andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervals[0].nextVehicleKey").value("VIN-2"))
                .andExpect(jsonPath("$.drivingIntervals[0].activityType").value("DRIVE"));

        mockMvc.perform(post("/api/eventhub/tachograph-file-sessions/{sessionId}/drivers/{driverKey}/processing/operating-periods", sessionId, "12:123")
                        .contentType("application/json")
                        .content("""
                                {
                                  "significantDrivingMinutes": 5
                                }
                                """))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.driverKey").value("12:123"))
                .andExpect(jsonPath("$.operatingPeriodCount").value(1));

        mockMvc.perform(delete("/api/eventhub/tachograph-file-sessions/{sessionId}", sessionId))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.deleted").value(true));
    }
}
