package ru.yandex.autotests.directapi.agencyclients.get;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import com.yandex.direct.api.v5.agencyclients.AgencyClientFieldEnum;
import com.yandex.direct.api.v5.agencyclients.GetResponse;
import com.yandex.direct.api.v5.generalclients.ClientGetItem;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;

import ru.yandex.aqua.annotations.project.Aqua;
import ru.yandex.autotests.directapi.agencyclients.AgencyClientsFeatures;
import ru.yandex.autotests.directapi.agencyclients.AgencyClientsLogins;
import ru.yandex.autotests.directapi.apiclient.errors.Api5Error;
import ru.yandex.autotests.directapi.apiclient.errors.Api5ErrorDetailsJava;
import ru.yandex.autotests.directapi.darkside.connection.Semaphore;
import ru.yandex.autotests.directapi.model.api5.agencyclients.AgencyClientsSelectionCriteriaMap;
import ru.yandex.autotests.directapi.model.api5.agencyclients.GetRequestMap;
import ru.yandex.autotests.directapi.model.api5.generalclients.ClientGetItemMap;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Step;
import ru.yandex.qatools.hazelcast.SemaphoreRule;

import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasItems;
import static ru.yandex.autotests.directapi.apiclient.errors.Path.path;
import static ru.yandex.autotests.directapi.matchers.beandiffer2.BeanDifferMatcherV5.beanDifferV5;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;

@Aqua.Test
@Features(AgencyClientsFeatures.GET)
@Description("Проверка SelectionCriteria.Logins")
public class GetSelectionCriteriaLoginsTest {
    private static final String AGENCY_LOGIN = AgencyClientsLogins.AGENCY_RUB;
    private static final String SUBCLIENT_LOGIN = AgencyClientsLogins.AGENCY_RUB_SUBCLIENT;

    @ClassRule
    public static ApiSteps api = new ApiSteps().as(AGENCY_LOGIN);

    @ClassRule
    public static SemaphoreRule semaphore = Semaphore.getSemaphore();

