package de.votian.services.controller;

import de.votian.services.dto.UserSessionDto;
import de.votian.services.entity.Job;
import de.votian.services.security.AccessControlService;
import de.votian.services.service.JobAcceptanceProtocolService;
import de.votian.services.service.JobBatchService;
import de.votian.services.service.JobListExportService;
import de.votian.services.service.JobPricingService;
import de.votian.services.service.JobService;
import de.votian.services.service.JobTourServiceReadService;
import de.votian.services.service.ViewDataService;
import de.votian.services.repository.AddressRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class JobControllerTest {

    private JobService jobService;
    private AccessControlService accessControlService;
    private JobController controller;
    private Authentication authentication;
    private UserSessionDto user;

    @BeforeEach
    void setUp() {
        jobService = mock(JobService.class);
        accessControlService = mock(AccessControlService.class);
        controller = new JobController(
                jobService,
                mock(JobBatchService.class),
                mock(JobAcceptanceProtocolService.class),
                mock(JobPricingService.class),
                mock(JobListExportService.class),
                mock(JobTourServiceReadService.class),
                mock(ViewDataService.class),
                mock(AddressRepository.class),
                accessControlService
        );
        authentication = mock(Authentication.class);
        user = new UserSessionDto();
        user.setUserType(1);
        user.setHeadquartersId(1L);

        when(accessControlService.sessionUser(authentication)).thenReturn(user);
        when(accessControlService.canManageJobs(user)).thenReturn(true);
        when(accessControlService.isCourierUser(user)).thenReturn(false);
        when(accessControlService.isCustomerUser(user)).thenReturn(false);
        when(accessControlService.isHeadquartersUser(user)).thenReturn(true);
    }

    @Test
    void createStripsManualLonghaulWithoutLonghaulPermission() {
        Job job = new Job();
        job.setHeadquartersId(1L);
        job.setLonghaul(3);

        JobController.JobCreateRequest request = new JobController.JobCreateRequest();
        request.job = job;
        request.tours = List.of();
        request.articles = List.of();
        request.prices = List.of();

        Job created = new Job();
        created.setId(11L);

        when(accessControlService.canAccessHeadquarters(user, 1L)).thenReturn(true);
        when(accessControlService.canManageLonghaul(user)).thenReturn(false);
        when(jobService.createJob(any(Job.class), anyList(), anyList(), anyList())).thenAnswer(invocation -> {
            Job submitted = invocation.getArgument(0);
            created.setLonghaul(submitted.getLonghaul());
            return created;
        });

        ResponseEntity<Job> response = controller.create(request, authentication);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(response.getBody()).isNotNull();
        assertThat(Objects.requireNonNull(response.getBody()).getLonghaul()).isNull();
        verify(jobService).createJob(any(Job.class), anyList(), anyList(), anyList());
    }

    @Test
    void updateDetailsAllowsManualLonghaulForLonghaulManagers() {
        Job existing = new Job();
        existing.setId(5L);
        existing.setHeadquartersId(1L);

        Job updates = new Job();
        updates.setLonghaul(3);

        JobController.JobCreateRequest request = new JobController.JobCreateRequest();
        request.job = updates;
        request.tours = List.of();
        request.articles = List.of();

        when(jobService.findById(5L)).thenReturn(Optional.of(existing));
        when(jobService.getTours(5L)).thenReturn(List.of());
        when(accessControlService.canAccessJob(user, existing)).thenReturn(true);
        when(accessControlService.canManageLonghaul(user)).thenReturn(true);
        when(jobService.updateJob(eq(5L), any(Job.class))).thenAnswer(invocation -> invocation.getArgument(1));

        ResponseEntity<Job> response = controller.updateDetails(5L, request, authentication);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(response.getBody()).isNotNull();
        assertThat(Objects.requireNonNull(response.getBody()).getLonghaul()).isEqualTo(3);
        verify(jobService).replaceTourArticles(5L, List.of());
    }

    @Test
    void updateRejectsSystemOwnedLonghaulStatesFromManualEdits() {
        Job existing = new Job();
        existing.setId(7L);
        existing.setHeadquartersId(1L);

        Job updates = new Job();
        updates.setLonghaul(1);

        when(jobService.findById(7L)).thenReturn(Optional.of(existing));
        when(accessControlService.canAccessJob(user, existing)).thenReturn(true);
        when(accessControlService.canManageLonghaul(user)).thenReturn(true);
        when(jobService.updateJob(eq(7L), any(Job.class))).thenAnswer(invocation -> invocation.getArgument(1));

        ResponseEntity<Job> response = controller.update(7L, updates, authentication);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(response.getBody()).isNotNull();
        assertThat(Objects.requireNonNull(response.getBody()).getLonghaul()).isNull();
    }
}
