package org.mte.numecoeval.referentiel.steps;

import io.cucumber.java.fr.Alors;
import io.cucumber.java.fr.Quand;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
import lombok.extern.slf4j.Slf4j;
import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactReseauDTO;
import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactreseau.ReferentielAdministrationImpactReseauRestApi;
import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactreseau.ReferentielImpactReseauRestApi;
import org.springframework.http.HttpStatus;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;

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

@Slf4j
public class ImpactReseauStepDefinitions  extends AbstractStepDefinitions {

    @Quand("on ajoute un facteur impact reseau dont la refReseau est {string}, etapeACV est  {string} ,  critere est {string} la source est {string} la valeur est {string} et l'unité est {string}")
    public void onAjouteUnFacteurImpactReseauDontLaRefReseauEstEtapeACVEstCritereEstLa(String refReseau, String etapeACV, String critere, String source, String valeur, String unite) throws ReferentielException, NoSuchMethodException, FileNotFoundException {
        log.debug("Debut creation d'un impact reseau dans table ref_impactReseau");
        initAlimentationEtapeEtCritere();
        String requestPath = Arrays.stream(ReferentielAdministrationImpactReseauRestApi.class.getMethod("add", ImpactReseauDTO.class)
                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
        ImpactReseauDTO impactReseau = new ImpactReseauDTO();
        impactReseau.setRefReseau(refReseau);
        impactReseau.setEtapeACV(etapeACV);
        impactReseau.setCritere(critere);
        impactReseau.setSource(source);
        impactReseau.setValeur(Double.valueOf(valeur));
        Response response = given()
                .contentType(ContentType.JSON)
                .body(impactReseau)
                .post(requestPath)
                .thenReturn();
        assertEquals(200, response.getStatusCode());
        ImpactReseauDTO impactReseauResultat = response.as(ImpactReseauDTO.class);
        //verification de la sortie
        assertEquals(refReseau, impactReseauResultat.getRefReseau());
        assertEquals(refReseau, impactReseauResultat.getRefReseau());
        assertEquals(source, impactReseauResultat.getSource());
        assertEquals(critere, impactReseauResultat.getCritere());
        assertEquals(etapeACV, impactReseauResultat.getEtapeACV());
        assertEquals(Double.valueOf(valeur), impactReseauResultat.getValeur());
        log.debug("Debut creation d'un impact reseau dans table ref_impactReseau");
    }

    @Alors("impact reseau est persister dans la table ref_impactReseau  avec les elements suivants: la refReseau est {string}, etapeACV est  {string} ,  critere est {string} la source est {string} la valeur est {string} et l'unité est {string}")
    public void impactReseauEstPersisterDansLaTableRef_impactReseau(String refReseau, String etapeACV, String critere, String source, String valeur, String unite) throws ReferentielException, NoSuchMethodException {
        log.debug("Debut recuperation depuis table ref_impactReseau pour verification de la CAF1");
        //check avec la ressource get
        //invocation de la ressource restapi ajout impact reseau
        String requestPath = Arrays.stream(ReferentielImpactReseauRestApi.class.getMethod("get", String.class, String.class, String.class)
                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
        Response response = given()
                .contentType(ContentType.JSON)
                .queryParam("refReseau", refReseau)
                .queryParam("etapeacv", etapeACV)
                .queryParam("critere", critere)
                .get(requestPath)
                .thenReturn();
        assertEquals(200, response.getStatusCode());
        ImpactReseauDTO impactReseauResultat = response.as(ImpactReseauDTO.class);
        //verification de la sortie
        assertEquals(refReseau, impactReseauResultat.getRefReseau());
        assertEquals(refReseau, impactReseauResultat.getRefReseau());
        assertEquals(source, impactReseauResultat.getSource());
        assertEquals(critere, impactReseauResultat.getCritere());
        assertEquals(etapeACV, impactReseauResultat.getEtapeACV());
        assertEquals(Double.valueOf(valeur), impactReseauResultat.getValeur());
        log.debug("END recuperation depuis table ref_impactReseau pour verification de la CAF1");
    }

    @Quand("on persiste un facteur impact reseau dont la refReseau est {string}, etapeACV est  {string} ,  critere est {string} la source est {string}")
    public void onPersisteUnFacteurImpactReseauDontLaRefReseauEstEtapeACVEstCritereEstLaSourceEst(String refReseau, String etapeACV, String critere, String source) throws NoSuchMethodException, FileNotFoundException {
        log.debug("Debut creation à vide dans table ref_impactReseau");
        //invoquation de la ressource restapi ajout impact reseau
        setupRestAssured();
        String requestPath = Arrays.stream(ReferentielAdministrationImpactReseauRestApi.class.getMethod("add", ImpactReseauDTO.class)
                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
        ImpactReseauDTO impactReseau = new ImpactReseauDTO();
        impactReseau.setRefReseau(refReseau);
        impactReseau.setEtapeACV(etapeACV);
        impactReseau.setCritere(critere);
        impactReseau.setSource(source);
        Response response = given()
                .contentType(ContentType.JSON)
                .body(impactReseau)
                .post(requestPath)
                .thenReturn();
        assertEquals(200, response.getStatusCode());
        ImpactReseauDTO impactReseauResultat = response.as(ImpactReseauDTO.class);
        //verification de la sortie
        assertEquals(refReseau, impactReseauResultat.getRefReseau());
        assertEquals(refReseau, impactReseauResultat.getRefReseau());
        assertEquals(source, impactReseauResultat.getSource());
        assertEquals(critere, impactReseauResultat.getCritere());
        assertEquals(etapeACV, impactReseauResultat.getEtapeACV());
        log.debug("Fin creation à vide  dans table ref_impactReseau");
    }


    @Alors("il est possible de modifier impact  Reseau avec les élements suivants: le refReseau est {string}, etapeACV est  {string} ,  critere est {string} la source est {string}, valeur est {string} et l'unité est {string}")
    public void ilEstPossibleDeModifierImpactReseau(String refReseau, String etapeACV, String critere, String source, String valeur, String unite) throws ReferentielException, NoSuchMethodException {
        log.debug("Debut modification impact reseau depuis table ref_impactReseau");
        //check avec REST API  GeT
        String requestPathGet = Arrays.stream(ReferentielImpactReseauRestApi.class.getMethod("get", String.class, String.class, String.class)
                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
        Response responseGet = given()
                .contentType(ContentType.JSON)
                .queryParam("refReseau", refReseau)
                .queryParam("etapeacv", etapeACV)
                .queryParam("critere", critere)
                .get(requestPathGet)
                .thenReturn();
        assertEquals(200, responseGet.getStatusCode());
        ImpactReseauDTO impactReseauResultatGet = responseGet.as(ImpactReseauDTO.class);
        //verification de la sortie
        assertEquals(etapeACV, impactReseauResultatGet.getEtapeACV());
        assertEquals(refReseau, impactReseauResultatGet.getRefReseau());
        assertEquals(critere, impactReseauResultatGet.getCritere());
        assertEquals(source, impactReseauResultatGet.getSource());
        assertNull(impactReseauResultatGet.getConsoElecMoyenne());
        //upadate avec rest api update
        //modification de l'impact vide
        //setupRestAssured();
        String requestPathUpdate = Arrays.stream(ReferentielAdministrationImpactReseauRestApi.class.getMethod("update", ImpactReseauDTO.class)
                .getAnnotation(PutMapping.class).path()).findFirst().orElse(null);
        ImpactReseauDTO impactReseau = new ImpactReseauDTO();
        impactReseau.setRefReseau(refReseau);
        impactReseau.setEtapeACV(etapeACV);
        impactReseau.setCritere(critere);
        impactReseau.setSource(source);
        impactReseau.setValeur(Double.valueOf(valeur));
        Response response = given()
                .contentType(ContentType.JSON)
                .body(impactReseau)
                .post(requestPathUpdate)
                .thenReturn();
        assertEquals(200, response.getStatusCode());
        ImpactReseauDTO impactReseauResultatUpdate = response.as(ImpactReseauDTO.class);
        //verification de la sortie
        assertEquals(refReseau, impactReseauResultatUpdate.getRefReseau());
        assertEquals(refReseau, impactReseauResultatUpdate.getRefReseau());
        assertEquals(source, impactReseauResultatUpdate.getSource());
        assertEquals(critere, impactReseauResultatUpdate.getCritere());
        assertEquals(etapeACV, impactReseauResultatUpdate.getEtapeACV());
        assertEquals(Double.valueOf(valeur), impactReseauResultatUpdate.getValeur());
        log.debug("Fin modification impact reseau depuis table ref_impactReseau");
    }

    @Quand("on ajoute un facteur impact reseau dont la refReseau est {string}, etapeACV est  {string} ,  critere est {string}  la valeur est {string} et l'unité est {string}")
    public void onAjouteUnFacteurImpactReseauDontLaRefReseau(String refReseau, String etapeACV, String critere, String valeur, String unite) throws NoSuchMethodException, FileNotFoundException {
        log.debug("Debut creation impact reseau sans source dans table ref_impactReseau");
        //invoquation de la ressource restapi ajout impact reseau
        setupRestAssured();
        String requestPath = Arrays.stream(ReferentielAdministrationImpactReseauRestApi.class.getMethod("add", ImpactReseauDTO.class)
                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
        ImpactReseauDTO impactReseau = new ImpactReseauDTO();
        impactReseau.setRefReseau(refReseau);
        impactReseau.setEtapeACV(etapeACV);
        impactReseau.setCritere(critere);
        impactReseau.setValeur(Double.valueOf(valeur));
        response = given()
                .contentType(ContentType.JSON)
                .body(impactReseau)
                .post(requestPath)
                .thenReturn();
        log.error("Fin creation impact reseau sans source dans table ref_impactReseau");
    }


    @Alors("Impossible d ajouter l'impact réseau dans la table ref_impactreseau")
    public void impossibleDAjouterLImpactReseauDansLaTableRef_impactreseau() {
        assertEquals(500, response.getStatusCode());
        ErrorResponseDTO impactReseauResultat = response.as(ErrorResponseDTO.class);
        //assertEquals("La source est obligatoire", impactReseauResultat.getMessage());
        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, impactReseauResultat.getStatus());
        assertEquals(500, impactReseauResultat.getCode());
        assertNotNull(impactReseauResultat.getTimestamp());
    }

    @Quand("le fichier CSV {string} est envoyé")
    public void leFichierCSVEstEnvoye(String fichier) throws IOException, NoSuchMethodException {
        File file = ResourceUtils.getFile("classpath:" + fichier);
        setupRestAssured();
        String requestPath = Arrays.stream(ReferentielAdministrationImpactReseauRestApi.class.getMethod("importCSV", MultipartFile.class)
                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
        Response response = given()
                .multiPart("file", file)
                .post(requestPath)
                .thenReturn();
        //check que le status est OK
        assertEquals(200, response.getStatusCode());
    }

    @Alors("l impact reseau  refReseal est {string}, etapeACV est  {string} ,  critere est {string} la source est {string} la valeur est {string} et l'unité est {string} existe")
    public void lImpactReseauRefResealEstE(String refReseau, String etapeACV, String critere, String source, String valeur, String unite) throws NoSuchMethodException {
        //recuperataion d'un resultat ajouter
        String requestPath = Arrays.stream(ReferentielImpactReseauRestApi.class.getMethod("get", String.class, String.class, String.class)
                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
        Response response = given()
                .contentType(ContentType.JSON)
                .queryParam("refReseau", refReseau)
                .queryParam("etapeacv", etapeACV)
                .queryParam("critere", critere)
                .get(requestPath)
                .thenReturn();
        ImpactReseauDTO impactReseauDTO = response.as(ImpactReseauDTO.class);
        assertEquals(200, response.getStatusCode());
        ImpactReseauDTO impactReseauResultat = response.as(ImpactReseauDTO.class);
        //verification de la sortie aleatoire
        assertEquals(refReseau, impactReseauResultat.getRefReseau());
        assertEquals(refReseau, impactReseauResultat.getRefReseau());
        assertEquals(source, impactReseauResultat.getSource());
        assertEquals(critere, impactReseauResultat.getCritere());
        assertEquals(etapeACV, impactReseauResultat.getEtapeACV());
        assertEquals(Double.valueOf(valeur), impactReseauResultat.getValeur());
    }


    @Quand("on cherche l impact reseau  dont la refReseau est {string}, etapeACV est  {string} ,  critere est {string}")
    public void onChercheLImpactReseauquinexistePAs(String refReseau, String etapeACV, String critere) throws NoSuchMethodException, FileNotFoundException {
        setupRestAssured();
        String requestPath = Arrays.stream(ReferentielImpactReseauRestApi.class.getMethod("get", String.class, String.class, String.class)
                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
        response = given()
                .contentType(ContentType.JSON)
                .queryParam("refReseau", refReseau)
                .queryParam("etapeacv", etapeACV)
                .queryParam("critere", critere)
                .get(requestPath)
                .thenReturn();
    }

    @Alors("lecture reponse impact resau n existe pas")
    public void lectureReponseImpactResauNExistePas() {
        assertEquals(404, response.getStatusCode());
        ErrorResponseDTO impactReseauResultat = response.as(ErrorResponseDTO.class);
        assertEquals("Impact Réseau non trouvé", impactReseauResultat.getMessage());
        assertEquals(HttpStatus.NOT_FOUND, impactReseauResultat.getStatus());
        assertEquals(404, impactReseauResultat.getCode());
        assertNotNull(impactReseauResultat.getTimestamp());
    }

}