package at.procon.dip.testsupport;

import at.procon.dip.domain.access.DocumentVisibility;
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.RepresentationType;
import at.procon.dip.domain.document.entity.Document;
import at.procon.dip.domain.document.entity.DocumentTextRepresentation;
import at.procon.dip.search.service.DocumentLexicalIndexService;
import at.procon.dip.domain.document.service.DocumentRepresentationService;
import at.procon.dip.domain.document.service.DocumentService;
import at.procon.dip.domain.document.service.command.AddDocumentTextRepresentationCommand;
import at.procon.dip.domain.document.service.command.CreateDocumentCommand;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@RequiredArgsConstructor
@Transactional
public class SearchTestDataFactory {

    private final DocumentService documentService;
    private final DocumentRepresentationService representationService;
    private final DocumentLexicalIndexService lexicalIndexService;

    public CreatedDocument createDocumentWithPrimaryRepresentation(
            String title,
            String summary,
            String body,
            DocumentType documentType,
            DocumentFamily documentFamily,
            String languageCode,
            RepresentationType primaryType) {

        Document document = documentService.create(new CreateDocumentCommand(
                null,
                DocumentVisibility.PUBLIC,
                documentType,
                documentFamily,
                DocumentStatus.RECEIVED,
                title,
                summary,
                languageCode,
                "text/plain",
                null,
                Integer.toHexString((title + body).hashCode())
        ));

        DocumentTextRepresentation primary = addRepresentation(document, primaryType, languageCode, true, null, null, null, body);
        return new CreatedDocument(document, primary, List.of(primary));
    }

    public CreatedDocument createDocumentWithPrimaryAndChunks(
            String title,
            String summary,
            String primaryBody,
            String languageCode,
            List<String> chunkBodies) {

        Document document = documentService.create(new CreateDocumentCommand(
                null,
                DocumentVisibility.PUBLIC,
                DocumentType.TEXT,
                DocumentFamily.GENERIC,
                DocumentStatus.RECEIVED,
                title,
                summary,
                languageCode,
                "text/plain",
                null,
                Integer.toHexString((title + primaryBody + chunkBodies).hashCode())
        ));

        List<DocumentTextRepresentation> all = new ArrayList<>();
        DocumentTextRepresentation primary = addRepresentation(document, RepresentationType.SEMANTIC_TEXT, languageCode, true, null, null, null, primaryBody);
        all.add(primary);

        int offset = 0;
        for (int i = 0; i < chunkBodies.size(); i++) {
            String chunk = chunkBodies.get(i);
            DocumentTextRepresentation saved = addRepresentation(
                    document,
                    RepresentationType.CHUNK,
                    languageCode,
                    false,
                    i,
                    offset,
                    offset + chunk.length(),
                    chunk);
            all.add(saved);
            offset += chunk.length();
        }

        return new CreatedDocument(document, primary, all);
    }

    private DocumentTextRepresentation addRepresentation(
            Document document,
            RepresentationType type,
            String languageCode,
            boolean primary,
            Integer chunkIndex,
            Integer chunkStartOffset,
            Integer chunkEndOffset,
            String text) {
        DocumentTextRepresentation representation = representationService.addRepresentation(new AddDocumentTextRepresentationCommand(
                document.getId(),
                null,
                type,
                "search-test-factory",
                languageCode,
                null,
                chunkIndex,
                chunkStartOffset,
                chunkEndOffset,
                primary,
                text,
                false
        ));
        lexicalIndexService.refreshRepresentationLexicalIndex(representation.getId());
        return representation;
    }

    public record CreatedDocument(
            Document document,
            DocumentTextRepresentation primaryRepresentation,
            List<DocumentTextRepresentation> representations
    ) {
    }
}
