package ru.yandex.autotests.directapi.steps.banners;

import java.util.Arrays;
import java.util.List;

import com.yandex.direct.api.v5.general.ActionResult;
import com.yandex.direct.api.v5.vcards.AddResponse;
import com.yandex.direct.api.v5.vcards.DeleteResponse;
import com.yandex.direct.api.v5.vcards.GetResponse;
import com.yandex.direct.api.v5.vcards.VCardFieldEnum;
import com.yandex.direct.api.v5.vcards.VCardGetItem;
import org.apache.commons.beanutils.BeanMap;

import ru.yandex.autotests.directapi.apiclient.RequestHeader;
import ru.yandex.autotests.directapi.apiclient.config.ConnectionConfig;
import ru.yandex.autotests.directapi.apiclient.errors.Api5Error;
import ru.yandex.autotests.directapi.apiclient.version5.ServiceNames;
import ru.yandex.autotests.directapi.model.api5.Action;
import ru.yandex.autotests.directapi.model.api5.general.ExpectedResult;
import ru.yandex.autotests.directapi.model.api5.general.IdsCriteriaMap;
import ru.yandex.autotests.directapi.model.api5.general.LimitOffsetMap;
import ru.yandex.autotests.directapi.model.api5.vcards.AddRequestMap;
import ru.yandex.autotests.directapi.model.api5.vcards.DeleteRequestMap;
import ru.yandex.autotests.directapi.model.api5.vcards.GetRequestMap;
import ru.yandex.autotests.directapi.model.api5.vcards.VCardAddMap;
import ru.yandex.autotests.directapi.steps.BaseApiSteps;
import ru.yandex.autotests.irt.testutils.allure.LogSteps;
import ru.yandex.qatools.allure.annotations.Step;

import static ch.lambdaj.Lambda.extract;
import static ch.lambdaj.Lambda.having;
import static ch.lambdaj.Lambda.on;
import static ch.lambdaj.Lambda.select;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assumeThat;

/**
 * Created by chicos on 28.05.14.
 */
public class VCardsSteps extends BaseApiSteps {
    private LogSteps log = LogSteps.getLogger(this.getClass());

    private static VCardsSteps _instance;

    private VCardsSteps(ConnectionConfig connectionConfig, RequestHeader requestHeader) {
        super(connectionConfig, requestHeader);
    }

    public static VCardsSteps getInstance(ConnectionConfig connectionConfig, RequestHeader requestHeader) {
        if (_instance == null) {
            _instance = new VCardsSteps(connectionConfig, requestHeader);
        } else {
            _instance.setConnectionConfig(connectionConfig);
            _instance.setRequestHeader(requestHeader);
        }
        return _instance;
    }

    @Step("[VCards]: Add")
    public List<Long> vCardsAdd(String login, AddRequestMap request) {
        List<ActionResult> results = ((AddResponse) defaultClientV5()
                .invokeMethod(ServiceNames.VCARDS, login, Action.ADD, request.getBean())).getAddResults();
        lookForResponseExceptions(results);
        return getIDsFromActionResults(results);
    }

    public List<Long> vCardsAdd(String login, VCardAddMap... vcards) {
        AddRequestMap request = new AddRequestMap().withVCards(vcards);
        return vCardsAdd(login, request);
    }

    public List<Long> vCardsAdd(VCardAddMap... vcards) {
        return vCardsAdd(null, vcards);
    }

    public Long addDefaultVCard(Long campaignId) {
        return addDefaultVCard(null, campaignId);
    }

    public Long addDefaultVCard(String login, Long campaignId) {
        List<Long> vCardsIDs = vCardsAdd(login, new VCardAddMap()
                .defaultContacts().withCampaignId(campaignId));
        assumeThat("добавилась одна визитная карточка", vCardsIDs, hasSize(1));
        return vCardsIDs.get(0);
    }

    public List<VCardGetItem> vCardsGet(String login, List<VCardFieldEnum> fields, LimitOffsetMap limitOffset,
            Long... vCardId)
    {
        VCardFieldEnum[] fieldsArray = new VCardFieldEnum[fields.size()];
        GetRequestMap request = new GetRequestMap()
                .withSelectionCriteria(getIdsCriteria(vCardId))
                .withFieldNames(fields.toArray(fieldsArray))
                .withPage(limitOffset);
        return vCardsGet(login, request);
    }

    @Step("[VCards]: Get")
    public GetResponse get(String login, GetRequestMap request) {
        GetResponse response =
                defaultClientV5().invokeMethod(ServiceNames.VCARDS, login, Action.GET, request.getBean());
        return response;
    }

    public GetResponse get(GetRequestMap request) {
        return get(null, request);
    }

    public List<VCardGetItem> vCardsGet(String login, GetRequestMap request) {
        List<VCardGetItem> results = get(login, request).getVCards();
        return results;
    }

    public List<VCardGetItem> vCardsGet(GetRequestMap request) {
        return vCardsGet(null, request);
    }

