package ru.yandex.autotests.directintapi.bstransport.main.banner.parameters.mobile;

import java.util.Arrays;

import org.junit.Before;
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.db.models.jooq.ppc.enums.MobileAppsStoreType;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.MobileAppsRecord;
import ru.yandex.autotests.direct.db.steps.DirectJooqDbSteps;
import ru.yandex.autotests.direct.utils.tags.TagDictionary;
import ru.yandex.autotests.directapi.darkside.Logins;
import ru.yandex.autotests.directapi.darkside.connection.Semaphore;
import ru.yandex.autotests.directapi.darkside.model.RunBsTransportScriptResponse;
import ru.yandex.autotests.directapi.darkside.model.bslogs.clientdata.Banner;
import ru.yandex.autotests.directapi.darkside.model.bslogs.clientdata.Campaign;
import ru.yandex.autotests.directapi.darkside.model.bslogs.clientdata.Context;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.autotests.directapi.rules.Trashman;
import ru.yandex.autotests.directintapi.bstransport.FeatureNames;
import ru.yandex.autotests.directintapi.bstransport.MobileContentCleanupRule;
import ru.yandex.autotests.directintapi.bstransport.StoriesNames;
import ru.yandex.qatools.Tag;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
import ru.yandex.qatools.allure.annotations.Title;
import ru.yandex.qatools.hazelcast.SemaphoreRule;

import static java.util.Collections.singletonList;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static ru.yandex.autotests.directapi.darkside.model.MobileContentUtils.getDefaultMobileContent;
import static ru.yandex.autotests.directapi.model.User.get;
import static ru.yandex.autotests.directintapi.bstransport.TransportTestUtils.getDefaultAdgroupsMobileContent;
import static ru.yandex.autotests.directintapi.bstransport.TransportTestUtils.getDefaultBannersMobileContent;
import static ru.yandex.autotests.directintapi.bstransport.TransportTestUtils.getDefaultCampaignsMobileContent;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assumeThat;

@Aqua.Test
@Tag(TagDictionary.TRUNK)
@Tag(TagDictionary.RELEASE)
@Title("Транспорт: баннеры с типом mobile_content, учитывая приложения в mobile_apps, поле DomainFilter")
@Stories(StoriesNames.BANNER_PARAMS_MOBILE_CONTENT)
@Features(FeatureNames.BANNERS)
@RunWith(Parameterized.class)
public class BsTransportOfMobileNewRmpDomainFilterTest {
    private static final String LOGIN = Logins.LOGIN_TRANSPORT;
    private static final String BUNDLE_ID = "ru.yandex.autotests.bundle";
    private static final Domain MOBILE_CONTENT_DOMAIN = new Domain(29170L, "www.yandex.ru");
    private static final Domain MOBILE_APP_DOMAIN = new Domain(915343L, "momondo.ru");
    private static final Domain GLUED_DOMAIN = new Domain(219099L, "vk.com");
    public static final String STORE_PREFIX = "ITunes_";

    @ClassRule
    public static ApiSteps api = new ApiSteps().as(LOGIN);
    @ClassRule
    public static SemaphoreRule semaphore = Semaphore.getSemaphore();
    @Rule
    public Trashman trasher = new Trashman(api);
    @Rule
    public MobileContentCleanupRule cleanupRule = new MobileContentCleanupRule(api);

    @Parameterized.Parameter()
    public String description;

    @Parameterized.Parameter(1)
    public Boolean hasMobileAppRelatedToUsedMobileContent;

    @Parameterized.Parameter(2)
    public Boolean mobileAppHasAnotherMobileContentId;

    @Parameterized.Parameter(3)
    public Long mobileAppDomainId;

    @Parameterized.Parameter(4)
    public String expectedDomainFilter;

    private static Banner banner;

    @Parameterized.Parameters(name = "{0}")
    public static Iterable<Object[]> data() {
        return Arrays.asList(
                new TestCase()
                        .withDescription("Без указанного в кампании мобильного приложения")
                        .withHasMobileAppRelatedToUsedMobileContent(false)
                        .withExpectedDomainFilter(MOBILE_CONTENT_DOMAIN.name)
                        .asArray(),
                new TestCase()
                        .withDescription("С указанным в кампании мобильным приложением. "
                                + "Мобильное приложение без указанного домена")
                        .withHasMobileAppRelatedToUsedMobileContent(true)
                        .withMobileAppDomainId(null)
                        .withExpectedDomainFilter(MOBILE_CONTENT_DOMAIN.name)
                        .asArray(),
                new TestCase()
                        // этот случай может возникнуть в результате миграции старых кампаний,
                        // в которых могли рекламироваться несколько приложений
                        .withDescription("С указанным в кампании мобильным приложением. "
                                + "Мобильное приложение mobile_content_id, отличающимся от указанного в группе, "
                                + "и с доменом, отличающимся от publisher_domain в mobile_content")
                        .withHasMobileAppRelatedToUsedMobileContent(true)
                        .withMobileAppHasAnotherMobileContentId(true)
                        .withMobileAppDomainId(MOBILE_APP_DOMAIN.id)
                        .withExpectedDomainFilter(MOBILE_CONTENT_DOMAIN.name)
                        .asArray(),
                new TestCase()
                        .withDescription("С указанным в кампании мобильным приложением. "
                                + "Мобильное приложение с доменом, отличающимся от publisher_domain в mobile_content")
                        .withHasMobileAppRelatedToUsedMobileContent(true)
                        .withMobileAppDomainId(MOBILE_APP_DOMAIN.id)
                        .withExpectedDomainFilter(MOBILE_APP_DOMAIN.name)
                        .asArray(),
                new TestCase()
                        .withDescription("С указанным в кампании мобильным приложением. "
                                + "Мобильное приложение с доменом, отличающимся от publisher_domain в mobile_content "
                                + "и совпадающим с общеупотребимым доменом")
                        .withHasMobileAppRelatedToUsedMobileContent(true)
                        .withMobileAppDomainId(GLUED_DOMAIN.id)
                        .withExpectedDomainFilter(STORE_PREFIX.toLowerCase() + BUNDLE_ID)
                        .asArray()
        );
    }

