package com.iqser.red.service.persistence.management.v1.processor.service;

import static com.iqser.red.service.persistence.management.v1.processor.exception.DossierNotFoundException.DOSSIER_NOT_FOUND_MESSAGE;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.DossierNotFoundException;
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierStats;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class DossierStatsService {

    private final DossierService dossierService;
    private final FileStatusService fileStatusService;

//    private Map<String, DossierStats> dossierStatsMap = new HashMap<>();

//    @Scheduled(fixedDelay = 10000, initialDelay = 1000)
//    external void computeDossierStats() {
//        log.info("Computing Dossier Stats ... ");
//        long start = System.currentTimeMillis();
//        Map<String, DossierStats> dossierStatsComputeMap = new HashMap<>();
//        dossierService.getAllDossiers().stream()
//                .filter(d -> !d.getStatus().equals(DossierStatus.DELETED))
//                .forEach(d -> dossierStatsComputeMap.put(d.getId(), computeDossierStats(d)));
//        dossierStatsMap.clear();
//        dossierStatsMap = dossierStatsComputeMap;
//        log.info("Dossier Stats Computed in {}ms", System.currentTimeMillis() - start);
//    }


    public DossierStats getDossierStats(String dossierId) {
//        var stats = dossierStatsMap.get(dossierId);
//        if (stats == null) {
//            stats = computeDossierStats(dossierService.getDossierById(dossierId));
//            dossierStatsMap.put(dossierId, stats);
//        }
        return computeDossierStats(dossierService.getDossierById(dossierId));
    }


    private DossierStats computeDossierStats(DossierEntity dossierEntity) {

        var dossierId = dossierEntity.getId();

        DossierStats dossierStats = new DossierStats();

        if (dossierEntity.getHardDeletedTime() != null) {
            throw new DossierNotFoundException(String.format(DOSSIER_NOT_FOUND_MESSAGE, dossierId));
        }

        dossierStats.setDossierId(dossierId);
        // get the associated files
        List<FileModel> files = fileStatusService.getActiveFiles(dossierId);
        dossierStats.setNumberOfFiles(files.size());
        dossierStats.setNumberOfSoftDeletedFiles(fileStatusService.countSoftDeletedFiles(dossierId));
        dossierStats.setNumberOfPages(files.stream().mapToInt(FileModel::getNumberOfPages).sum());
        dossierStats.setNumberOfExcludedPages(files.stream().mapToInt(f -> f.getExcludedPages().size()).sum());
        files.stream().filter(FileModel::isHasRedactions).findAny().ifPresent(v -> dossierStats.setHasRedactionsFilePresent(true));
        files.stream().filter(FileModel::isHasHints).filter(f -> !f.isHasRedactions()).findAny().ifPresent(v -> dossierStats.setHasHintsNoRedactionsFilePresent(true));
        files.stream().filter(FileModel::isHasSuggestions).findAny().ifPresent(v -> dossierStats.setHasSuggestionsFilePresent(true));
        files.stream().filter(FileModel::isHasUpdates).findAny().ifPresent(v -> dossierStats.setHasUpdatesFilePresent(true));
        files.stream()
                .filter(f -> !f.isHasRedactions())
                .filter(f -> !f.isHasHints())
                .filter(f -> !f.isHasSuggestions())
                .filter(f -> !f.isHasUpdates())
                .findAny()
                .ifPresent(v -> dossierStats.setHasNoFlagsFilePresent(true));
        var fileCountPerProcessingStatus = files.stream().collect(Collectors.toMap(FileModel::getProcessingStatus, e -> 1, Math::addExact));
        dossierStats.setFileCountPerProcessingStatus(fileCountPerProcessingStatus);

        var fileCountPerWorkflowStatus = files.stream().collect(Collectors.toMap(FileModel::getWorkflowStatus, e -> 1, Math::addExact));
        dossierStats.setFileCountPerWorkflowStatus(fileCountPerWorkflowStatus);

        files.stream()
                .sorted(Comparator.comparing(FileModel::getLastUpdated, Comparator.nullsLast(Comparator.reverseOrder())))
                .findFirst()
                .ifPresent(file -> dossierStats.setLastFileUpdateDate(file.getLastUpdated()));
        files.stream()
                .sorted(Comparator.comparing(FileModel::getFileManipulationDate, Comparator.nullsLast(Comparator.reverseOrder())))
                .findFirst()
                .ifPresent(file -> dossierStats.setFileManipulationDate(file.getFileManipulationDate()));
        return dossierStats;
    }

}