    public List<VCardGetItem> vCardsGet(Long... vCardId) {
        return vCardsGet(null, Arrays.asList(VCardFieldEnum.class.getEnumConstants()), null, vCardId);
    }

    public List<VCardGetItem> vCardsGet(String login, Long... vCardId) {
        return vCardsGet(login, Arrays.asList(VCardFieldEnum.class.getEnumConstants()), null, vCardId);
    }

    public List<VCardGetItem> vCardsGet(List<VCardFieldEnum> fields, Long... vCardId) {
        return vCardsGet(null, fields, null, vCardId);
    }

    public List<VCardGetItem> vCardsGet(String login, List<VCardFieldEnum> fields, Long... vCardId) {
        return vCardsGet(login, fields, null, vCardId);
    }

    public List<VCardGetItem> vCardsGet(LimitOffsetMap limitOffset, Long... vCardId) {
        return vCardsGet(null, Arrays.asList(VCardFieldEnum.class.getEnumConstants()), limitOffset, vCardId);
    }

    public List<VCardGetItem> vCardsGet(String login, LimitOffsetMap limitOffset, Long... vCardId) {
        return vCardsGet(login, Arrays.asList(VCardFieldEnum.class.getEnumConstants()), limitOffset, vCardId);
    }

    @Step("[VCards]: Delete")
    public List<Long> vCardsDelete(String login, Long... vCardId) {
        DeleteRequestMap request = new DeleteRequestMap()
                .withSelectionCriteria(getIdsCriteria(vCardId));
        List<ActionResult> results = ((DeleteResponse) defaultClientV5()
                .invokeMethod(ServiceNames.VCARDS, login, Action.DELETE, request.getBean())).getDeleteResults();
        lookForResponseExceptions(results);
        return getIDsFromActionResults(results);
    }

    public List<Long> vCardsDelete(Long... vCardId) {
        return vCardsDelete(null, vCardId);
    }

    private void lookForResponseExceptions(List<ActionResult> results) {
        List<ActionResult> errors = select(results, having(on(ActionResult.class).getErrors(), is(not(empty()))));
        List<ActionResult> warnings = select(results, having(on(ActionResult.class).getWarnings(), is(not(empty()))));

        assertThat("Есть ошибки при вызове метода", errors, is(empty()));
        assertThat("Есть предупреждения при вызове метода", warnings, is(empty()));
    }

    private IdsCriteriaMap getIdsCriteria(Long... ids) {
        IdsCriteriaMap criteria = new IdsCriteriaMap();
        criteria.withIds(ids);
        return criteria;
    }

    private List<Long> getIDsFromActionResults(List<ActionResult> results) {
        return extract(results, on(ActionResult.class).getId());
    }

    public <T extends BeanMap> void shouldGetVCardErrorOn(Action action, T request, Api5Error api5Error) {
        shouldGetErrorOn("", ServiceNames.VCARDS, null, action, request, api5Error);
    }

    public <T extends BeanMap> void shouldGetVCardErrorWithErrorCodeOn(Action action, T request,
            Integer expectedErrorCode)
    {
        shouldGetErrorWithCodeOn("", ServiceNames.VCARDS, null, action, request, expectedErrorCode);
    }

    public <T extends BeanMap> void shouldGetVCardErrorWithErrorCodeOn(Action action, String login, T request,
            Integer expectedErrorCode)
    {
        shouldGetErrorWithCodeOn("", ServiceNames.VCARDS, login, action, request, expectedErrorCode);
    }

    public <T extends BeanMap> void shouldGetVCardErrorOn(String message, Action action, T request,
            Api5Error api5Error)
    {
        shouldGetErrorOn(message, ServiceNames.VCARDS, null, action, request, api5Error);
    }

    public <T extends BeanMap> void shouldGetVCardErrorOn(Action action, String login, T request, Api5Error api5Error) {
        shouldGetErrorOn("", ServiceNames.VCARDS, login, action, request, api5Error);
    }

    public <T> void shouldGetVCardErrorJsonOn(Action action, T request, Api5Error api5Error) {
        shouldGetJSONErrorOn(ServiceNames.VCARDS, null, action, request, api5Error);
    }

    public <T> void shouldGetVCardErrorJsonOn(Action action, String login, T request, Api5Error api5Error) {
        shouldGetJSONErrorOn(ServiceNames.VCARDS, login, action, request, api5Error);
    }

    public <T extends BeanMap> void shouldGetResultOn(Action action,
            String login,
            T args,
            ExpectedResult... expectedResults)
    {
        shouldGetResultOn(ServiceNames.VCARDS, login, action, args, expectedResults);
    }

    public <T extends BeanMap> void shouldGetResultOn(Action action,
            T args,
            ExpectedResult... expectedResults)
    {
        shouldGetResultOn(ServiceNames.VCARDS, null, action, args, expectedResults);
    }

    public <T> void shouldGetResultOnJson(Action action,
            String login,
            T args,
            ExpectedResult... expectedResults)
    {
        shouldGetResultOnJson(ServiceNames.VCARDS, login, action, args, expectedResults);
    }
}
