package at.procon.dip.domain.ted.service;

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.entity.Document;
import at.procon.dip.domain.document.repository.DocumentRepository;
import at.procon.dip.domain.document.service.DocumentService;
import at.procon.dip.domain.document.service.command.CreateDocumentCommand;
import at.procon.dip.runtime.condition.ConditionalOnRuntimeMode;
import at.procon.dip.runtime.config.RuntimeMode;
import at.procon.ted.model.entity.ProcurementDocument;
import at.procon.ted.model.entity.TedDailyPackage;
import at.procon.ted.repository.TedDailyPackageRepository;
import at.procon.ted.util.HashUtils;
import java.time.OffsetDateTime;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@ConditionalOnRuntimeMode(RuntimeMode.NEW)
@RequiredArgsConstructor
public class TedPackageDocumentService {

    private static final String PACKAGE_MIME_TYPE = "application/gzip";

    private final TedPackageIdentifierResolver packageIdentifierResolver;
    private final TedDailyPackageRepository tedDailyPackageRepository;
    private final DocumentRepository documentRepository;
    private final DocumentService documentService;

    @Transactional
    public Optional<Document> ensurePackageDocumentForLegacyNotice(ProcurementDocument legacyDocument) {
        return packageIdentifierResolver.resolveFromSourceMetadata(legacyDocument.getSourcePath(), legacyDocument.getSourceFilename())
                .map(this::ensurePackageDocument);
    }

    @Transactional
    public Document ensurePackageDocument(String packageIdentifier) {
        String businessKey = buildBusinessKey(packageIdentifier);
        Document document = documentRepository.findByBusinessKey(businessKey)
                .orElseGet(() -> createPackageDocument(packageIdentifier));

        Optional<TedDailyPackage> packageEntity = tedDailyPackageRepository.findByPackageIdentifier(packageIdentifier);
        document.setVisibility(DocumentVisibility.PUBLIC);
        document.setDocumentType(DocumentType.TED_PACKAGE);
        document.setDocumentFamily(DocumentFamily.PROCUREMENT);
        document.setStatus(resolveStatus(packageEntity));
        document.setTitle(buildTitle(packageIdentifier));
        document.setSummary(buildSummary(packageIdentifier, packageEntity.orElse(null)));
        document.setMimeType(PACKAGE_MIME_TYPE);
        document.setBusinessKey(businessKey);
        document.setDedupHash(HashUtils.computeSha256(businessKey));
        return documentService.save(document);
    }

    private Document createPackageDocument(String packageIdentifier) {
        String businessKey = buildBusinessKey(packageIdentifier);
        return documentService.create(new CreateDocumentCommand(
                null,
                DocumentVisibility.PUBLIC,
                DocumentType.TED_PACKAGE,
                DocumentFamily.PROCUREMENT,
                DocumentStatus.RECEIVED,
                buildTitle(packageIdentifier),
                null,
                null,
                PACKAGE_MIME_TYPE,
                businessKey,
                HashUtils.computeSha256(businessKey)
        ));
    }

    private DocumentStatus resolveStatus(Optional<TedDailyPackage> packageEntity) {
        if (packageEntity.isEmpty()) {
            return DocumentStatus.RECEIVED;
        }
        return switch (packageEntity.get().getDownloadStatus()) {
            case COMPLETED -> DocumentStatus.CLASSIFIED;
            case FAILED, NOT_FOUND -> DocumentStatus.FAILED;
            default -> DocumentStatus.RECEIVED;
        };
    }

    private String buildBusinessKey(String packageIdentifier) {
        return "TED_PACKAGE:" + packageIdentifier;
    }

    private String buildTitle(String packageIdentifier) {
        return packageIdentifier + ".tar.gz";
    }

    private String buildSummary(String packageIdentifier, TedDailyPackage packageEntity) {
        if (packageEntity == null) {
            return "TED daily package " + packageIdentifier;
        }
        return "TED daily package %s (status=%s, xmlFileCount=%s, processedCount=%s, failedCount=%s, downloadedAt=%s)".formatted(
                packageIdentifier,
                packageEntity.getDownloadStatus(),
                packageEntity.getXmlFileCount(),
                packageEntity.getProcessedCount(),
                packageEntity.getFailedCount(),
                formatTimestamp(packageEntity.getDownloadedAt())
        );
    }

    private String formatTimestamp(OffsetDateTime value) {
        return value == null ? null : value.toString();
    }
}
