package ru.yandex.autotests.direct.api.campaigns.add.negativekeywords;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;

import org.apache.commons.lang3.RandomStringUtils;
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.api.campaigns.CampaignsFeatures;
import ru.yandex.autotests.direct.api.campaigns.CampaignsLogins;
import ru.yandex.autotests.direct.utils.tags.TagDictionary;
import ru.yandex.autotests.directapi.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.apiclient.errors.Api5ErrorDetails;
import ru.yandex.autotests.directapi.model.api5.campaigns.AddRequestMap;
import ru.yandex.autotests.directapi.model.api5.campaigns.CampaignAddItemMap;
import ru.yandex.autotests.directapi.model.api5.general.ExpectedResult;
import ru.yandex.autotests.directapi.model.api5.general.JavaOrPerlExpectedResult;
import ru.yandex.autotests.directapi.model.api5.general.Notification;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.autotests.directapi.rules.Trashman;
import ru.yandex.autotests.directapi.steps.banners.KeywordPhraseGenerator;
import ru.yandex.autotests.directapi.steps.banners.KeywordsSteps;
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.apache.commons.lang3.StringUtils.capitalize;

/**
 * Created by pavryabov on 26.08.15.
 * https://st.yandex-team.ru/TESTIRT-6546
 */
@Aqua.Test
@Features(CampaignsFeatures.ADD)
@Description("Проверка валидации поля NegativeKeywords. Негативные сценарии")
@Issue("https://st.yandex-team.ru/DIRECT-34567")
@Tag(TagDictionary.TRUNK)
@RunWith(Parameterized.class)
public class NegativeKeywordsValidationNegativeTest {

    private static final String CLIENT = CampaignsLogins.CLIENT;

    @ClassRule
    public static ApiSteps api = new ApiSteps().version(5).as(CLIENT);

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

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

    @Parameterized.Parameter(0)
    public String description;

    @Parameterized.Parameter(1)
    public String[] negativeKeywords;

    @Parameterized.Parameter(2)
    public JavaOrPerlExpectedResult expectedResult;

    private static Integer[] manyMaxLengths;

    static {
        manyMaxLengths = new Integer[10];
        Arrays.fill(manyMaxLengths, KeywordsSteps.MINUS_WORD_MAX_LENGTH + 1);
    }

