/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.bytesw.bytebot.service;

import com.bytesw.bytebot.bean.AgentBean;
import com.bytesw.bytebot.bean.ChannelBean;
import com.bytesw.bytebot.bean.CountryBean;
import com.bytesw.bytebot.bean.DeploymentChannelBean;
import com.bytesw.bytebot.bean.DeploymentChannelParamValueBean;
import com.bytesw.bytebot.bean.FrequentQuestionBean;
import com.bytesw.bytebot.model.Agent;
import com.bytesw.bytebot.model.Channel;
import com.bytesw.bytebot.model.ChannelParam;
import com.bytesw.bytebot.model.Country;
import com.bytesw.bytebot.model.DeploymentChannel;
import com.bytesw.bytebot.model.DeploymentChannelParamValue;
import com.bytesw.bytebot.model.FrequentQuestion;
import com.bytesw.bytebot.model.QuestionFile;
import com.bytesw.bytebot.model.enums.AgentStatusEnum;
import com.bytesw.bytebot.model.enums.AgentTypeEnum;
import com.bytesw.bytebot.model.enums.FrequentQuestionStatusEnum;
import com.bytesw.bytebot.model.enums.LanguageEnum;
import com.bytesw.bytebot.model.enums.StatusEnum;
import com.bytesw.bytebot.repository.AgentRepository;
import com.bytesw.bytebot.repository.ChannelParamRepository;
import com.bytesw.bytebot.repository.ChannelRepository;
import com.bytesw.bytebot.repository.CountryRepository;
import com.bytesw.bytebot.repository.DeploymentChannelParamValueRepository;
import com.bytesw.bytebot.repository.DeploymentChannelRepository;
import com.bytesw.bytebot.repository.FrequentQuestionRepository;
import com.bytesw.bytebot.repository.QuestionFileRepository;
import com.bytesw.xdf.sql.beans.Pagination;
import com.bytesw.xdf.sql.beans.SortField;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import org.apache.camel.ProducerTemplate;
import static org.assertj.core.api.Java6Assertions.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.mockito.ArgumentMatchers.any;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author Hernán Uriarte Melchor
 * @version 14/09/18.
 * <p>
 * <p>
 * Copyright (c) 2018 Byte, S.A. Todos los derechos reservados.
 * <p>
 * Este software constituye información confidencial y propietaria de Byte, S.A.
 * ("Información Confidencial"). Usted no debe develar dicha Información
 * Confidencial y debe usarla de acuerdo con los términos de aceptación de
 * licencia de uso que firmó con Byte.
 */
@RunWith(SpringRunner.class)
public class AgentServiceTest {

    @TestConfiguration
    static class AgentServiceTestContextConfiguration {

        @MockBean
        private AgentRepository agentRepository;

        @MockBean
        private CountryRepository countryRepository;

        @MockBean
        private DeploymentChannelRepository deploymentChannelRepository;

        @MockBean
        private DeploymentChannelParamValueRepository deploymentChannelParamValueRepository;

        @MockBean
        private ChannelRepository channelRepository;

        @MockBean
        private ChannelParamRepository channelParamRepository;

        @MockBean
        private FrequentQuestionRepository frequentQuestionRepository;

        @MockBean
        private QuestionFileRepository questionFileRepository;

        @MockBean
        private ProducerTemplate producerTemplate;

        @Bean
        public AgentService agentService() {
            return new AgentService();
        }
    }

    @Autowired
    private AgentService agentService;

    @Autowired
    private ChannelRepository channelRepository;

    @Autowired
    private CountryRepository countryRepository;

    @Autowired
    private AgentRepository agentRepository;

    @Autowired
    private FrequentQuestionRepository frequentQuestionRepository;

    @Autowired
    private QuestionFileRepository questionFileRepository;

    @Autowired
    private ProducerTemplate producerTemplate;

    @Autowired
    private DeploymentChannelRepository deploymentChannelRepository;