    @Before
    @Step("Подготовка тестовых данных")
    public void prepare() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(AGENCY_LOGIN);
    }

    @Test
    public void getSelectionCriteriaWithoutLoginsTest() {
        List<String> expectedLogins = Arrays.asList(
                AgencyClientsLogins.AGENCY_RUB_SUBCLIENT,
                AgencyClientsLogins.AGENCY_RUB_SUBCLIENT1,
                AgencyClientsLogins.AGENCY_RUB_SUBCLIENT2_WITH_PHONE,
                AgencyClientsLogins.AGENCY_RUB_SUBCLIENT_ARCHIVED,
                AgencyClientsLogins.AGENCY_RUB_SUBCLIENT1_WITH_FREEDOM,
                AgencyClientsLogins.TWO_AGENCIES_SUBCLIENT,
                AgencyClientsLogins.AGENCY_RUB_SUBCLIENT3_NOTIFICATIONS
        );

        GetResponse getResponse = api.userSteps.agencyClientsStepsV5().agencyClientsGet(
                new GetRequestMap().withSelectionCriteria(new AgencyClientsSelectionCriteriaMap())
                        .withFieldNames(AgencyClientFieldEnum.LOGIN));

        List<String> returnedLogins = getResponse.getClients().stream()
                .map(ClientGetItem::getLogin)
                .collect(Collectors.toList());

        assertThat("полученные значения совпадают с ожидаемыми",
                returnedLogins, hasItems((String[]) expectedLogins.toArray()));
    }

    @Test
    public void getSelectionCriteriaWithLoginsTest() {
        List<Object> expectedResult = Arrays.asList(
                new ClientGetItemMap()
                        .withLogin(AgencyClientsLogins.AGENCY_RUB_SUBCLIENT)
                        .getBean(),
                new ClientGetItemMap()
                        .withLogin(AgencyClientsLogins.AGENCY_RUB_SUBCLIENT_ARCHIVED)
                        .getBean());

        expectedResult.sort(Comparator.comparing(e -> ((ClientGetItem) e).getLogin()));

        GetResponse getResponse = api.userSteps.agencyClientsStepsV5().agencyClientsGet(new GetRequestMap()
                .withSelectionCriteria(new AgencyClientsSelectionCriteriaMap()
                        .withLogins(AgencyClientsLogins.AGENCY_RUB_SUBCLIENT,
                                AgencyClientsLogins.AGENCY_RUB_SUBCLIENT_ARCHIVED))
                .withFieldNames(AgencyClientFieldEnum.LOGIN));

        List<ClientGetItem> actualResult = getResponse.getClients();

        actualResult.sort(Comparator.comparing(ClientGetItem::getLogin));

        assertThat("полученные значения совпадают с ожидаемыми", actualResult, beanDifferV5(expectedResult));
    }


    @Test
    public void getSelectionCriteriaWithRepsLoginsTest() {
        List<Object> expectedResult = Arrays.asList(
                new ClientGetItemMap()
                        .withLogin(AgencyClientsLogins.AGENCY_RUB_SUBCLIENT)
                        .getBean());

        expectedResult.sort(Comparator.comparing(e -> ((ClientGetItem) e).getLogin()));

        GetResponse getResponse = api.userSteps.agencyClientsStepsV5().agencyClientsGet(new GetRequestMap()
                .withSelectionCriteria(new AgencyClientsSelectionCriteriaMap()
                        .withLogins(AgencyClientsLogins.AGENCY_RUB_SUBCLIENT_REP,
                                AgencyClientsLogins.AGENCY_RUB_SUBCLIENT_REP1))
                .withFieldNames(AgencyClientFieldEnum.LOGIN));

        List<ClientGetItem> actualResult = getResponse.getClients();

        actualResult.sort(Comparator.comparing(ClientGetItem::getLogin));

        assertThat("полученные значения совпадают с ожидаемыми", actualResult, beanDifferV5(expectedResult));
    }


    @Test
    public void getSelectionCriteriaWithDuplicateLoginsTest() {
        List<Object> expectedResult = Collections.singletonList(
                new ClientGetItemMap()
                        .withLogin(AgencyClientsLogins.AGENCY_RUB_SUBCLIENT)
                        .getBean());

        expectedResult.sort(Comparator.comparing(e -> ((ClientGetItem) e).getLogin()));

        GetResponse getResponse = api.userSteps.agencyClientsStepsV5().agencyClientsGet(new GetRequestMap()
                .withSelectionCriteria(new AgencyClientsSelectionCriteriaMap()
                        .withLogins(AgencyClientsLogins.AGENCY_RUB_SUBCLIENT,
                                AgencyClientsLogins.AGENCY_RUB_SUBCLIENT))
                .withFieldNames(AgencyClientFieldEnum.LOGIN));

        List<ClientGetItem> actualResult = getResponse.getClients();

        assertThat("полученные значения совпадают с ожидаемыми", actualResult, beanDifferV5(expectedResult));
    }

    @Test
    public void getSelectionCriteriaWithNotExistLoginsTest() {
        GetResponse getResponse = api.userSteps.agencyClientsStepsV5().agencyClientsGet(new GetRequestMap()
                .withSelectionCriteria(new AgencyClientsSelectionCriteriaMap().withLogins("not_exists_login"))
                .withFieldNames(AgencyClientFieldEnum.LOGIN));

        assertThat("субклиенты на найдены", getResponse.getClients(), empty());
    }

    @Test
    public void getSelectionCriteriaWithEmptyLoginTest() {
        GetResponse getResponse = api.userSteps.agencyClientsStepsV5().agencyClientsGet(new GetRequestMap()
                .withSelectionCriteria(new AgencyClientsSelectionCriteriaMap().withLogins(""))
                .withFieldNames(AgencyClientFieldEnum.LOGIN));

        assertThat("субклиенты на найдены", getResponse.getClients(), empty());
    }

    @Test
    public void getSelectionCriteriaToMuchLoginsErrorNegativeTest() {
        String[] logins = new String[AgencyClientsSelectionCriteriaMap.LOGINS_MAX_SIZE + 1];
        Arrays.fill(logins, SUBCLIENT_LOGIN);

        api.userSteps.agencyClientsStepsV5().expectErrorOnAgencyClientsGet(
                new GetRequestMap()
                        .withSelectionCriteria(new AgencyClientsSelectionCriteriaMap().withLogins(logins))
                        .withFieldNames(AgencyClientFieldEnum.LOGIN),
                new Api5Error(4001,
                        Api5ErrorDetailsJava.ARRAY_CANNOT_CONTAIN_MORE_THAN,
                        path(GetRequestMap.SELECTION_CRITERIA, AgencyClientsSelectionCriteriaMap.LOGINS),
                        AgencyClientsSelectionCriteriaMap.LOGINS_MAX_SIZE));
    }
}