    @Parameterized.Parameters(name = "{0}")
    public static Collection testData() {
        KeywordPhraseGenerator keywordPhraseGenerator =
                new KeywordPhraseGenerator(KeywordsSteps.CYRILLIC_CHARS_NO_SPACE);

        KeywordPhraseGenerator.Result oneKeywordWithTooManyCharacters =
                keywordPhraseGenerator.generatePhraseWithPlusAndMinusWords(
                        new Integer[0],
                        new Integer[]{KeywordsSteps.MINUS_WORD_MAX_LENGTH + 1});

        KeywordPhraseGenerator.Result twoKeywordsWithTooManyCharacters =
                keywordPhraseGenerator.generatePhraseWithPlusAndMinusWords(
                        new Integer[0],
                        new Integer[]{KeywordsSteps.MINUS_WORD_MAX_LENGTH + 1,
                                KeywordsSteps.MINUS_WORD_MAX_LENGTH + 1});

        KeywordPhraseGenerator.Result manyKeywordsWithTooManyCharacters =
                keywordPhraseGenerator.generatePhraseWithPlusAndMinusWords(
                        new Integer[0], manyMaxLengths);

        KeywordPhraseGenerator.Result manyKeywordsWithTotalLengthOneCharacterOverMaximum =
                keywordPhraseGenerator.generatePhraseWithPlusAndMinusWords(
                        new Integer[0],
                        KeywordPhraseGenerator.minusWordLengthsWithSpecificTotalLength(
                                KeywordsSteps.MINUS_WORD_MAX_LENGTH,
                                KeywordsSteps.MINUS_WORD_MAX_LENGTH,
                                CampaignAddItemMap.MAX_NEGATIVE_KEYWORDS_LENGTH + 1
                        ).toArray(new Integer[0]));

        String negativeKeywordWithAverageLength =
                RandomStringUtils.randomAlphabetic(KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH);

        Object[][] data = new Object[][]{
                {"One keyword with too many characters",
                        oneKeywordWithTooManyCharacters.minusWordArray(),
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5162,
                                        Api5ErrorDetails.LENGTH_OF_NEGATIVE_KEYWORDS_LONGER_THAN,
                                        KeywordsSteps.KEYWORD_MAX_LENGTH,
                                        oneKeywordWithTooManyCharacters.commaSeparatedMinusWords())))
                                .perl(ExpectedResult.errors(
                                new Notification(5162,
                                        Api5ErrorDetails.LENGTH_OF_NEGATIVE_KEYWORDS_LONGER_THAN,
                                        KeywordsSteps.KEYWORD_MAX_LENGTH,
                                        oneKeywordWithTooManyCharacters.commaSeparatedMinusWords())))
                },
                {"Two keywords with too many characters",
                        twoKeywordsWithTooManyCharacters.minusWordArray(),
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5162,
                                        Api5ErrorDetails.LENGTH_OF_NEGATIVE_KEYWORDS_LONGER_THAN,
                                        KeywordsSteps.KEYWORD_MAX_LENGTH,
                                        twoKeywordsWithTooManyCharacters.commaSeparatedMinusWords()),
                                new Notification(5162,
                                        Api5ErrorDetails.LENGTH_OF_NEGATIVE_KEYWORDS_LONGER_THAN,
                                        KeywordsSteps.KEYWORD_MAX_LENGTH,
                                        twoKeywordsWithTooManyCharacters.commaSeparatedMinusWords()))
                        )
                                .perl(ExpectedResult.errors(
                                new Notification(5162,
                                        Api5ErrorDetails.LENGTH_OF_NEGATIVE_KEYWORDS_LONGER_THAN,
                                        KeywordsSteps.KEYWORD_MAX_LENGTH,
                                        twoKeywordsWithTooManyCharacters.commaSeparatedMinusWords())))},

                // DIRECT-57575
                {"Many keywords with too many characters",
                        manyKeywordsWithTooManyCharacters.minusWordArray(),
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                repeat(10,
                                        new Notification(5162,
                                                Api5ErrorDetails.LENGTH_OF_NEGATIVE_KEYWORDS_LONGER_THAN,
                                                KeywordsSteps.KEYWORD_MAX_LENGTH,
                                                manyKeywordsWithTooManyCharacters.commaSeparatedMinusWords()))
                        ))
                                .perl(ExpectedResult.errors(
                                new Notification(5162,
                                        Api5ErrorDetails.LENGTH_OF_NEGATIVE_KEYWORDS_LONGER_THAN,
                                        KeywordsSteps.KEYWORD_MAX_LENGTH,
                                        manyKeywordsWithTooManyCharacters.commaSeparatedMinusWords())))},
                {"Many keywords with total length one character over maximum",
                        manyKeywordsWithTotalLengthOneCharacterOverMaximum.minusWordArray(),
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5001,
                                        Api5ErrorDetails.MINUS_PHRASES_LENGHT_MORE_THAN,
                                        CampaignAddItemMap.MAX_NEGATIVE_KEYWORDS_LENGTH)))
                                .perl(ExpectedResult.errors(
                                new Notification(5001,
                                        Api5ErrorDetails.MINUS_PHRASES_LENGHT_MORE_THAN,
                                        CampaignAddItemMap.MAX_NEGATIVE_KEYWORDS_LENGTH)))},
                {"One keyword with not many characters and [",
                        new String[]{negativeKeywordWithAverageLength + "["},
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_BRACKETS_IN_MINUS_PHRASE,
                                        negativeKeywordWithAverageLength + "[")))
                                .perl(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_BRACKETS_IN_MINUS_PHRASE,
                                        negativeKeywordWithAverageLength + "[")))},
                {"[test", new String[]{"[test"},
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_BRACKETS_IN_MINUS_PHRASE, "[test")))
                                .perl(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_BRACKETS_IN_MINUS_PHRASE, "[test")))},
                {".test", new String[]{".test"},
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5002,
                                        Api5ErrorDetails.MINUS_PHRASES_COULD_NOT_START_WITH_DOT_OR_APOSTROPHE, ".test"
                                )))
                                .perl(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.MINUS_PHRASES_COULD_NOT_START_WITH_DOT_OR_APOSTROPHE, ".test"
                                )))},
                {"te+st", new String[]{"te+st"},
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "+", "te+st")))
                                .perl(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "+", "te+st")))},
                {"te!st", new String[]{"te!st"},
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "!", "te!st")))
                                .perl(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "!", "te!st")))},
                {"test+", new String[]{"test+"},
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "+", "test+")))
                                .perl(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "+", "test+")))},
                {"test!", new String[]{"test!"},
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "!", "test!")))
                                .perl(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "!", "test!")))},
                {"+ test", new String[]{"+ test"},
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "+", "+ test")))
                                .perl(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "+", "+ test")))},
                {"++test", new String[]{"++test"},
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "+", "++test")))
                                .perl(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "+", "++test")))},
                {"-test", new String[]{"-test"},
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_START_OR_END_OF_MINUS_PHRASE, "-",
                                        "-test")))
                                .perl(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_START_OR_END_OF_MINUS_PHRASE, "-",
                                        "-test")))},
                {"test-", new String[]{"test-"},
                        JavaOrPerlExpectedResult.java(ExpectedResult.errorsIgnoringDetails(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_START_OR_END_OF_MINUS_PHRASE, "-",
                                        "test-")))
                                .perl(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_START_OR_END_OF_MINUS_PHRASE, "-",
                                        "test-")))},
                {"te!st, te-st", new String[]{"te!st", "te-st"},
                        JavaOrPerlExpectedResult.both(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.INCORRECT_USE_OF_SYMBOL_IN_MINUS_PHRASE, "!", "te!st")))},
                {",test", new String[]{",test"},
                        JavaOrPerlExpectedResult.both(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.MINUS_PHRASES_CAN_ONLY_CONSIST, ",test")))},
                {"te,st", new String[]{"te,st"},
                        JavaOrPerlExpectedResult.both(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.MINUS_PHRASES_CAN_ONLY_CONSIST, "te,st")))},
                {"test,", new String[]{"test,"},
                        JavaOrPerlExpectedResult.both(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.MINUS_PHRASES_CAN_ONLY_CONSIST, "test,")))},
                {"10.10.10", new String[]{"10.10.10"},
                        JavaOrPerlExpectedResult.both(ExpectedResult.errors(
                                new Notification(5002,
                                        Api5ErrorDetails.MINUS_PHRASES_CANNOT_CONTAIN_MORE_THAN_TWO_NUMBERS,
                                        "10.10.10")))},
                {"test test", new String[]{"test", "test"},
                        JavaOrPerlExpectedResult.both(ExpectedResult.errors(
                                new Notification(9802, Api5ErrorDetails.ELEMENT_PRESENT_IN_LIST_MORE_THAN_ONE_TIME,
                                        "test", capitalize(CampaignAddItemMap.NEGATIVE_KEYWORDS))))},//DIRECT-46426
        };
        return Arrays.asList(data);
    }

    private static Notification[] repeat(int times, Notification notification) {
        return Collections.nCopies(times, notification).toArray(new Notification[]{});
    }

    @BeforeClass
    public static void initTest() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(CLIENT);
    }

    @Test
    @ru.yandex.qatools.allure.annotations.TestCaseId("174")
    public void addWithNegativeKeywords() {
        //DIRECT-45549
        api.userSteps.campaignSteps().shouldGetResultOnAdd(new AddRequestMap()
                        .withCampaigns(new CampaignAddItemMap()
                                .defaultCampaignAddItem().withNegativeKeywords(negativeKeywords)
                                .withDefaultTextCampaign()
                        ),
                expectedResult);
    }
}
