package ru.yandex.autotests.directintapi.bstransport.main.internalads;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;

import ru.yandex.aqua.annotations.project.Aqua;
import ru.yandex.autotests.direct.cmd.rules.CampaignRule;
import ru.yandex.autotests.direct.cmd.rules.DirectCmdRule;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.BannersStatusbssynced;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsAutobudget;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsInternalRfCloseByClick;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsStatusbssynced;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.CampaignsInternalRecord;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.CampaignsRecord;
import ru.yandex.autotests.direct.db.steps.DirectJooqDbSteps;
import ru.yandex.autotests.direct.httpclient.TestEnvironment;
import ru.yandex.autotests.direct.utils.campaigns.CampaignTypeEnum;
import ru.yandex.autotests.direct.utils.money.Currency;
import ru.yandex.autotests.direct.utils.money.Money;
import ru.yandex.autotests.direct.utils.tags.TagDictionary;
import ru.yandex.autotests.directapi.darkside.model.bslogs.UpdateInfo;
import ru.yandex.autotests.directapi.darkside.model.bslogs.clientdata.Campaign;
import ru.yandex.autotests.directintapi.bstransport.FeatureNames;
import ru.yandex.autotests.directintapi.bstransport.TransportHelpSteps;
import ru.yandex.autotests.irt.testutils.RandomUtils;
import ru.yandex.autotests.irt.testutils.beandiffer2.comparestrategy.defaultcomparestrategy.DefaultCompareStrategies;
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.allure.annotations.Step;

import static org.hamcrest.Matchers.notNullValue;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assumeThat;
import static ru.yandex.autotests.irt.testutils.beandiffer2.BeanDifferMatcher.beanDiffer;


@Aqua.Test
@Tag(TagDictionary.RELEASE)
@Tag(TagDictionary.TRUNK)
@Description("Проверяем первую отправку кампаний с внутренней рекламой (internal_autobudget)")
@Features(FeatureNames.INTERNAL_ADS)
@Issue("https://st.yandex-team.ru/DIRECT-118152")
public class InternalAutobudgetCampaignTest extends InternalAdsBaseTest {

    @ClassRule
    public static DirectCmdRule defaultClassRule = DirectCmdRule.defaultClassRule();

    public CampaignRule campaignRule = new CampaignRule()
            .withMediaType(CampaignTypeEnum.INTERNAL_AUTOBUDGET)
            .withUlogin(LOGIN);

    @Rule
    public DirectCmdRule cmdRule = DirectCmdRule.defaultRule().withRules(campaignRule);

    @BeforeClass
    public static void beforeClass() {
        shard = api.userSteps.getDarkSideSteps().getClientFakeSteps().getUserShard(LOGIN);
        dbSteps = TestEnvironment.newDbSteps().useShard(shard);
        transportHelpSteps = new TransportHelpSteps(api).useDbJooqSteps(dbSteps);
    }

    @Before
    @Step("Подготовка тестовых данных")
    public void init() {
        cid = campaignRule.getCampaignId();
        api.userSteps.campaignFakeSteps().makeCampaignInternalReadyForSendingToBS(cid);
        api.userSteps.campaignFakeSteps().makeNewCampaignReadyForSendingToBS(cid);
    }

    @Test
    public void createInternalAutobudgetCampaign_commonCheck() {
        TransportHelpSteps helpSteps = new TransportHelpSteps(api);
        Campaign expectedCampaign = helpSteps.buildExpectedCampaignObjFromDb(cid, shard, UpdateInfo.UPDATE);
        fillInStrategy(cid, expectedCampaign);

        Campaign campaign = sendNewCampaign();
        assumeThat("в БК отправлена кампания", campaign, notNullValue());
        assertThat("Значение параметров кампании соответствует ожидаениям",
                campaign,
                helpSteps.campaignReq1Matcher(expectedCampaign));
    }

    @Test
    public void createInternalAutobudgetCampaign_checkEmptyPageIds() {
        dbSteps.campaignsInternalSteps().setPageIds(cid, "");
        TransportHelpSteps helpSteps = new TransportHelpSteps(api);
        Campaign expectedCampaign = helpSteps.buildExpectedCampaignObjFromDb(cid, shard, UpdateInfo.UPDATE);
        expectedCampaign.setPageIds(Collections.emptyList());
        fillInStrategy(cid, expectedCampaign);

        Campaign campaign = sendNewCampaign();
        assumeThat("в БК отправлена кампания", campaign, notNullValue());
        assertThat("Значение параметров кампании соответствует ожидаениям",
                campaign,
                helpSteps.campaignReq1Matcher(expectedCampaign));
    }

