package ru.yandex.autotests.directapi.keywords.add.keyword;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

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.apiclient.config.Semaphore;
import ru.yandex.autotests.directapi.apiclient.errors.Api5ErrorDetails;
import ru.yandex.autotests.directapi.keywords.KeywordsFeatures;
import ru.yandex.autotests.directapi.keywords.KeywordsLogins;
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.Notification;
import ru.yandex.autotests.directapi.model.api5.keywords.AddRequestMap;
import ru.yandex.autotests.directapi.model.api5.keywords.KeywordAddMap;
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.autotests.directapi.utils.ErrorTextUtils;
import ru.yandex.autotests.irt.testutils.allure.LogSteps;
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.Step;
import ru.yandex.qatools.hazelcast.SemaphoreRule;

/**
 * Created by chicos on 24.04.2015.
 */
@Aqua.Test
@Features(KeywordsFeatures.ADD)
@Description("Добавления значений параметра Keyword предельной длины")
@Tag(TagDictionary.TRUNK)
@RunWith(Parameterized.class)
public class AddKeywordsKeywordLengthTest {
    private static LogSteps log = LogSteps.getLogger(AddKeywordsKeywordLengthTest.class);
    private static final String client = KeywordsLogins.SINGLE_CLIENT_ADD;

    private static Long campaignID;

    private Long groupID;

    @ClassRule
    public static ApiSteps api = new ApiSteps().as(client);

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

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

    @Parameterized.Parameter(value = 0)
    public String description;

    @Parameterized.Parameter(value = 1)
    public List<String> keywordValues;

    @Parameterized.Parameter(value = 2)
    public List<ExpectedResult> expectedResults;

    private static final Integer[] manyMaxPlusWordLengths;
    static {
        manyMaxPlusWordLengths = new Integer[5];
        Arrays.fill(manyMaxPlusWordLengths, KeywordsSteps.KEYWORD_MAX_LENGTH + 1);
    }

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

