package at.procon.ted.service;

import at.procon.ted.config.TedProcessorProperties;
import at.procon.ted.model.entity.ProcurementDocument;
import at.procon.ted.model.entity.VectorizationStatus;
import at.procon.ted.repository.ProcurementDocumentRepository;
import at.procon.dip.runtime.condition.ConditionalOnRuntimeMode;
import at.procon.dip.runtime.config.RuntimeMode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.OffsetDateTime;
import java.util.UUID;

/**
 * Service for vectorization processing with transactional support.
 * Called by VectorizationRoute to ensure proper transaction management.
 *
 * @author Martin.Schweitzer@procon.co.at and claude.ai
 */
@Service
@ConditionalOnRuntimeMode(RuntimeMode.LEGACY)
@RequiredArgsConstructor
@Slf4j
public class VectorizationProcessorService {

    private final ProcurementDocumentRepository documentRepository;
    private final TedProcessorProperties properties;

    /**
     * Load document text content for vectorization (memory efficient - does NOT load XML).
     * Updates status to PROCESSING.
     *
     * @return DocumentContent with text and documentId, or null if should skip
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public DocumentContent prepareDocumentForVectorization(UUID documentId) {
        // Update status to PROCESSING first
        documentRepository.updateVectorizationStatus(
                documentId,
                VectorizationStatus.PROCESSING,
                null,
                null
        );

        // Load ONLY text content (not the whole document with XML) - memory efficient
        String textContent = documentRepository.findTextContentById(documentId);

        if (textContent == null || textContent.isBlank()) {
            documentRepository.updateVectorizationStatus(
                    documentId,
                    VectorizationStatus.SKIPPED,
                    "No text content available",
                    OffsetDateTime.now()
            );
            return null; // Skip vectorization
        }

        // Truncate if necessary
        int maxLength = properties.getVectorization().getMaxTextLength();
        if (textContent.length() > maxLength) {
            textContent = textContent.substring(0, maxLength);
            log.debug("Truncated text content for document {} from {} to {} chars",
                    documentId, textContent.length(), maxLength);
        }

        return new DocumentContent(documentId, textContent);
    }

    /**
     * Save embedding vector to database.
     * Updates status to COMPLETED.
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void saveEmbedding(UUID documentId, float[] embedding, Integer tokenCount) {
        if (embedding == null || embedding.length != properties.getVectorization().getDimensions()) {
            throw new RuntimeException("Invalid embedding dimension: expected " +
                    properties.getVectorization().getDimensions() +
                    ", got " + (embedding != null ? embedding.length : 0));
        }

        // Convert to PostgreSQL vector format
        String vectorStr = floatArrayToVectorString(embedding);

        // Update document with vector and token count
        documentRepository.updateContentVector(documentId, vectorStr, tokenCount);

        log.debug("Successfully vectorized document: {} ({} tokens)", documentId, tokenCount);
    }

    /**
     * Mark document as failed with error message.
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void markAsFailed(UUID documentId, String errorMessage) {
        log.debug("Vectorization failed for document {}: {}", documentId, errorMessage);

        documentRepository.updateVectorizationStatus(
                documentId,
                VectorizationStatus.FAILED,
                errorMessage,
                OffsetDateTime.now()
        );
    }

    /**
     * Convert float array to PostgreSQL vector format: [0.1,0.2,0.3]
     */
    private String floatArrayToVectorString(float[] embedding) {
        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < embedding.length; i++) {
            if (i > 0) sb.append(",");
            sb.append(embedding[i]);
        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * Document content holder for vectorization.
     */
    public record DocumentContent(UUID documentId, String textContent) {}
}
