package ru.yandex.autotests.directapi.finance.accountmanagement.update;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

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.tables.Campaigns;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.CampaignsRecord;
import ru.yandex.autotests.direct.db.steps.DirectJooqDbSteps;
import ru.yandex.autotests.directapi.darkside.Logins;
import ru.yandex.autotests.directapi.finance.FinanceFeatures;
import ru.yandex.autotests.directapi.finance.FinanceLogins;
import ru.yandex.autotests.directapi.model.common.SpendMode;
import ru.yandex.autotests.directapi.model.finances.sharedaccount.AccountDayBudgetInfoMap;
import ru.yandex.autotests.directapi.model.finances.sharedaccount.AccountMap;
import ru.yandex.autotests.directapi.rules.ApiSteps;
import ru.yandex.autotests.directapi.rules.Trashman;
import ru.yandex.qatools.allure.annotations.Features;

import static org.hamcrest.Matchers.comparesEqualTo;
import static org.hamcrest.Matchers.hasProperty;
import static ru.yandex.autotests.irt.testutils.allure.TestSteps.assertThat;

@Aqua.Test
@RunWith(Parameterized.class)
@Features(FinanceFeatures.ACCOUNT_MANAGEMENT_GET_UPDATE)
public class AccountManagementUpdateAccountDailyBudgetAmountChangeRightsTest {
    @ClassRule
    public static final ApiSteps api = new ApiSteps().version(104);

    private static final float RESET_VALUE = 500f;
    private static final float SET_VALUE = 1000f;

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

    public static final class TestCase {
        private final String description;
        private final String operatorLogin;
        private final String clientLogin;

        private TestCase(String description, String operatorLogin, String clientLogin) {
            this.description = description;
            this.operatorLogin = operatorLogin;
            this.clientLogin = clientLogin;
        }

        @Override
        public String toString() {
            return description;
        }
    }

    private final TestCase testCase;

    @Parameterized.Parameters(name = "{0}")
    public static Collection<Object[]> parameters() {
        List<TestCase> parameters = Arrays.asList(
                new TestCase("самоходный клиент может поменять дневной бюджет на общий счёт себе",
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_REGULAR_CLIENT_LOGIN,
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_REGULAR_CLIENT_LOGIN),
                new TestCase("агентский клиент с правом на перенос средств может поменять дневной бюджет на общий счёт себе",
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_AGENCY_CLIENT_LOGIN1,
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_AGENCY_CLIENT_LOGIN1),
                new TestCase("представитель агентства может поменять дневной бюджет на общий счёт клиенту",
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_AGENCY_REP1_LOGIN,
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_AGENCY_CLIENT_LOGIN1),
                new TestCase("сервисируемый клиент может поменять дневной бюджет на общий счёт себе",
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_MANAGED_CLIENT_LOGIN,
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_MANAGED_CLIENT_LOGIN),
                new TestCase("менеджер агентства может поменять дневной бюджет на общий счёт клиенту",
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_AGENCY_MANAGER_LOGIN,
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_AGENCY_CLIENT_LOGIN1),
                new TestCase("менеджер может поменять дневной бюджет на общий счёт своему клиенту",
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_MANAGER_LOGIN,
                        FinanceLogins.ACCOUNT_DAILY_BUDGET_MANAGED_CLIENT_LOGIN)
        );

        return parameters.stream()
                .map(testCase -> new Object[]{ testCase })
                .collect(Collectors.toList());
    }

    public AccountManagementUpdateAccountDailyBudgetAmountChangeRightsTest(TestCase testCase) {
        this.testCase = testCase;
    }

    private long accountId;

    @Before
    public void setUp() {
        api.as(Logins.LOGIN_SUPER, testCase.operatorLogin);

        DirectJooqDbSteps jooqDbSteps = api.userSteps.getDirectJooqDbSteps()
                .useShardForLogin(testCase.clientLogin);

        Long clientId = jooqDbSteps.usersSteps().getUser(testCase.clientLogin).getClientid();
        accountId = jooqDbSteps.campaignsSteps().getWallet(clientId).getCid();

        jooqDbSteps.campaignsSteps()
                .updateCampaigns(new CampaignsRecord()
                        .with(Campaigns.CAMPAIGNS.CID, accountId)
                        .with(Campaigns.CAMPAIGNS.DAY_BUDGET, BigDecimal.valueOf(RESET_VALUE)));

    }

    @Test
    public void testCanSetDailyBudgetAmount() {
        api.userSteps.campaignFakeSteps().setDayBudgetChangeCount((int) accountId, 0);
        api.userSteps.financeSteps().update(new AccountMap(api.type())
                .withAccountID((int) accountId)
                .withAccountDayBudget(new AccountDayBudgetInfoMap(api.type())
                        .withSpendMode(SpendMode.STRETCHED.getValue())
                        .withAmount(SET_VALUE)));

        assertThat(
                "сумма дневного бюджета сохранилась и вернулась верно",
                api.userSteps.financeSteps().getAccount((int) accountId),
                hasProperty(AccountMap.ACCOUNT_DAY_BUDGET,
                        hasProperty(AccountDayBudgetInfoMap.AMOUNT, comparesEqualTo(SET_VALUE))));
    }
}
