package com.iqser.red.persistence.service.v2.external.api.impl.controller;

import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierResource.DOSSIER_ID_PARAM;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource.DOSSIER_TEMPLATE_ID_PARAM;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource.FILE_ID_PARAM;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.iqser.red.persistence.service.v1.external.api.impl.controller.AnalysisLogController;
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierTemplateController;
import com.iqser.red.persistence.service.v1.external.api.impl.controller.StatusController;
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentOverrideService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.Component;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentValue;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.EntityReference;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentsOverrides;
import com.iqser.red.service.persistence.service.v2.api.external.model.Entity;
import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponents;
import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponentsList;
import com.iqser.red.service.persistence.service.v2.api.external.resource.ComponentResource;

import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@Tag(name = "4. Component endpoints", description = "Provides operations related to components")
public class ComponentControllerV2 implements ComponentResource {

    private final DossierTemplateController dossierTemplateController;
    private final AnalysisLogController analysisLogController;
    private final StatusController statusController;
    private final ComponentOverrideService componentOverrideService;


    @Override
    public FileComponents getComponents(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                                        @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                                        @PathVariable(FILE_ID_PARAM) String fileId,
                                        @RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails) {

        dossierTemplateController.getDossierTemplate(dossierTemplateId);

        var componentLog = analysisLogController.getComponentLog(dossierId, fileId);
        var overrides = componentOverrideService.getOverrides(dossierId, fileId);

        Map<String, List<String>> components = new HashMap<>();
        List<Component> componentLogCategories = componentLog.getComponents();
        if (componentLogCategories != null && !componentLogCategories.isEmpty()) {
            componentLogCategories.forEach(c -> {

                if (overrides.getComponentOverrides() != null && overrides.getComponentOverrides().containsKey(c.getName())) {
                    components.computeIfAbsent(c.getName(), (x) -> new ArrayList<>()).add(overrides.getComponentOverrides().get(c.getName()));
                } else {
                    components.computeIfAbsent(c.getName(), (x) -> new ArrayList<>()).addAll(c.getComponentValues().stream().map(ComponentValue::getValue).toList());
                }
            });
        }

        Map<String, List<com.iqser.red.service.persistence.service.v2.api.external.model.Component>> componentsDetails = new HashMap<>();
        if (includeDetails && overrides.getComponentOverrides() != null) {
            componentLog.getComponents().forEach(c -> {
                componentsDetails.computeIfAbsent(c.getName(), (x) -> new ArrayList<>())
                        .addAll(c.getComponentValues().stream().map(entry -> convert(entry, overrides, c.getName())).toList());
            });
        }

        return FileComponents.builder().dossierTemplateId(dossierTemplateId).dossierId(dossierId).fileId(fileId).components(components).componentDetails(componentsDetails).build();
    }


    private com.iqser.red.service.persistence.service.v2.api.external.model.Component convert(ComponentValue componentValue, ComponentsOverrides overrides, String category) {

        return com.iqser.red.service.persistence.service.v2.api.external.model.Component.builder()
                .componentRule(componentValue.getComponentRuleId())
                .entityReferences(componentValue.getEntityReferences().stream().map(this::convertComponentEntityReference).toList())
                .originalValues(List.of(componentValue.getValue()))
                .values(overrides.getComponentOverrides().containsKey(category) ? List.of(overrides.getComponentOverrides().get(category)) : List.of(componentValue.getValue()))
                .build();
    }


    private Entity convertComponentEntityReference(EntityReference entityReference) {

        return Entity.builder()
                .id(entityReference.getId())
                .entityRule(entityReference.getEntityRuleId())
                .type(entityReference.getType())
                .pages(Set.of(entityReference.getPage()))
                .build();
    }


    @Override
    public FileComponentsList getComponentsOfDossier(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                                                     @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                                                     @RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails) {

        dossierTemplateController.getDossierTemplate(dossierTemplateId);
        var dossierFiles = statusController.getDossierStatus(dossierId);
        return new FileComponentsList(dossierFiles.stream().map(file -> getComponents(dossierTemplateId, dossierId, file.getFileId(), includeDetails)).toList());
    }

}
