package org.raddatz.familienarchiv.ocr;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.raddatz.familienarchiv.exception.DomainException;
import org.raddatz.familienarchiv.exception.ErrorCode;
import org.raddatz.familienarchiv.ocr.OcrJobDocumentRepository;
import org.raddatz.familienarchiv.ocr.OcrJobRepository;

import java.util.List;
import java.util.UUID;

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.Mockito.*;

@ExtendWith(MockitoExtension.class)
class OcrBatchServiceTest {

    @Mock OcrHealthClient ocrHealthClient;
    @Mock OcrJobRepository ocrJobRepository;
    @Mock OcrJobDocumentRepository ocrJobDocumentRepository;
    @Mock OcrAsyncRunner ocrAsyncRunner;

    @InjectMocks OcrBatchService ocrBatchService;

    @Test
    void startBatch_throwsServiceUnavailable_whenOcrServiceIsDown() {
        when(ocrHealthClient.isHealthy()).thenReturn(false);

        assertThatThrownBy(() -> ocrBatchService.startBatch(List.of(UUID.randomUUID()), UUID.randomUUID()))
                .isInstanceOf(DomainException.class)
                .satisfies(e -> assertThat(((DomainException) e).getCode())
                        .isEqualTo(ErrorCode.OCR_SERVICE_UNAVAILABLE));
    }

    @Test
    void startBatch_createsJobAndDispatchesAsync() {
        UUID docId = UUID.randomUUID();
        UUID userId = UUID.randomUUID();
        UUID jobId = UUID.randomUUID();

        when(ocrHealthClient.isHealthy()).thenReturn(true);
        when(ocrJobRepository.save(any())).thenAnswer(inv -> {
            OcrJob job = inv.getArgument(0);
            job.setId(jobId);
            return job;
        });
        when(ocrJobDocumentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));

        UUID result = ocrBatchService.startBatch(List.of(docId), userId);

        assertThat(result).isEqualTo(jobId);
        verify(ocrAsyncRunner).runBatch(jobId, userId);
    }

    @Test
    void startBatch_createsJobDocumentForEachId() {
        UUID doc1 = UUID.randomUUID();
        UUID doc2 = UUID.randomUUID();
        UUID userId = UUID.randomUUID();

        when(ocrHealthClient.isHealthy()).thenReturn(true);
        when(ocrJobRepository.save(any())).thenAnswer(inv -> {
            OcrJob job = inv.getArgument(0);
            job.setId(UUID.randomUUID());
            return job;
        });
        when(ocrJobDocumentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));

        ocrBatchService.startBatch(List.of(doc1, doc2), userId);

        verify(ocrJobDocumentRepository, times(2)).save(any());
    }
}
