package org.mte.numecoeval.expositiondonneesentrees.domain.ports.input;

import org.apache.commons.csv.CSVRecord;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.mte.numecoeval.expositiondonneesentrees.domain.exception.ValidationException;
import org.mte.numecoeval.expositiondonneesentrees.domain.model.*;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;

@SuppressWarnings("java:S107")
// Obligatoire à cause de la gestion des fichiers différents au niveau contrat d'interface
public interface ImportDonneesEntreePort {
    String EQUIPEMENT_PHYSIQUE_CSV_HEADER = "modele;quantite;nomEquipementPhysique;type;statut;paysDUtilisation;utilisateur;nbCoeur;nomCourtDatacenter;goTelecharge;nbJourUtiliseAn;consoElecAnnuelle";
    String CSV_SEPARATOR = ";";
    String DATA_CENTER_CSV_HEADER = "nomCourtDatacenter;nomLongDatacenter;pue;localisation";
    String EQUIPEMENT_VIRTUEL_CSV_HEADER = "nomEquipementPhysique;vCPU;cluster";
    String APPLICATION_CSV_HEADER = "nomApplication;typeEnvironnement;nomEquipementPhysique;domaine;sousDomaine";
    String OPERATION_NON_IT_CSV_HEADER = "nomItemNonIT;quantite;type;localisation;dureeDeVie;nomCourtDatacenter;description;consoElecAnnuelle";
    String[] OPERATION_NON_IT_NOT_BLANK_FIELDS = {"nomItemNonIT", "quantite", "type", "localisation"};
    String MESSAGERIE_CSV_HEADER = "nombreMailEmis;nombreMailEmisXDestinataires;volumeTotalMailEmis;MoisAnnee";
    String ENTITE_CSV_HEADER = "nomEntite;nbCollaborateurs;responsableEntite;responsableNumeriqueDurable";
    String MESSAGE_LIGNE_INVALIDE = "La ligne n°%d est invalide : %s";

    ResultatImport importCsv(String nomOrganisation, String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel,
                             MultipartFile csvApplication, MultipartFile csvOperationNonIT, MultipartFile csvMessagerie, MultipartFile csvEntite);

    Pair<RapportImport, List<DataCenter>> importDataCenter(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvDataCenter);

    Pair<RapportImport, List<EquipementPhysique>> importEquipementsPhysiques(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvEquipementPhysique);

    Pair<RapportImport, List<EquipementVirtuel>> importEquipementsVirtuels(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvEquipementVirtuel);

    Pair<RapportImport, List<Application>> importApplications(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvApplication);

    Pair<RapportImport, List<OperationNonIT>> importOperationsNonIT(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvOperationNonIT);

    Pair<RapportImport, List<Messagerie>> importMessageries(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvMessagerie);

    Pair<RapportImport, List<Entite>> importEntite(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvMessagerie);


    default boolean isFieldIsMappedAtLeastOnce(CSVRecord csvRecord, String mainName, String... alternativeNames) {
        if (csvRecord.isMapped(mainName)) {
            return true;
        }

        for (String alternativeName : alternativeNames) {
            if (csvRecord.isMapped(alternativeName)) {
                return true;
            }
        }
        return false;
    }

    default String checkAllHeadersAreMapped(CSVRecord csvRecord, String[] headers) {
        if (Arrays.stream(headers).allMatch(csvRecord::isMapped)) {
            return null;
        }
        return (MESSAGE_LIGNE_INVALIDE.formatted(csvRecord.getRecordNumber() + 1, "Entêtes incohérentes"));
    }

    default String checkFieldsAreMappedAndNotBlankInCSVRecord(CSVRecord csvRecord, String[] fields) throws ValidationException {
        for (String field : fields) {
            if (StringUtils.isBlank(csvRecord.get(field))) {
                return (MESSAGE_LIGNE_INVALIDE.formatted(csvRecord.getRecordNumber() + 1, "La colonne " + field + " ne peut être vide"));
            }
        }
        return null;
    }

    default String checkCSVRecord(CSVRecord csvRecord, String[] mandatoryHeaders, String[] notBlankFields) {
        if (checkAllHeadersAreMapped(csvRecord, mandatoryHeaders) != null) {
            return checkAllHeadersAreMapped(csvRecord, mandatoryHeaders);
        } else if (checkFieldsAreMappedAndNotBlankInCSVRecord(csvRecord, notBlankFields) != null) {
            return checkFieldsAreMappedAndNotBlankInCSVRecord(csvRecord, notBlankFields);
        }
        return null;
    }

}