    @Autowired
    private DeploymentChannelParamValueRepository deploymentChannelParamValueRepository;

    @Autowired
    private ChannelParamRepository channelParamRepository;

    @Before
    public void setUp() {
    }
    
    @Test
    public void searchByPagination_whenThereAreNotSortField_isOK(){
        Pagination<AgentBean> pagination = new Pagination<>();
        pagination.setItemsPerPage(20);
        pagination.setCurrentPage(1);
        
        List<Agent> listOfAgents = new ArrayList<>();
        Country countryPeru = new Country();
        countryPeru.setId(1L);
        countryPeru.setName("PERU");       
        
        Agent agentA = new Agent();
        agentA.setId(1L);
        agentA.setName("BYTEBOT");
        agentA.setVersion("1.0.0");
        agentA.setStatus(AgentStatusEnum.PENDING_SYNCHRONIZED);
        agentA.setTimezone("GMT-5");
        agentA.setAvatar("bytebot.png");
        agentA.setCountry(countryPeru);
        
        Agent agentB = new Agent();
        agentB.setId(1L);
        agentB.setName("BFMBOT");
        agentB.setVersion("2.0.0");
        agentB.setStatus(AgentStatusEnum.PENDING_SYNCHRONIZED);
        agentB.setTimezone("GMT-5");
        agentB.setAvatar("bfmbot.png");
        agentB.setCountry(countryPeru);
        
        listOfAgents.add(agentA);
        listOfAgents.add(agentB);
        
        Page<Agent> page = new PageImpl<>(listOfAgents);
        
        Mockito.when(agentRepository.findAll(any(Specification.class), any(Pageable.class)))
                .thenReturn(page);
        
        agentService.searchByPagination(pagination);
    }
    
    @Test
    public void searchByPagination_whenThereAreResults_isOK(){
        Pagination<AgentBean> pagination = new Pagination<>();
        pagination.setItemsPerPage(20);
        pagination.setCurrentPage(1);
        
        SortField[] orderFields = new SortField[1];
        
        SortField sortFieldA = new SortField();
        sortFieldA.setDirection("asc");
        sortFieldA.setField("id");
        orderFields[0] = sortFieldA;
        
        pagination.setSortFields(orderFields);
        List<Agent> listOfAgents = new ArrayList<>();
        Country countryPeru = new Country();
        countryPeru.setId(1L);
        countryPeru.setName("PERU");       
        
        Agent agentA = new Agent();
        agentA.setId(1L);
        agentA.setName("BYTEBOT");
        agentA.setVersion("1.0.0");
        agentA.setStatus(AgentStatusEnum.PENDING_SYNCHRONIZED);
        agentA.setTimezone("GMT-5");
        agentA.setAvatar("bytebot.png");
        agentA.setCountry(countryPeru);
        
        Agent agentB = new Agent();
        agentB.setId(1L);
        agentB.setName("BFMBOT");
        agentB.setVersion("2.0.0");
        agentB.setStatus(AgentStatusEnum.PENDING_SYNCHRONIZED);
        agentB.setTimezone("GMT-5");
        agentB.setAvatar("bfmbot.png");
        agentB.setCountry(countryPeru);
        
        listOfAgents.add(agentA);
        listOfAgents.add(agentB);
        
        Page<Agent> page = new PageImpl<>(listOfAgents);
        
        
        
        Mockito.when(agentRepository.findAll(any(Specification.class), any(Pageable.class)))
                .thenReturn(page);
        
        agentService.searchByPagination(pagination);
    }

