package org.raddatz.familienarchiv.document.transcription;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.raddatz.familienarchiv.audit.AuditService;
import org.raddatz.familienarchiv.document.annotation.AnnotationService;
import org.raddatz.familienarchiv.document.BlockSource;
import org.raddatz.familienarchiv.document.DocumentService;
import org.raddatz.familienarchiv.document.transcription.TranscriptionBlock;
import org.raddatz.familienarchiv.document.transcription.TranscriptionBlockRepository;
import org.raddatz.familienarchiv.document.transcription.TranscriptionBlockVersionRepository;
import org.raddatz.familienarchiv.ocr.SenderModelService;

import java.util.Optional;
import java.util.UUID;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

class TranscriptionServiceGuidedTest {

    TranscriptionBlockRepository blockRepository;
    TranscriptionBlockVersionRepository versionRepository;
    AnnotationService annotationService;
    DocumentService documentService;
    SenderModelService senderModelService;
    AuditService auditService;
    TranscriptionService service;

    UUID docId = UUID.randomUUID();
    UUID annId = UUID.randomUUID();
    UUID userId = UUID.randomUUID();

    @BeforeEach
    void setUp() {
        blockRepository = mock(TranscriptionBlockRepository.class);
        versionRepository = mock(TranscriptionBlockVersionRepository.class);
        annotationService = mock(AnnotationService.class);
        documentService = mock(DocumentService.class);
        senderModelService = mock(SenderModelService.class);
        auditService = mock(AuditService.class);

        service = new TranscriptionService(blockRepository, versionRepository,
                annotationService, documentService, senderModelService, auditService);

        when(blockRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
        when(versionRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
    }

    @Test
    void upsertGuidedBlock_createsNewBlock_whenAnnotationHasNoBlock() {
        when(blockRepository.findByAnnotationId(annId)).thenReturn(Optional.empty());

        TranscriptionBlock result = service.upsertGuidedBlock(docId, annId, "Hallo", userId);

        assertThat(result.getText()).isEqualTo("Hallo");
        assertThat(result.getSource()).isEqualTo(BlockSource.OCR);
        assertThat(result.getAnnotationId()).isEqualTo(annId);
        verify(blockRepository).save(any());
    }

    @Test
    void upsertGuidedBlock_updatesExistingOcrBlock_whenAnnotationHasOcrBlock() {
        TranscriptionBlock existing = TranscriptionBlock.builder()
                .id(UUID.randomUUID())
                .annotationId(annId)
                .documentId(docId)
                .text("old text")
                .source(BlockSource.OCR)
                .sortOrder(0)
                .build();
        when(blockRepository.findByAnnotationId(annId)).thenReturn(Optional.of(existing));

        TranscriptionBlock result = service.upsertGuidedBlock(docId, annId, "new text", userId);

        assertThat(result.getText()).isEqualTo("new text");
        verify(blockRepository).save(any());
    }

    @Test
    void upsertGuidedBlock_doesNotOverwriteNonEmptyManualBlock() {
        TranscriptionBlock manual = TranscriptionBlock.builder()
                .id(UUID.randomUUID())
                .annotationId(annId)
                .documentId(docId)
                .text("manually written")
                .source(BlockSource.MANUAL)
                .sortOrder(0)
                .build();
        when(blockRepository.findByAnnotationId(annId)).thenReturn(Optional.of(manual));

        TranscriptionBlock result = service.upsertGuidedBlock(docId, annId, "ocr result", userId);

        assertThat(result.getText()).isEqualTo("manually written");
        verify(blockRepository, never()).save(any());
    }

    @Test
    void upsertGuidedBlock_fillsEmptyManualBlock_withOcrText() {
        TranscriptionBlock emptyManual = TranscriptionBlock.builder()
                .id(UUID.randomUUID())
                .annotationId(annId)
                .documentId(docId)
                .text("")
                .source(BlockSource.MANUAL)
                .sortOrder(0)
                .build();
        when(blockRepository.findByAnnotationId(annId)).thenReturn(Optional.of(emptyManual));

        TranscriptionBlock result = service.upsertGuidedBlock(docId, annId, "ocr result", userId);

        assertThat(result.getText()).isEqualTo("ocr result");
        verify(blockRepository).save(any());
    }
}
