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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

import org.apache.commons.lang3.RandomStringUtils;
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.errors.Api5ErrorDetails;
import ru.yandex.autotests.directapi.apiclient.errors.Api5ErrorDetailsJava;
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.JavaOrPerlExpectedResult;
import ru.yandex.autotests.directapi.model.api5.general.Notification;
import ru.yandex.autotests.directapi.model.api5.keywords.KeywordUpdateMap;
import ru.yandex.autotests.directapi.model.api5.keywords.UpdateRequestMap;
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.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.junit.runners.Parameterized.Parameter;
import static org.junit.runners.Parameterized.Parameters;

/**
 * Created by semkagtn on 07.05.15.
 * https://st.yandex-team.ru/TESTIRT-4580
 */
@Aqua.Test
@Features(KeywordsFeatures.UPDATE)
@Issue("https://st.yandex-team.ru/DIRECT-36383")
@Description("Обновление значений параметра Keyword предельной длины")
@Tag(TagDictionary.TRUNK)
@RunWith(Parameterized.class)
public class UpdateKeywordsKeywordLengthTest {

    private static final String LOGIN = KeywordsLogins.SINGLE_CLIENT_UPDATE;

    private static Long campaignID;

    private long keywordID;

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

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

    @Parameter(0)
    public String description;

    @Parameter(1)
    public String keywordValue;

    @Parameter(2)
    public JavaOrPerlExpectedResult expectedResult;

    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);
    }

    @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);

        String wordMaxLengthExclamation =
                RandomStringUtils.random(KeywordsSteps.PHRASE_MAX_LENGTH - 7, KeywordsSteps.CYRILLIC_CHARS_NO_SPACE) +
                        " -!конец";
        String wordMaxLengthPlus =
                RandomStringUtils.random(KeywordsSteps.PHRASE_MAX_LENGTH - 7, KeywordsSteps.CYRILLIC_CHARS_NO_SPACE) +
                        " -+конец";

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

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

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

                {"Максимальное количество плюс-слов",
                        keywordPhraseGenerator
                                .generatePlusWordPhraseOfSameLengthWords(KeywordsSteps.MAX_PLUS_WORDS_IN_PHRASE,
                                        KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH).toString(),
                        JavaOrPerlExpectedResult
                                .java(ExpectedResult.success())
                                .perl(ExpectedResult.warnings(new Notification(10141)))},
                {"Больше максимального количества плюс-слов",
                        phraseWithTooManyPlusWords.toString(),
                        JavaOrPerlExpectedResult.both(
                                ExpectedResult.errors(
                                        new Notification(5140, Api5ErrorDetails.KEYWORD_COULD_NOT_CONTAIN_MORE_WORDS,
                                                phraseWithTooManyPlusWords.toString()))
                        )
                },
                {"Одно плюс-слово, одно минус-слово",
                        keywordPhraseGenerator.generatePhraseWithPlusAndMinusWords(
                                new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH}).toString(),
                        JavaOrPerlExpectedResult
                                .java(ExpectedResult.success())
                                .perl(ExpectedResult.warnings(new Notification(10141)))},
                {"Одно плюс-слово, одно минус-слово почти максимальной длины",
                        keywordPhraseGenerator.generatePhraseWithPlusAndMinusWords(
                                new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                new Integer[]{KeywordsSteps.MINUS_WORD_MAX_LENGTH - 1}).toString(),
                        JavaOrPerlExpectedResult
                                .java(ExpectedResult.success())
                                .perl(ExpectedResult.warnings(new Notification(10141)))},
                {"Одно плюс-слово, одно минус-слово максимальной длины",
                        keywordPhraseGenerator.generatePhraseWithPlusAndMinusWords(
                                new Integer[]{KeywordsSteps.ACCEPTABLE_KEYWORD_LENGTH},
                                new Integer[]{KeywordsSteps.MINUS_WORD_MAX_LENGTH}).toString(),
                        JavaOrPerlExpectedResult
                                .java(ExpectedResult.success())
                                .perl(ExpectedResult.warnings(new Notification(10141)))},
                {"Одно плюс-слово, одно минус-слово длиннее максимальной длины",
                        phraseWithOneMinusWordOverLength.toString(),
                        JavaOrPerlExpectedResult.both(
                                ExpectedResult.errors(
                                        new Notification(5162, Api5ErrorDetails.KEYWORD_MINUS_WORD_LENGTH_EXCEEDED,
                                                KeywordsSteps.KEYWORD_MAX_LENGTH,
                                                phraseWithOneMinusWordOverLength.commaSeparatedMinusWords()))
                        )
                },

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

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

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

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

    @Before
    @Step("Подготовка данных для теста")
    public void prepareKeywords() {
        long groupID = api.userSteps.adGroupsSteps().addDefaultGroup(campaignID);
        keywordID = api.userSteps.keywordsSteps().addDefaultKeyword(groupID);
    }

    @Test
    @ru.yandex.qatools.allure.annotations.TestCaseId("3782")
    public void keywordLengthTest() {
        api.userSteps.keywordsSteps().shouldGetResultOn(
                Action.UPDATE,
                new UpdateRequestMap().withKeywords(new KeywordUpdateMap()
                        .withId(keywordID)
                        .withKeyword(keywordValue)),
                expectedResult);
    }
}