    @Test
    public void save_whenAgentExists_OK() {
        Long idAgente = 1L;
        Long idCountry = 1L;
        Long idFrequentQuestion = 1L;

        Agent agentBD = new Agent();
        agentBD.setId(idAgente);
        agentBD.setName("BOT-1");
        agentBD.setDescription("BOT BASICO DE PREGUNTAS");
        agentBD.setVersion("0.0.1");
        agentBD.setLanguage(LanguageEnum.SPANISH);
        agentBD.setTimezone("GMT-5");
        agentBD.setType(AgentTypeEnum.FREQUENT_QUESTION);
        agentBD.setStatus(AgentStatusEnum.CREATED);
        agentBD.setAvatar("avatar-png");

        Country countryA = new Country();
        countryA.setId(idCountry);
        countryA.setName("Perú");

        agentBD.setCountry(countryA);

        List<FrequentQuestion> frequentQuestions = new ArrayList<>();
        FrequentQuestion frequentQuestionA = new FrequentQuestion();
        frequentQuestionA.setId(idFrequentQuestion);
        frequentQuestionA.setDescription("Preguntas de entrenamiento");
        frequentQuestionA.setUser("lortiz");
        frequentQuestionA.setFilename("preguntas-base-old.xls");
        frequentQuestionA.setUploadDate(LocalDateTime.now());
        frequentQuestionA.setStatus(FrequentQuestionStatusEnum.PENDING_SYNCHRONIZED);

        frequentQuestions.add(frequentQuestionA);

        agentBD.setFrequentQuestions(frequentQuestions);

        List<DeploymentChannel> deploymentChannels = new ArrayList<>();
        DeploymentChannel deploymentChannelA = new DeploymentChannel();
        deploymentChannelA.setId(1L);
        deploymentChannelA.setName("FACEBOOK");
        deploymentChannelA.setStatus(StatusEnum.ACTIVE);

        Channel channelA = new Channel();
        channelA.setId(1L);
        channelA.setName("FACEBOOK");

        deploymentChannelA.setChannel(channelA);

        List<DeploymentChannelParamValue> parameters = new ArrayList<>();
        ChannelParam channelParamA = new ChannelParam();
        channelParamA.setId(1L);
        channelParamA.setName("token");

        DeploymentChannelParamValue parameterA = new DeploymentChannelParamValue();
        parameterA.setId(1L);
        parameterA.setValue("facebook-abc");
        parameterA.setParameter(channelParamA);

        DeploymentChannelParamValue parameterB = new DeploymentChannelParamValue();
        parameterB.setId(2L);
        parameterB.setValue("https://facebook....");

        parameters.add(parameterA);
        parameters.add(parameterB);

        deploymentChannelA.setParameters(parameters);

        DeploymentChannel deploymentChannelB = new DeploymentChannel();
        deploymentChannelB.setId(2L);
        deploymentChannelB.setName("WHATSAPP");
        deploymentChannelB.setStatus(StatusEnum.INACTIVE);
        deploymentChannelB.setParameters(new ArrayList<>());

        deploymentChannels.add(deploymentChannelA);
        deploymentChannels.add(deploymentChannelB);

        agentBD.setDeploymentChannels(deploymentChannels);

        // Agent Data Bean
        AgentBean agentBeanA = new AgentBean();
        agentBeanA.setId(idAgente);
        agentBeanA.setName("BOT-AGENT");
        agentBeanA.setDescription("BOT AVANZADO DE PREGUNTAS");
        agentBeanA.setVersion("2.0.0");
        agentBeanA.setLanguage(LanguageEnum.SPANISH.getName());
        agentBeanA.setTimezone("GMT-5");
        agentBeanA.setType(AgentTypeEnum.FREQUENT_QUESTION.getName());
        agentBeanA.setStatus(AgentStatusEnum.CREATED.getName());
        agentBeanA.setAvatar("avatar-BOT.png");
        agentBeanA.setCountryId(countryA.getId());
        agentBeanA.setCountryName(countryA.getName());

        agentBeanA.setFrequentQuestions(new ArrayList<>());

        FrequentQuestionBean frequentQuestionBeanA = new FrequentQuestionBean();
        frequentQuestionBeanA.setId(idFrequentQuestion);
        frequentQuestionBeanA.setUuid("");
        frequentQuestionBeanA.setDescription("Database Principal");
        frequentQuestionBeanA.setUser("lortiz");
        frequentQuestionBeanA.setFilename("preguntas-advanced.xls");
        frequentQuestionBeanA.setStatus(FrequentQuestionStatusEnum.PENDING_SYNCHRONIZED.getName());

        agentBeanA.getFrequentQuestions().add(frequentQuestionBeanA);

        FrequentQuestionBean frequentQuestionBeanB = new FrequentQuestionBean();
        //frequentQuestionBeanB.setId(12L);
        frequentQuestionBeanB.setUuid("");
        frequentQuestionBeanB.setDescription("Database Secundaria");
        frequentQuestionBeanB.setUser("lortiz");
        frequentQuestionBeanB.setFilename("preguntas-advanced-TIGO.xls");
        frequentQuestionBeanB.setStatus(FrequentQuestionStatusEnum.PENDING_SYNCHRONIZED.getName());

        agentBeanA.getFrequentQuestions().add(frequentQuestionBeanB);

        agentBeanA.setDeploymentChannels(new ArrayList<>());

        DeploymentChannelBean deploymentChannelBeanA = new DeploymentChannelBean();
        deploymentChannelBeanA.setId(1L);
        deploymentChannelBeanA.setName("FACEBOOK");
        deploymentChannelBeanA.setStatus(StatusEnum.ACTIVE.getName());
        deploymentChannelBeanA.setChannelId(channelA.getId());
        deploymentChannelBeanA.setChannelName(channelA.getName());
        deploymentChannelBeanA.setParameters(new ArrayList<>());

        DeploymentChannelParamValueBean deploymentChannelParamValueBeanA = new DeploymentChannelParamValueBean();
        deploymentChannelParamValueBeanA.setId(1L);
        deploymentChannelParamValueBeanA.setValue("facebook-botbyte");
        deploymentChannelParamValueBeanA.setChannelParamName(channelParamA.getName());

        deploymentChannelBeanA.getParameters().add(deploymentChannelParamValueBeanA);
        agentBeanA.getDeploymentChannels().add(deploymentChannelBeanA);

        Mockito.when(agentRepository.findById(idAgente))
                .thenReturn(Optional.ofNullable(agentBD));
        Mockito.when(countryRepository.findById(idCountry))
                .thenReturn(Optional.ofNullable(countryA));
        Mockito.when(frequentQuestionRepository.findById(idFrequentQuestion))
                .thenReturn(Optional.ofNullable(frequentQuestionA));
        Mockito.when(agentRepository.save(any(Agent.class)))
                .thenReturn(agentBD);
        Mockito.when(deploymentChannelRepository.findById(1L))
                .thenReturn(Optional.ofNullable(deploymentChannelA));
        Mockito.when(channelRepository.findById(1L))
                .thenReturn(Optional.ofNullable(channelA));
        Mockito.when(deploymentChannelParamValueRepository.findById(1L))
                .thenReturn(Optional.ofNullable(parameterA));
        Mockito.when(channelParamRepository.findByNameAndChannelId(channelParamA.getName(), channelA.getId()))
                .thenReturn(Optional.ofNullable(channelParamA));
        
        agentService.save(agentBeanA);

    }

