package ru.yandex.autotests.direct.api.audiencetargets.units;

import java.util.Collection;
import java.util.function.Function;
import java.util.function.Supplier;

import javax.util.streamex.StreamEx;

import com.yandex.direct.api.v5.audiencetargets.ApiException;
import com.yandex.direct.api.v5.audiencetargets.AudienceTargetFieldEnum;
import com.yandex.direct.api.v5.audiencetargets.AudienceTargetsPort;
import com.yandex.direct.api.v5.audiencetargets.GetRequest;
import com.yandex.direct.api.v5.audiencetargets.GetResponse;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import ru.yandex.aqua.annotations.project.Aqua;
import ru.yandex.autotests.direct.utils.tags.TagDictionary;
import ru.yandex.autotests.directapi.ApiFeatures;
import ru.yandex.autotests.directapi.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.model.api5.audiencetargets.AudienceTargetSelectionCriteriaMap;
import ru.yandex.autotests.directapi.model.api5.audiencetargets.GetRequestMap;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.autotests.directapi.rules.Trashman;
import ru.yandex.autotests.directapi.test.units.UnitsUsedLoginHeaderTester;
import ru.yandex.autotests.directapi.test.units.UnitsUsedLoginTestDataProvider;
import ru.yandex.qatools.Tag;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Issue;
import ru.yandex.qatools.hazelcast.SemaphoreRule;

import static org.hamcrest.Matchers.empty;
import static org.junit.runners.Parameterized.Parameter;
import static org.junit.runners.Parameterized.Parameters;
import static ru.yandex.autotests.directapi.test.units.UnitsHeaderUtil.getUnitsUsedLoginHeader;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assumeThat;

@Aqua.Test
@Issue("https://st.yandex-team.ru/TESTIRT-11526")
@Features(ApiFeatures.UNITS)
@Description("Проверка заголовка Units-Used-Login: AudienceTargets")
@Tag(TagDictionary.TRUNK)
@RunWith(Parameterized.class)
public class UnitsHeaderAudienceTargetsTest {

    @ClassRule
    public static ApiSteps api = new ApiSteps();

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

    @Rule
    public Trashman trasher = new Trashman(api);

    private static UnitsUsedLoginHeaderTester tester = UnitsUsedLoginHeaderTester.newInstance(api);

    @Parameter()
    public String description;
    @Parameter(1)
    public String operatorLogin;
    @Parameter(2)
    public String clientLogin;
    @Parameter(3)
    public String useOperatorUnits;
    @Parameter(4)
    public String unitsUsedLogin;
    @Parameter(5)
    public Collection<String> clientsWithoutUnits;
    @Parameter(6)
    public int unitsDelta;
    @Parameter(7)
    public Collection<String> expectedUnitsWithdrawLogins;
    @Parameter(8)
    public Collection<String> expectedUnitsKeepLogins;
    @Parameter(9)
    public Function<String, String> serviceCall;

    @Parameters(name = "{0}; Operator: {1}; Client-Login: {2}; Use-Operator-Units: {3}")
    public static Iterable<Object[]> params() {
        return UnitsUsedLoginTestDataProvider.buildDataSets(

                getUnitsUsedLoginHeader((String clientLogin) -> {
                    AudienceTargetsPort port = api.userSteps.soapClientV5().audienceTargetsService(clientLogin);
                    try {
                        GetResponse response = port.get((GetRequest) new GetRequestMap()
                                .withFieldNames(AudienceTargetFieldEnum.ID)
                                .withSelectionCriteria(
                                        new AudienceTargetSelectionCriteriaMap().withIds(0L)).getBean());
                        assumeThat("Получен пустой ответ", response.getAudienceTargets(), empty());
                    } catch (ApiException ignore) {
                        // игнорируем ошибку, чтобы можно было достать заголовки из ошибочного запроса
                    }
                    return port;
                })
        );
    }

    @BeforeClass
    public static void init() {
        tester.init();
    }

    @Before
    public void before() {
        tester.reset(clientsWithoutUnits, expectedUnitsWithdrawLogins);
    }

    @Test
    public void testHeader() {
        Supplier<String> serviceCallReturningHeaderValue = () -> serviceCall.apply(clientLogin);

        tester.test(serviceCallReturningHeaderValue, operatorLogin, clientLogin, useOperatorUnits, unitsUsedLogin);
    }

    @After
    public void after() {
        StreamEx.of(clientsWithoutUnits).forEach(client ->
                api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(client));
    }

    @AfterClass
    public static void shutdown() {
        tester.shutdown();
    }
}
