package at.procon.dip.ingestion.controller;

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

import at.procon.dip.domain.access.DocumentAccessContext;
import at.procon.dip.domain.access.DocumentVisibility;
import at.procon.dip.domain.document.DocumentAttributeValueType;
import at.procon.dip.domain.document.DocumentFamily;
import at.procon.dip.domain.document.DocumentStatus;
import at.procon.dip.domain.document.DocumentType;
import at.procon.dip.domain.document.service.DocumentAttributeService;
import at.procon.dip.ingestion.config.DipIngestionProperties;
import at.procon.dip.ingestion.dto.GenericIngestionHintsRequest;
import at.procon.dip.ingestion.dto.GenericNameValuePairRequest;
import at.procon.dip.ingestion.dto.GenericTextImportRequest;
import at.procon.dip.ingestion.service.DocumentIngestionGateway;
import at.procon.dip.ingestion.spi.IngestionResult;
import at.procon.dip.ingestion.spi.SourceDescriptor;
import at.procon.dip.domain.document.CanonicalDocumentMetadata;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class GenericDocumentImportControllerTest {

    @Mock
    private DocumentIngestionGateway ingestionGateway;
    @Mock
    private DocumentAttributeService documentAttributeService;

    private GenericDocumentImportController controller;

    @BeforeEach
    void setUp() {
        DipIngestionProperties properties = new DipIngestionProperties();
        properties.setEnabled(true);
        properties.setRestUploadEnabled(true);
        controller = new GenericDocumentImportController(properties, ingestionGateway, documentAttributeService);
    }

    @Test
    void shouldPersistAttributesButUseOnlyTopLevelFieldsAndIngestionHintsForDescriptorAttributes() {
        UUID documentId = UUID.randomUUID();
        OffsetDateTime syncedAt = OffsetDateTime.parse("2026-04-21T11:05:00+02:00");
        List<GenericNameValuePairRequest> pairs = List.of(
                new GenericNameValuePairRequest("title", null, DocumentAttributeValueType.STRING, null, "Text title from pair", null, null, null, null, null),
                new GenericNameValuePairRequest("languageCode", null, DocumentAttributeValueType.STRING, null, "de", null, null, null, null, null),
                new GenericNameValuePairRequest("country", null, DocumentAttributeValueType.STRING, null, "AT", null, null, null, null, null),
                new GenericNameValuePairRequest("estimatedValue", null, DocumentAttributeValueType.NUMBER, null, null, null, new BigDecimal("125000.50"), null, null, null),
                new GenericNameValuePairRequest("publishedDate", null, DocumentAttributeValueType.DATE, null, null, null, null, LocalDate.of(2026, 4, 21), null, null),
                new GenericNameValuePairRequest("version", null, DocumentAttributeValueType.INTEGER, null, null, 7L, null, null, null, null),
                new GenericNameValuePairRequest("lastSyncedAt", null, DocumentAttributeValueType.DATETIME, null, null, null, null, null, syncedAt, null),
                new GenericNameValuePairRequest("status", "ted", DocumentAttributeValueType.STRING, null, "closed", null, null, null, null, null)
        );
        GenericTextImportRequest request = new GenericTextImportRequest(
                "Hello world",
                "sample.txt",
                "text/plain",
                null,
                null,
                "fr",
                "Top level title",
                "source-1",
                pairs,
                new GenericIngestionHintsRequest("TEXT", "policy-key", "policy-hint", "batch-1", true, false)
        );

        when(ingestionGateway.ingest(any(SourceDescriptor.class))).thenReturn(new IngestionResult(
                List.of(new CanonicalDocumentMetadata(
                        documentId,
                        new DocumentAccessContext(null, DocumentVisibility.PUBLIC),
                        DocumentType.TEXT,
                        DocumentFamily.GENERIC,
                        DocumentStatus.REPRESENTED,
                        "Top level title",
                        "fr",
                        "text/plain",
                        null,
                        OffsetDateTime.now(),
                        OffsetDateTime.now()
                )),
                List.of()
        ));

        var response = controller.importText(request);

        ArgumentCaptor<SourceDescriptor> descriptorCaptor = ArgumentCaptor.forClass(SourceDescriptor.class);
        verify(ingestionGateway).ingest(descriptorCaptor.capture());
        SourceDescriptor descriptor = descriptorCaptor.getValue();
        assertThat(descriptor.textContent()).isEqualTo("Hello world");
        assertThat(descriptor.attributes()).containsEntry("title", "Top level title");
        assertThat(descriptor.attributes()).containsEntry("languageCode", "fr");
        assertThat(descriptor.attributes()).containsEntry("documentTypeHint", "TEXT");
        assertThat(descriptor.attributes()).containsEntry("embeddingPolicyKey", "policy-key");
        assertThat(descriptor.attributes()).containsEntry("embeddingPolicyHint", "policy-hint");
        assertThat(descriptor.attributes()).containsEntry("importBatchId", "batch-1");
        assertThat(descriptor.attributes()).containsEntry("wrapperDocument", "true");
        assertThat(descriptor.attributes()).containsEntry("containerDocument", "false");
        assertThat(descriptor.attributes()).doesNotContainKeys(
                "country", "estimatedValue", "publishedDate", "version", "lastSyncedAt", "status"
        );

        verify(documentAttributeService).addAttributes(documentId, pairs);
        assertThat(response.getBody()).isNotNull();
        assertThat(response.getBody().documentId()).isEqualTo(documentId);
    }
}