    @Test
    public void getAgent_whenAgentNotExists_OK() {
        Long idAgente = 1L;

        Mockito.when(agentRepository.findById(idAgente))
                .thenReturn(Optional.ofNullable(null));

        AgentBean agentBean = agentService.getAgent(idAgente);

        assertThat(agentBean).isNull();
    }

    @Test
    public void getAgent_whenAgentExists_OK() {
        Long idAgente = 1L;
        Long idCountry = 1L;
        Long idFrequentQuestion = 1L;

        Agent agentA = new Agent();
        agentA.setId(idAgente);
        agentA.setName("BOT-1");
        agentA.setDescription("BOT BASICO DE PREGUNTAS");
        agentA.setVersion("0.0.1");
        agentA.setLanguage(LanguageEnum.SPANISH);
        agentA.setTimezone("GMT-5");
        agentA.setType(AgentTypeEnum.FREQUENT_QUESTION);
        agentA.setStatus(AgentStatusEnum.CREATED);
        agentA.setAvatar("avatar-png");

        Country countryA = new Country();
        countryA.setId(idCountry);
        countryA.setName("Perú");

        agentA.setCountry(countryA);

        List<FrequentQuestion> frequentQuestions = new ArrayList<>();
        FrequentQuestion frequentQuestionA = new FrequentQuestion();
        frequentQuestionA.setId(idFrequentQuestion);
        frequentQuestionA.setDescription("Preguntas de entrenamiento");
        frequentQuestionA.setUser("lortiz");
        frequentQuestionA.setFilename("preguntas-base-old.xls");
        frequentQuestionA.setUploadDate(LocalDateTime.now());
        frequentQuestionA.setStatus(FrequentQuestionStatusEnum.PENDING_SYNCHRONIZED);

        frequentQuestions.add(frequentQuestionA);

        agentA.setFrequentQuestions(frequentQuestions);

        List<DeploymentChannel> deploymentChannels = new ArrayList<>();
        DeploymentChannel deploymentChannelA = new DeploymentChannel();
        deploymentChannelA.setId(1L);
        deploymentChannelA.setName("FACEBOOK");
        deploymentChannelA.setStatus(StatusEnum.ACTIVE);

        Channel channelA = new Channel();
        channelA.setId(1L);
        channelA.setName("FACEBOOK");

        deploymentChannelA.setChannel(channelA);

        List<DeploymentChannelParamValue> parameters = new ArrayList<>();
        ChannelParam channelParamA = new ChannelParam();
        channelParamA.setName("token");

        DeploymentChannelParamValue parameterA = new DeploymentChannelParamValue();
        parameterA.setId(1L);
        parameterA.setValue("facebook-abc");
        parameterA.setParameter(channelParamA);

        DeploymentChannelParamValue parameterB = new DeploymentChannelParamValue();
        parameterB.setId(2L);
        parameterB.setValue("https://facebook....");

        parameters.add(parameterA);
        parameters.add(parameterB);

        deploymentChannelA.setParameters(parameters);

        DeploymentChannel deploymentChannelB = new DeploymentChannel();
        deploymentChannelB.setId(2L);
        deploymentChannelB.setName("WHATSAPP");
        deploymentChannelB.setStatus(StatusEnum.INACTIVE);
        deploymentChannelB.setParameters(new ArrayList<>());

        deploymentChannels.add(deploymentChannelA);
        deploymentChannels.add(deploymentChannelB);

        agentA.setDeploymentChannels(deploymentChannels);

        Mockito.when(agentRepository.findById(idAgente)).thenReturn(Optional.ofNullable(agentA));

        AgentBean agentBean = agentService.getAgent(idAgente);

        assertThat(agentBean.getId()).isEqualTo(idAgente);
    }

