package org.mte.numecoeval.referentiel.steps;

import io.cucumber.java.DataTableType;
import io.cucumber.java.fr.Alors;
import io.cucumber.java.fr.Et;
import io.cucumber.java.fr.Quand;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.mte.numecoeval.referentiel.domain.model.TypeEquipement;
import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.TypeEquipementJpaAdapter;
import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeequipement.ReferentielAdministrationTypeEquipementRestApi;
import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeequipement.ReferentielTypeEquipementRestApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static io.restassured.RestAssured.given;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

public class TypeEquipementStepDefinitions extends AbstractStepDefinitions {

    @Autowired
    TypeEquipementJpaAdapter jpaAdapter;

    @DataTableType
    public TypeEquipement typeEquipement(Map<String, String> entry) {
        return TypeEquipement.builder()
                .type(entry.get("type"))
                .source(StringUtils.defaultString(entry.get("source")))
                .commentaire(StringUtils.defaultString(entry.get("commentaire")))
                .serveur(Boolean.parseBoolean(entry.get("serveur")))
                .refEquipementParDefaut(StringUtils.defaultString(entry.get("refEquipementParDefaut")))
                .dureeVieDefaut(NumberUtils.createDouble(entry.get("dureeVieDefaut")))
                .build();
    }

    @Quand("le fichier CSV des types d'équipements {string} est importé par API et la réponse est {int}")
    public void importReferentielTypeEquipements(String nomFichier, int codeReponseHttpAttendu) throws FileNotFoundException, NoSuchMethodException {
        setupRestAssured();
        initAlimentationEtapeEtCritere();
        File file = ResourceUtils.getFile("classpath:" + nomFichier);
        String requestPath = Arrays.stream(ReferentielAdministrationTypeEquipementRestApi.class.getMethod("importCSV", MultipartFile.class)
                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
        response = given()
                .multiPart("file", file)
                .post(requestPath)
                .thenReturn();
        assertEquals(codeReponseHttpAttendu, response.getStatusCode());
    }

    @Et("La récupération de tous les types d'équipements renvoie {int} lignes")
    public void getAllTypeEquipement(int nombreLignesAttendues) throws NoSuchMethodException {
        List<TypeEquipement> typeEquipements = jpaAdapter.getAll();

        assertEquals(nombreLignesAttendues, typeEquipements.size());
    }

    @Alors("Vérifications des types d'équipements disponibles")
    public void checkImpactEquipements(List<TypeEquipement> dataTable) {
        List<TypeEquipement> datasInDatabase = jpaAdapter.getAll();

        assertEquals(dataTable.size(), datasInDatabase.size());
        dataTable.forEach(expected -> {
            var dataInDatabase = datasInDatabase.stream().filter(data -> data.getType().equals(expected.getType())).findFirst().orElse(null);
            assertNotNull(dataInDatabase, "Il existe un type d'équipement avec le type %s".formatted(expected.getType()));

            assertEquals(expected.getCommentaire(), dataInDatabase.getCommentaire(), "TypeEquipement %s : le commentaire ne matche pas".formatted(expected.getType()));
            assertEquals(expected.getSource(), dataInDatabase.getSource(), "TypeEquipement %s : la source ne matche pas".formatted(expected.getType()));
            assertEquals(expected.getDureeVieDefaut(), dataInDatabase.getDureeVieDefaut(), "TypeEquipement %s : la durée de vie par défaut ne matche pas".formatted(expected.getType()));
            assertEquals(expected.getRefEquipementParDefaut(), dataInDatabase.getRefEquipementParDefaut(), "TypeEquipement %s : la référence d'équipement par défaut ne matche pas".formatted(expected.getType()));
            assertEquals(expected.isServeur(), dataInDatabase.isServeur(), "TypeEquipement %s : le flag serveur ne matche pas".formatted(expected.getType()));
        });
    }

    @Et("La récupération unitaire d\'un type équipement {string} répond {int}")
    public void getTypeEquipementAndCheckHttpStatus(String type, int codeReponseHttpAttendu) throws NoSuchMethodException {

        String requestPath = Arrays.stream(ReferentielTypeEquipementRestApi.class.getMethod("getTypeEquipement", String.class)
                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
        response = given()
                .pathParam("type", type)
                .get(requestPath)
                .thenReturn();
        assertEquals(codeReponseHttpAttendu, response.getStatusCode());
    }
}