    @Test
    public void createInternalAutobudgetCampaign_checkExportRotationGoalId() {
        long rotationGoalId = RandomUtils.getNextInt();
        dbSteps.campaignsInternalSteps().setRotationGoalId(cid, rotationGoalId);
        TransportHelpSteps helpSteps = new TransportHelpSteps(api);
        Campaign expectedCampaign = helpSteps.buildExpectedCampaignObjFromDb(cid, shard, UpdateInfo.UPDATE);
        expectedCampaign.setRotationGoalId(rotationGoalId);
        fillInStrategy(cid, expectedCampaign);

        Campaign campaign = sendNewCampaign();
        assumeThat("в БК отправлена кампания", campaign, notNullValue());
        assertThat("Значение параметров кампании соответствует ожидаениям",
                campaign,
                helpSteps.campaignReq1Matcher(expectedCampaign));
    }

    @Test
    public void createInternalAutobudgetCampaign_checkExportRfCloseByClick() {
        dbSteps.campaignsInternalSteps().setRfCloseByClick(cid, CampaignsInternalRfCloseByClick.adgroup);
        TransportHelpSteps helpSteps = new TransportHelpSteps(api);
        Campaign expectedCampaign = helpSteps.buildExpectedCampaignObjFromDb(cid, shard, UpdateInfo.UPDATE);
        expectedCampaign.setRfCloseByClick(CampaignsInternalRfCloseByClick.adgroup.getLiteral());
        fillInStrategy(cid, expectedCampaign);

        Campaign campaign = sendNewCampaign();
        assumeThat("в БК отправлена кампания", campaign, notNullValue());
        assertThat("Значение параметров кампании соответствует ожиданиям",
                campaign,
                helpSteps.campaignReq1Matcher(expectedCampaign));
    }

    @Test
    public void createInternalAutobudgetCampaign_checkSecondRequestMandatoryFields() {
        long rotationGoalId = RandomUtils.getNextInt();
        dbSteps.campaignsInternalSteps().setRotationGoalId(cid, rotationGoalId);
        Long clientId =
                Long.valueOf(api.userSteps.getDarkSideSteps().getClientFakeSteps().getClientData(LOGIN).getClientID());
        pid = createInternalAdgroupsWithDefaultAdditionalTargeting(clientId, cid);
        bid = createInternalBanner(clientId, cid, pid);

        Campaign campaign = sendNewCampaign();
        assumeThat("Новая кампания отправлена в БК", campaign, notNullValue());

        dbSteps.bannersSteps().setBannerStatusBsSynced(bid, BannersStatusbssynced.No);

        Campaign expectedSyncedCampaign = transportHelpSteps.buildExpectedInternalCampaignObjFromDb(cid, shard,
                UpdateInfo.SKIP);
        expectedSyncedCampaign.setIsMobileApp(null);
        expectedSyncedCampaign.setPageIds(null);
        expectedSyncedCampaign.setRestrictionType(null);
        expectedSyncedCampaign.setRestrictionValue(null);

        campaign = sendSyncedCampaign();

        assumeThat("кампания переотправлена в БК", campaign, notNullValue());
        assertThat("обязательные поля при UpdateInfo=0 соответствуют ожиданиям",
                campaign,
                beanDiffer(expectedSyncedCampaign).useCompareStrategy(DefaultCompareStrategies.onlyExpectedFields()));
    }

    @Test
    public void updateInternalAutobudgetCampaign_commonCheck() {
        sendNewCampaign();

        List<String> pageIds = Arrays.asList("123", "456", "789");
        Long restrictionValue = 999999L;
        Long placeId = 100500L;

        CampaignsInternalRecord campaignsInternal = dbSteps.campaignsInternalSteps().getCampaignsInternalRecord(cid);
        campaignsInternal
                .setRestrictionValue(restrictionValue)
                .setIsMobile(1)
                .setPageIds(String.join(",", pageIds))
                .setPlaceId(placeId)
                .setRotationGoalId(3735928559L);
        dbSteps.campaignsInternalSteps().updateCampaignsInternalRecord(campaignsInternal);
        TransportHelpSteps helpSteps = new TransportHelpSteps(api);
        Campaign expectedCampaign = helpSteps.buildExpectedCampaignObjFromDb(cid, shard, UpdateInfo.UPDATE);
        fillInStrategy(cid, expectedCampaign);

        dbSteps.campaignsSteps().setCampaignsStatusBsSynced(cid, CampaignsStatusbssynced.No);
        Campaign campaign = sendSyncedCampaign();
        assumeThat("в БК отправлена кампания", campaign, notNullValue());
        assertThat("Значение параметров кампании соответствует ожидаениям",
                campaign,
                helpSteps.campaignReq1Matcher(expectedCampaign));
    }

    private void fillInStrategy(long cid, Campaign expectedCampaign) {
        DirectJooqDbSteps jooqSteps = api.userSteps.getDirectJooqDbSteps();
        CampaignsRecord dbRecord = jooqSteps.campaignsSteps().getCampaignById(cid);
        BigDecimal sum = dbRecord.getStrategyData().getAsJsonObject().get("sum").getAsBigDecimal();

        expectedCampaign.setAutoBudget(dbRecord.getAutobudget() == CampaignsAutobudget.Yes ? 1 : 0);
        expectedCampaign.setAutoBudgetWeekLimitCur(Money.valueOf(sum, Currency.RUB).addVAT().floatValue());
    }
}