    @Before
    public void before() {
        int shard = api.userSteps.clientFakeSteps().getUserShard(LOGIN);
        DirectJooqDbSteps jooqSteps = api.userSteps.getDirectJooqDbSteps().useShard(shard);

        Long clientId = Long.valueOf(get(LOGIN).getClientID());

        Long mobileContentId = jooqSteps.mobileContentSteps()
                .saveMobileContent(getDefaultMobileContent(clientId.toString())
                        .setBundleId(BUNDLE_ID)
                        .setPublisherDomainId(MOBILE_CONTENT_DOMAIN.id));

        Long cid = api.userSteps.campaignSteps().addDefaultMobileAppCampaign();
        Long pid = api.userSteps.adGroupsSteps().addDefaultMobileGroup(cid);
        Long bid = api.userSteps.adsSteps().addDefaultMobileAppAd(pid);
        long keywordId = api.userSteps.keywordsSteps().addDefaultKeyword(pid);

        cleanupRule.setMobileContentIds(singletonList(mobileContentId));
        cleanupRule.setPids(singletonList(pid));
        cleanupRule.setShard(shard);

        if (hasMobileAppRelatedToUsedMobileContent) {
            MobileAppsRecord mobileApp = getDefaultMobileAppsRecord(clientId, mobileContentId)
                    .setDomainId(mobileAppDomainId);
            if (mobileAppHasAnotherMobileContentId) {
                mobileApp.setMobileContentId(mobileContentId + 1000L);
            }
            Long mobileAppId = jooqSteps.mobileAppsSteps().createMobileApp(mobileApp);
            jooqSteps.campaignsSteps().setCampaignMobileAppId(cid, mobileAppId);
            cleanupRule.setMobileAppIdsToDeleteAfterTest(clientId, singletonList(mobileAppId));
        }

        api.userSteps.campaignFakeSteps().makeNewCampaignReadyForSendingToBS(cid);
        api.userSteps.groupFakeSteps().makeGroupFullyModerated(pid);
        api.userSteps.bannersFakeSteps().makeBannerFullyModerated(bid);
        api.userSteps.phrasesFakeSteps().makeKeywordModerated(keywordId);

        jooqSteps.mobileContentSteps()
                .updateCampaignsMobileContent(getDefaultCampaignsMobileContent(cid));
        jooqSteps.mobileContentSteps()
                .updateAdgroupsMobileContent(getDefaultAdgroupsMobileContent(pid, mobileContentId));
        jooqSteps.mobileContentSteps()
                .updateBannersMobileContent(getDefaultBannersMobileContent(bid));

        RunBsTransportScriptResponse resp =
                api.userSteps.getDarkSideSteps().getTransportSteps().sendNewCampaign(shard, cid);
        Campaign campaign =
                api.userSteps.getDarkSideSteps().getTransportSteps().getClientDataRequestCampaign(resp, cid);
        assumeThat("кампания отправляется в БК", campaign, notNullValue());

        Context context = campaign.getContext(pid);
        assumeThat("в кампании присутствует Context", context, notNullValue());

        banner = context.getBanner(bid);

        assumeThat("в контексте присутствует Banner", banner, notNullValue());
    }

    @Test
    public void testTransportOfBannerMobileContentAction() {
        assertThat("при отправке баннера с типом mobile_content отправляется правильное значение DomainFilter",
                banner.getDomainFilter(), equalTo(expectedDomainFilter));
    }

    private MobileAppsRecord getDefaultMobileAppsRecord(Long clientId, Long mobileContentId) {
        return new MobileAppsRecord()
                .setClientid(clientId)
                .setStoreType(MobileAppsStoreType.GooglePlayStore)
                .setStoreHref("http://play.google.com/store/apps/details?id=ru.yandex.searchplugin")
                .setName("some app")
                .setMobileContentId(mobileContentId);
    }

    private static class TestCase {
        private String description;

        private boolean hasMobileAppRelatedToUsedMobileContent;

        private boolean mobileAppHasAnotherMobileContentId;

        private Long mobileAppDomainId;

        private String expectedDomainFilter;

        private TestCase withDescription(final String description) {
            this.description = description;
            return this;
        }

        public TestCase withMobileAppHasAnotherMobileContentId(boolean mobileAppHasAnotherMobileContentId) {
            this.mobileAppHasAnotherMobileContentId = mobileAppHasAnotherMobileContentId;
            return this;
        }

        private TestCase withHasMobileAppRelatedToUsedMobileContent(boolean hasMobileAppRelatedToUsedMobileContent) {
            this.hasMobileAppRelatedToUsedMobileContent = hasMobileAppRelatedToUsedMobileContent;
            return this;
        }

        private TestCase withMobileAppDomainId(Long mobileAppDomainId) {
            this.mobileAppDomainId = mobileAppDomainId;
            return this;
        }

        private TestCase withExpectedDomainFilter(String expectedDomainFilter) {
            this.expectedDomainFilter = expectedDomainFilter;
            return this;
        }

        Object[] asArray() {
            return new Object[]{description, hasMobileAppRelatedToUsedMobileContent, mobileAppHasAnotherMobileContentId,
                    mobileAppDomainId, expectedDomainFilter};
        }

    }

    private static class Domain {
        private final Long id;
        private final String name;

        private Domain(Long id, String name) {
            this.id = id;
            this.name = name;
        }
    }
}