    @Test
    public void delete_whenAgentExists_OK() {

        Long idAgente = 1L;

        Agent agentA = new Agent();
        agentA.setId(idAgente);
        agentA.setStatus(AgentStatusEnum.PENDING_SYNCHRONIZED);

        Mockito.when(agentRepository.findById(idAgente)).thenReturn(Optional.ofNullable(agentA));
        Mockito.when(agentRepository.save(any(Agent.class))).thenReturn(agentA);

        boolean isValid = agentService.delete(idAgente);

        assertThat(isValid).isEqualTo(Boolean.TRUE);
    }

    @Test
    public void delete_whenAgentNotExists_OK() {

        Long idAgente = null;

        boolean isValid = agentService.delete(idAgente);

        assertThat(isValid).isEqualTo(Boolean.TRUE);
    }

    @Test
    public void delete_whenAgentNotExistsById_OK() {
        Long idAgente = 1L;
        Agent agentA = null;

        Mockito.when(agentRepository.findById(idAgente)).thenReturn(Optional.ofNullable(agentA));

        boolean isValid = agentService.delete(idAgente);

        assertThat(isValid).isEqualTo(Boolean.TRUE);
    }

    @Test
    public void getCountries_whenCountries_areOK() {
        List<Country> countries = new ArrayList<>();

        Country countryA = new Country();
        Country countryB = new Country();

        countries.add(countryA);
        countries.add(countryB);

        Mockito.when(countryRepository.findAll()).thenReturn(countries);

        List<CountryBean> countriesBeanList = agentService.getCountries();

        assertThat(countriesBeanList.size()).isEqualTo(2);
    }