    @Parameterized.Parameters(name = "test = {0}")
    public static Collection fields() {
        // java-сервис выдаёт в ошибках фразу с замененой буквой "ё", для тестов длины это не важно,
        // поэтому убираем из генерации "ё"
        KeywordPhraseGenerator keywordPhraseGenerator =
                new KeywordPhraseGenerator(KeywordsSteps.CYRILLIC_CHARS_NO_SPACE.replaceAll("[Ёё]", ""));

        KeywordPhraseGenerator.Result oneWordOverLength = keywordPhraseGenerator
                .generatePlusWordPhrase(KeywordsSteps.KEYWORD_MAX_LENGTH + 1);

        KeywordPhraseGenerator.Result phraseWithOneWordOverLength = keywordPhraseGenerator
                .generatePlusWordPhrase(KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH, KeywordsSteps.KEYWORD_MAX_LENGTH + 1);

        KeywordPhraseGenerator.Result phraseWithTwoWordsOverLength = keywordPhraseGenerator
                .generatePlusWordPhrase(KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH,
                        KeywordsSteps.KEYWORD_MAX_LENGTH + 1, KeywordsSteps.KEYWORD_MAX_LENGTH + 1);

        KeywordPhraseGenerator.Result phraseWithManyWordsOverLength = keywordPhraseGenerator
                .generatePlusWordPhrase(
                        new ArrayList<Integer>() {{
                            add(KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH);
                            addAll(Arrays.asList(manyMaxPlusWordLengths));
                        }}.toArray(new Integer[0]));

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

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

        KeywordPhraseGenerator.Result phraseWithManyMinusWordsOverLength = keywordPhraseGenerator
                .generatePhraseWithPlusAndMinusWords(
                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                        manyMaxMinusWordLengths);

        KeywordPhraseGenerator.Result phraseWithTooManyPlusWords = keywordPhraseGenerator
                .generatePlusWordPhraseOfSameLengthWords(
                        KeywordsSteps.MAX_PLUS_WORDS_IN_PHRASE + 1,
                        KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH);

        KeywordPhraseGenerator.Result phraseExceedingPhraseLengthLimit = keywordPhraseGenerator
                .generatePhraseOfSpecificLength(
                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                        KeywordsSteps.PHRASE_MAX_LENGTH + 1,
                        KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH);

        Object[][] data = new Object[][]{
                {"Одиночное ключевое слово", Arrays.asList(keywordPhraseGenerator.generatePlusWordPhrase(KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH).toString()),
                        Arrays.asList(ExpectedResult.success())},
                {"Одиночное ключевое слово максимальной длины",
                        Arrays.asList(keywordPhraseGenerator.generatePlusWordPhrase(KeywordsSteps.KEYWORD_MAX_LENGTH).toString()),
                        Arrays.asList(ExpectedResult.success())},
                {"Одиночное ключевое слово длиннее максимальной длины",
                        Arrays.asList(oneWordOverLength.toString()),
                        Arrays.asList(ExpectedResult.errors(
                                new Notification(5142
                                        , Api5ErrorDetails.KEYWORD_MAX_LENGTH_EXCEEDED_INDIVIDUAL
                                        , KeywordsSteps.KEYWORD_MAX_LENGTH
                                        , oneWordOverLength.commaSeparatedPlusWords())))
                },

                {"Два плюс-слова",
                        Arrays.asList(keywordPhraseGenerator.generatePlusWordPhrase(
                                KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH, KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH).toString()),
                        Arrays.asList(ExpectedResult.success())},
                {"Два плюс-слова, одно из них максимальной длины",
                        Arrays.asList(keywordPhraseGenerator.generatePlusWordPhrase(KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH, KeywordsSteps.KEYWORD_MAX_LENGTH).toString()),
                        Arrays.asList(ExpectedResult.success())},
                {"Два плюс-слова, одно из них длиннее максимальной длины",
                        Arrays.asList(phraseWithOneWordOverLength.toString()),
                        Arrays.asList(ExpectedResult.errors(
                                new Notification(5142
                                        , Api5ErrorDetails.KEYWORD_MAX_LENGTH_EXCEEDED_INDIVIDUAL
                                        , KeywordsSteps.KEYWORD_MAX_LENGTH
                                        , phraseWithOneWordOverLength.plusWordArray()[1])))
                },

                {"Несколько плюс-слов, два из них длиннее максимальной длины",
                        Arrays.asList(phraseWithTwoWordsOverLength.toString()),
                        Arrays.asList(ExpectedResult.errors(
                                new Notification(5142
                                        , Api5ErrorDetails.KEYWORD_MAX_LENGTH_EXCEEDED_INDIVIDUAL
                                        , KeywordsSteps.KEYWORD_MAX_LENGTH
                                        , phraseWithTwoWordsOverLength.commaSeparatedFilteredPlusWords(
                                                word -> word.length() > KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH))))
                },
                {"Несколько плюс-слов, несколько из них длиннее максимальной длины",
                        Arrays.asList(phraseWithManyWordsOverLength.toString()),
                        Arrays.asList(ExpectedResult.errors(
                                new Notification(5142
                                        , Api5ErrorDetails.KEYWORD_MAX_LENGTH_EXCEEDED_INDIVIDUAL
                                        , KeywordsSteps.KEYWORD_MAX_LENGTH
                                        , phraseWithManyWordsOverLength.commaSeparatedFilteredPlusWords(
                                                word -> word.length() > KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH))))
                },

                {"Максимальное количество плюс-слов",
                        Arrays.asList(keywordPhraseGenerator.generatePlusWordPhraseOfSameLengthWords(KeywordsSteps.MAX_PLUS_WORDS_IN_PHRASE, KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH).toString()),
                        Arrays.asList(ExpectedResult.success())},
                {"Больше максимального количества плюс-слов",
                        Arrays.asList(phraseWithTooManyPlusWords.toString()),
                        Arrays.asList(ExpectedResult.errors(
                                new Notification(5140
                                        , Api5ErrorDetails.KEYWORD_COULD_NOT_CONTAIN_MORE_WORDS
                                        , phraseWithTooManyPlusWords.toString())))
                },

                {"Одно плюс-слово, одно минус-слово",
                        Arrays.asList(
                                keywordPhraseGenerator.generatePhraseWithPlusAndMinusWords(
                                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH}).toString()),
                        Arrays.asList(ExpectedResult.success())},
                {"Одно плюс-слово, одно минус-слово почти максимальной длины",
                        Arrays.asList(
                                keywordPhraseGenerator.generatePhraseWithPlusAndMinusWords(
                                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                        new Integer[]{KeywordsSteps.MINUS_WORD_MAX_LENGTH - 1}).toString()),
                        Arrays.asList(ExpectedResult.success())},
                {"Одно плюс-слово, одно минус-слово максимальной длины",
                        Arrays.asList(
                                keywordPhraseGenerator.generatePhraseWithPlusAndMinusWords(
                                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                        new Integer[]{KeywordsSteps.MINUS_WORD_MAX_LENGTH}).toString()),
                        Arrays.asList(ExpectedResult.success())},
                {"Одно плюс-слово, одно минус-слово длиннее максимальной длины",
                        Arrays.asList(phraseWithOneMinusWordOverLength.toString()),
                        Arrays.asList(ExpectedResult.errors(
                                new Notification(5162
                                        , Api5ErrorDetails.KEYWORD_MINUS_WORD_LENGTH_EXCEEDED
                                        , KeywordsSteps.KEYWORD_MAX_LENGTH
                                        , phraseWithOneMinusWordOverLength.commaSeparatedMinusWords())))
                },

                {"Одно плюс-слово, два минус-слова длиннее максимальной длины",
                        Arrays.asList(phraseWithTwoMinusWordsOverLength.toString()),
                        Arrays.asList(ExpectedResult.errors(
                                new Notification(5162
                                        , Api5ErrorDetails.KEYWORD_MINUS_WORD_LENGTH_EXCEEDED
                                        , KeywordsSteps.KEYWORD_MAX_LENGTH
                                        , phraseWithTwoMinusWordsOverLength.commaSeparatedMinusWords())))
                },
                {"Одно плюс-слово, несколько минус-слов длиннее максимальной длины",
                        Arrays.asList(phraseWithManyMinusWordsOverLength.toString()),
                        Arrays.asList(ExpectedResult.errors(
                                new Notification(5162
                                        , Api5ErrorDetails.KEYWORD_MINUS_WORD_LENGTH_EXCEEDED
                                        , KeywordsSteps.KEYWORD_MAX_LENGTH
                                        , phraseWithManyMinusWordsOverLength.commaSeparatedMinusWords())))
                },

                {"Одно плюс-слово, много минус-слов до максимальной длины",
                        Arrays.asList(
                                keywordPhraseGenerator.generatePhraseOfSpecificLength(
                                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                        KeywordsSteps.PHRASE_MAX_LENGTH,
                                        KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH).toString()),
                        Arrays.asList(ExpectedResult.success())},
                {"Одно плюс-слово, много минус-слов до длины больше максимальной",
                        Arrays.asList(phraseExceedingPhraseLengthLimit.toString()),
                        Arrays.asList(ExpectedResult.errors(
                                new Notification(5001
                                        , Api5ErrorDetails.KEYWORD_MAX_LENGTH_EXCEEDED
                                        , KeywordsSteps.PHRASE_MAX_LENGTH
                                        , ErrorTextUtils.getShortTextParameter(phraseExceedingPhraseLengthLimit.toString()))))
                },
                {"Одно плюс-слово, много минус-слов до максимальной длины, лишние пробелы в начале строки",
                        Arrays.asList(
                                " " + keywordPhraseGenerator.generatePhraseOfSpecificLength(
                                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                        KeywordsSteps.PHRASE_MAX_LENGTH,
                                        KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH).toString()),
                        Arrays.asList(ExpectedResult.success())},
                {"Одно плюс-слово, много минус-слов до максимальной длины, лишние пробелы в конце строки",
                        Arrays.asList(
                                keywordPhraseGenerator.generatePhraseOfSpecificLength(
                                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                        KeywordsSteps.PHRASE_MAX_LENGTH,
                                        KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH).toString() + " "),
                        Arrays.asList(ExpectedResult.success())},
                {"Одно плюс-слово, много минус-слов до максимальной длины, лишние пробелы в середине строки",
                        Arrays.asList(
                                keywordPhraseGenerator.generatePhraseOfSpecificLength(
                                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                        KeywordsSteps.PHRASE_MAX_LENGTH + 1,
                                        KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH, 1).toString()),
                        Arrays.asList(ExpectedResult.success())},

                {"Две корректных фразы суммарной длиной больше 4096",
                        Arrays.asList(
                                keywordPhraseGenerator.generatePhraseOfSpecificLength(
                                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                        KeywordsSteps.PHRASE_MAX_LENGTH * 3 / 4,
                                        KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH).toString(),
                                keywordPhraseGenerator.generatePhraseOfSpecificLength(
                                        new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                        KeywordsSteps.PHRASE_MAX_LENGTH * 3 / 4,
                                        KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH).toString()
                        ),
                        Arrays.asList(ExpectedResult.success(), ExpectedResult.success())
                },
                {"Две фразы, одна корректная, одна слишком длинная",
                        Arrays.asList(
                                keywordPhraseGenerator.generatePlusWordPhrase(KeywordsSteps.KEYWORD_MAX_LENGTH).toString(),
                                phraseExceedingPhraseLengthLimit.toString()
                        ),
                        Arrays.asList(
                                ExpectedResult.success(),
                                ExpectedResult.errors(
                                        new Notification(5001
                                                , Api5ErrorDetails.KEYWORD_MAX_LENGTH_EXCEEDED
                                                , KeywordsSteps.PHRASE_MAX_LENGTH
                                                , ErrorTextUtils.getShortTextParameter(phraseExceedingPhraseLengthLimit.toString())))
                        )
                },

                //DIRECT-40342
                /*{"Комбинация '-!' считается за один символ", Arrays.asList(wordMaxLengthExclamation),
                        ExpectedResult.success()},
                {"Комбинация '-+' считается за один символ", Arrays.asList(wordMaxLengthPlus),
                        ExpectedResult.success()}*/
        };
        return Arrays.asList(data);
    }

    @BeforeClass
    public static void createCampaign() {
        api.userSteps.clientFakeSteps().fakeClearClientSpentUnits(client);
        campaignID = api.userSteps.campaignSteps().addDefaultTextCampaign(client);
    }

    @Before
    @Step("Подготовим данные для теста")
    public void prepareGroup() {
        groupID = api.userSteps.adGroupsSteps().addDefaultGroup(campaignID);
    }

    @Test
    @ru.yandex.qatools.allure.annotations.TestCaseId("3586")
    public void keywordLengthTest() {
        api.userSteps.keywordsSteps().shouldGetResultOn(
                Action.ADD,
                new AddRequestMap().withKeywords(keywordValues.stream()
                        .map(
                                keyword -> new KeywordAddMap()
                                        .withKeyword(keyword)
                                        .withAdGroupId(groupID))
                        .collect(Collectors.toList())
                        .toArray(new KeywordAddMap[0])),
                expectedResults.toArray(new ExpectedResult[0]));
    }
}
