package at.procon.dip.processing.impl;

import at.procon.dip.classification.spi.DetectionResult;
import at.procon.dip.domain.document.ContentRole;
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.DocumentService;
import at.procon.dip.domain.ted.service.TedNoticeProjectionService;
import at.procon.dip.extraction.spi.ExtractedStructuredPayload;
import at.procon.dip.extraction.spi.ExtractionResult;
import at.procon.dip.ingestion.spi.SourceDescriptor;
import at.procon.dip.processing.spi.DocumentProcessingPolicy;
import at.procon.dip.processing.spi.StructuredDocumentProcessor;
import at.procon.dip.processing.spi.StructuredProcessingRequest;
import at.procon.dip.runtime.condition.ConditionalOnRuntimeMode;
import at.procon.dip.runtime.config.RuntimeMode;
import at.procon.ted.model.entity.ProcurementDocument;

import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import at.procon.ted.service.XmlParserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

@Component
@ConditionalOnRuntimeMode(RuntimeMode.NEW)
@RequiredArgsConstructor
@Slf4j
public class TedStructuredDocumentProcessor implements StructuredDocumentProcessor {

    private final XmlParserService xmlParserService;
    private final DocumentService documentService;
    private final TedNoticeProjectionService tedNoticeProjectionService;

    @Override
    public boolean supports(SourceDescriptor sourceDescriptor, DetectionResult detectionResult) {
        return detectionResult.documentType() == DocumentType.TED_NOTICE;
    }

    @Override
    public DocumentProcessingPolicy processingPolicy(SourceDescriptor sourceDescriptor, DetectionResult detectionResult) {
        return DocumentProcessingPolicy.replaceGenericTextProcessing();
    }

    @Override
    public ExtractionResult process(StructuredProcessingRequest request) {
        String xml = request.textContent();
        if (!StringUtils.hasText(xml) && request.binaryContent() != null) {
            xml = new String(request.binaryContent(), StandardCharsets.UTF_8);
        }
        if (!StringUtils.hasText(xml)) {
            return new ExtractionResult(Map.of(), List.of(), List.of("TED structured processor received no XML payload"));
        }

        ProcurementDocument tedDocument = xmlParserService.parseDocument(xml);
        tedDocument.setDocumentHash(request.dedupHash());
        tedDocument.setXmlDocument(xml);
        tedDocument.setSourceFilename(request.sourceDescriptor().fileName());
        tedDocument.setSourcePath(request.sourceDescriptor().sourceUri());
        tedDocument.setFileSizeBytes(request.binaryContent() == null ? null : (long) request.binaryContent().length);

        var canonical = request.document();
        canonical.setDocumentType(DocumentType.TED_NOTICE);
        canonical.setDocumentFamily(DocumentFamily.PROCUREMENT);
        canonical.setStatus(DocumentStatus.CLASSIFIED);
        canonical.setTitle(tedDocument.getProjectTitle());
        canonical.setSummary(tedDocument.getProjectDescription());
        canonical.setLanguageCode(tedDocument.getLanguageCode());
        canonical.setMimeType(request.detectionResult().mimeType() == null ? "application/xml" : request.detectionResult().mimeType());
        if (StringUtils.hasText(tedDocument.getPublicationId())) {
            canonical.setBusinessKey("TED_NOTICE:" + tedDocument.getPublicationId());
        } else if (StringUtils.hasText(tedDocument.getNoticeId())) {
            canonical.setBusinessKey("TED_NOTICE:" + tedDocument.getNoticeId());
        }
        documentService.save(canonical);

        tedNoticeProjectionService.registerOrRefreshProjection(tedDocument, canonical.getId());

        Map<String, Object> payload = new LinkedHashMap<>();
        if (StringUtils.hasText(tedDocument.getProjectTitle())) payload.put("title", tedDocument.getProjectTitle());
        if (StringUtils.hasText(tedDocument.getProjectDescription())) payload.put("description", tedDocument.getProjectDescription());
        if (StringUtils.hasText(tedDocument.getBuyerName())) payload.put("buyerName", tedDocument.getBuyerName());
        if (tedDocument.getCpvCodes() != null && tedDocument.getCpvCodes().length > 0) payload.put("cpvCodes", String.join(", ", tedDocument.getCpvCodes()));
        if (tedDocument.getNutsCodes() != null && tedDocument.getNutsCodes().length > 0) payload.put("nutsCodes", String.join(", ", tedDocument.getNutsCodes()));
        payload.put("lotCount", tedDocument.getLots() == null ? 0 : tedDocument.getLots().size());
        payload.put("noticeId", tedDocument.getNoticeId());
        payload.put("publicationId", tedDocument.getPublicationId());

        Map<ContentRole, String> derivedText = new LinkedHashMap<>();
        if (StringUtils.hasText(tedDocument.getTextContent())) {
            derivedText.put(ContentRole.NORMALIZED_TEXT, tedDocument.getTextContent());
        }

        return new ExtractionResult(
                derivedText,
                List.of(new ExtractedStructuredPayload("ted-notice", payload)),
                List.of()
        );
    }
}