    @Test
    public void getChannels_whenChannels_areOK() {
        List<Channel> channels = new ArrayList<>();

        Channel channelA = new Channel();
        Channel channelB = new Channel();

        channels.add(channelA);
        channels.add(channelB);

        Mockito.when(channelRepository.findAll()).thenReturn(channels);

        List<ChannelBean> channelsBeanList = agentService.getChannels();

        assertThat(channelsBeanList.size()).isEqualTo(2);
    }

    @Test
    public void synchronizeFiles_whenQuestionFileIsNotPresent_OK() {
        Long idAgente = 1L;
        String user = "lortiz";
        String uuid = "1f59cb41-778a-46f6-acfc-3625108275bb";

        List<FrequentQuestion> frequentQuestions = new ArrayList<>();

        FrequentQuestion frequentQuestionA = new FrequentQuestion();
        frequentQuestionA.setId(idAgente);
        frequentQuestionA.setUuid(uuid);

        frequentQuestions.add(frequentQuestionA);

        Agent agentA = new Agent();
        agentA.setId(idAgente);
        agentA.setStatus(AgentStatusEnum.PENDING_SYNCHRONIZED);

        Mockito.when(frequentQuestionRepository.findAllByAgentIdAndStatus(idAgente, FrequentQuestionStatusEnum.PENDING_SYNCHRONIZED))
                .thenReturn(frequentQuestions);
        Mockito.when(questionFileRepository.findByUuid(uuid))
                .thenReturn(Optional.ofNullable(null));
        Mockito.when(agentRepository.findById(idAgente))
                .thenReturn(Optional.ofNullable(agentA));

        agentService.synchronizeFiles(idAgente, user);

        //@HU como validar un void method
    }

    @Test
    public void synchronizeFiles_whenQuestionFileIsPresentButNotAgent_OK() {
        Long idAgente = 1L;
        String user = "lortiz";
        String uuid = "1f59cb41-778a-46f6-acfc-3625108275bb";

        List<FrequentQuestion> frequentQuestions = new ArrayList<>();

        FrequentQuestion frequentQuestionA = new FrequentQuestion();
        frequentQuestionA.setId(idAgente);
        frequentQuestionA.setUuid(uuid);

        frequentQuestions.add(frequentQuestionA);

        QuestionFile questionFileA = new QuestionFile();
        questionFileA.setName("preguntas-basicas-old");

        Mockito.when(frequentQuestionRepository.findAllByAgentIdAndStatus(idAgente, FrequentQuestionStatusEnum.PENDING_SYNCHRONIZED))
                .thenReturn(frequentQuestions);
        Mockito.when(questionFileRepository.findByUuid(uuid))
                .thenReturn(Optional.ofNullable(questionFileA));
        Mockito.when(agentRepository.findById(idAgente))
                .thenReturn(Optional.ofNullable(null));

        agentService.synchronizeFiles(idAgente, user);

        //@HU como validar un void method
    }
}
