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

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierTemplateEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierRepository;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplateDictionaryStats;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplateStats;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplateStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionarySummary;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionarySummaryResponse;

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

@Slf4j
@Service
@RequiredArgsConstructor
public class DossierTemplateStatsService {

    private final DictionaryPersistenceService dictionaryPersistenceService;

    private final DossierTemplatePersistenceService dossierTemplatePersistenceService;

    private final DossierTemplateRepository dossierTemplateRepository;

    private final FileRepository fileRepository;

    private final DossierRepository dossierRepository;


    public DossierTemplateStats getDossierTemplateStats(String dossierTemplateId) {

        var dossierTemplate = dossierTemplateRepository.findByIdAndNotDeleted(dossierTemplateId)
                .orElseThrow(() -> new NotFoundException("Dossier Template with id: " + dossierTemplateId + " not found."));
        dossierTemplate.setDossierTemplateStatus(dossierTemplatePersistenceService.computeDossierTemplateStatus(dossierTemplate));
        return getDossierTemplateStats(dossierTemplateId, dossierTemplate.getName(), dossierTemplate.getDossierTemplateStatus());
    }


    private DossierTemplateStats getDossierTemplateStats(String dossierTemplateId, String dossierTemplateName, DossierTemplateStatus dossierTemplateStatus) {

        DossierTemplateStats dts = new DossierTemplateStats();

        dts.setDossierTemplateId(dossierTemplateId);
        dts.setName(dossierTemplateName);
        dts.setDossierTemplateStatus(dossierTemplateStatus);
        dts.setNumberOfArchivedDossiers(dossierRepository.countArchived(dossierTemplateId));
        dts.setNumberOfActiveDossiers(dossierRepository.countActive(dossierTemplateId));
        dts.setNumberOfDeletedDossiers(dossierRepository.countSofDeleted(dossierTemplateId));
        dts.setNumberOfActiveFiles(fileRepository.countActiveFiles(dossierTemplateId));
        dts.setNumberOfSoftDeletedFiles(fileRepository.countSoftDeletedFilesPerDossierTemplateId(dossierTemplateId));

        var processingCounts = fileRepository.countFilesByProcessingStatus(dossierTemplateId);
        var workflowCounts = fileRepository.countFilesByWorkflowStatus(dossierTemplateId);
        var pageCounts = fileRepository.countPages(dossierTemplateId);
        var dossierStatusCounts = dossierRepository.countByDossierStatus(dossierTemplateId);

        dts.setNumberOfPages(pageCounts.getNumberOfAnalyzedPages());
        dts.setNumberOfExcludedPages(pageCounts.getNumberOfExcludedPages());

        dts.setFileCountPerProcessingStatus(processingCounts.stream()
                .map(t -> new DossierTemplateStats.ProcessingStatusCount(t.getProcessingStatus(), t.getCount()))
                .collect(Collectors.toList()));
        dts.setFileCountPerWorkflowStatus(workflowCounts.stream()
                .map(t -> new DossierTemplateStats.WorkflowStatusCount(t.getWorkflowStatus(), t.getCount()))
                .collect(Collectors.toList()));
        dts.setDossierCountByStatus(dossierStatusCounts.stream()
                .map(t -> new DossierTemplateStats.DossierStatusCount(t.getDossierStatusId(), t.getCount()))
                .collect(Collectors.toList()));

        dts.setDossiersInTemplate(dossierRepository.findActiveDossierIdsForTemplate(dossierTemplateId));

        return dts;
    }


    public List<DossierTemplateStats> getDossierTemplateStats() {

        var allUnDeletedTemplates = dossierTemplateRepository.findAllWhereDeletedIsFalse();

        allUnDeletedTemplates.forEach(dt -> dt.setDossierTemplateStatus(dossierTemplatePersistenceService.computeDossierTemplateStatus(dt)));
        List<DossierTemplateEntity> templates = allUnDeletedTemplates.stream()
                .filter(dt -> !DossierTemplateStatus.INCOMPLETE.equals(dt.getDossierTemplateStatus()))
                .collect(Collectors.toList());

        final List<DossierTemplateStats> dossierTemplateStatsList = Collections.synchronizedList(new ArrayList<>());
        templates.stream().forEach(dt -> dossierTemplateStatsList.add(getDossierTemplateStats(dt.getId(), dt.getName(), dt.getDossierTemplateStatus())));

        List<DossierTemplateStats> result = dossierTemplateStatsList.stream()
                .filter(stat -> !(DossierTemplateStatus.INACTIVE.equals(stat.getDossierTemplateStatus()) && stat.getNumberOfActiveDossiers() == 0 && stat.getNumberOfArchivedDossiers() == 0))
                .collect(Collectors.toList());
        result.sort(Comparator.comparing(DossierTemplateStats::getName));

        return result;
    }


    public List<DossierTemplateDictionaryStats> getDossierTemplateStats(Set<String> dossierTemplateIds) {

        List<DictionarySummaryResponse> dictionarySummaryList = dictionaryPersistenceService.getDictionarySummaryForDossierTemplateId(dossierTemplateIds);
        Map<String, List<DictionarySummary>> dictionarySummaryMap = dictionarySummaryList.stream()
                .collect(Collectors.groupingBy(DictionarySummaryResponse::getDossierTemplateId, Collectors.mapping(this::getDossierTemplateStats, Collectors.toList())));
        List<DossierTemplateDictionaryStats> dossierTemplateStatsList = dictionarySummaryMap.entrySet()
                .stream()
                .map(e -> e.getValue().size() == 1 && e.getValue().get(0).getId() == null ? new DossierTemplateDictionaryStats(e.getKey(),
                        0,
                        new ArrayList<>()) : new DossierTemplateDictionaryStats(e.getKey(), e.getValue().size(), e.getValue()))
                .collect(Collectors.toList());
        // add the dossier templates with no dictionaries but with dossiers
        Set<String> dossierTemplatesIdsFounded = dossierTemplateStatsList.stream().map(DossierTemplateDictionaryStats::getDossierTemplateId).collect(Collectors.toSet());

        dossierTemplateIds.removeAll(dossierTemplatesIdsFounded);
        List<DossierTemplateDictionaryStats> dossierTemplateStatsListForDossierNotFound = dossierTemplateIds.stream()
                .map(e -> new DossierTemplateDictionaryStats(e, 0, new ArrayList<>()))
                .collect(Collectors.toList());
        dossierTemplateStatsList.addAll(dossierTemplateStatsListForDossierNotFound);
        return dossierTemplateStatsList;
    }


    private DictionarySummary getDossierTemplateStats(DictionarySummaryResponse response) {

        return new DictionarySummary(response.getId(), response.getType(), response.getName(), response.getEntriesCount());
    }

}
