package ru.yandex.autotests.direct.db.steps;

import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Nullable;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.jooq.TableField;
import org.jooq.UpdateSetMoreStep;

import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampOptionsStrategy;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsArchived;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsAttributionModel;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsCpmPriceStatusApprove;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsCpmPriceStatusCorrect;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsCurrencyconverted;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsMetatype;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsPerformanceNowOptimizingBy;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsPlatform;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsSource;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsStatusactive;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsStatusbehavior;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsStatusbssynced;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsStatusempty;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsStatusmoderate;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsStatusshow;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsStrategyName;
import ru.yandex.autotests.direct.db.models.jooq.ppc.enums.CampaignsType;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.CampaignsPerformance;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.CampOptionsRecord;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.CampaignsCpmPriceRecord;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.CampaignsCpmYndxFrontpageRecord;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.CampaignsMobileContentRecord;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.CampaignsPerformanceRecord;
import ru.yandex.autotests.direct.db.models.jooq.ppc.tables.records.CampaignsRecord;
import ru.yandex.autotests.direct.db.steps.base.BasePpcSteps;
import ru.yandex.autotests.irt.testutils.RandomUtils;
import ru.yandex.qatools.allure.annotations.Step;

import static java.time.temporal.ChronoUnit.HOURS;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.joining;
import static ru.yandex.autotests.direct.db.models.jooq.ppc.Tables.CAMPAIGNS_CPM_PRICE;
import static ru.yandex.autotests.direct.db.models.jooq.ppc.Tables.CAMPAIGNS_CPM_YNDX_FRONTPAGE;
import static ru.yandex.autotests.direct.db.models.jooq.ppc.Tables.CAMPAIGNS_MOBILE_CONTENT;
import static ru.yandex.autotests.direct.db.models.jooq.ppc.Tables.CAMPAIGNS_PERFORMANCE;
import static ru.yandex.autotests.direct.db.models.jooq.ppc.Tables.CAMP_DIALOGS;
import static ru.yandex.autotests.direct.db.models.jooq.ppc.Tables.CAMP_METRIKA_GOALS;
import static ru.yandex.autotests.direct.db.models.jooq.ppc.Tables.CAMP_OPTIONS;
import static ru.yandex.autotests.direct.db.models.jooq.ppc.Tables.CLIENT_DIALOGS;
import static ru.yandex.autotests.direct.db.models.jooq.ppc.tables.Campaigns.CAMPAIGNS;


/*
 * todo javadoc
 */
public class CampaignsSteps extends BasePpcSteps {

    @Step("DB: Установка field в значение value для cid={0}")
    public void setCampaignOption(Long cid, TableField field, Object value) {
        run(db -> db.update(field.getTable())
                .set(field, value)
                .where(field.getTable().field("cid").eq(cid))
                .execute()
        );
    }

    @Step("DB: Получение значения поля field для cid={0}")
    public Object getCampaignOption(Long cid, TableField field) {
        return exec(db -> db.select(field)
                .from(field.getTable())
                .where(field.getTable().field("cid").eq(cid))
                .fetchOne().getValue(0)
        );
    }

    @Step
    public CampaignsRecord getCampaignById(Long cid) {
        return exec(db -> db.selectFrom(CAMPAIGNS)
                .where(CAMPAIGNS.CID.eq(cid))
                .fetchOne()
        );
    }

    @Step
    public List<Long> getCampaignIdsByUid(Long uid) {
        return exec(db -> db.select(singletonList(CAMPAIGNS.CID))
                .from(CAMPAIGNS)
                .where(CAMPAIGNS.UID.eq(uid))
                .fetch()
                .map(rec -> rec.getValue(CAMPAIGNS.CID))
        );
    }

    @Step("DB: Получение id всех не удаленных кампаний для uid={0}")
    public List<Long> getNotEmptyCampaignsByUid(Long uid) {
        return exec(db -> db.select(singletonList(CAMPAIGNS.CID))
                .from(CAMPAIGNS)
                .where(CAMPAIGNS.UID.eq(uid))
                .and(CAMPAIGNS.STATUSEMPTY.eq(CampaignsStatusempty.No))
                .fetch()
                .map(rec -> rec.getValue(CAMPAIGNS.CID))
        );
    }

    @Step
    public List<Long> getCampaignIdsByClientIdOlderThan(Long clientId, LocalDateTime borderCreateTime) {
        return exec(db -> db.select(singletonList(CAMPAIGNS.CID))
                .from(CAMPAIGNS)
                .join(CAMP_OPTIONS).on(CAMPAIGNS.CID.eq(CAMP_OPTIONS.CID))
                .where(CAMPAIGNS.CLIENTID.eq(clientId)
                        .and(CAMP_OPTIONS.CREATE_TIME.lessThan(Timestamp.valueOf(borderCreateTime))))
                .fetch()
                .map(rec -> rec.getValue(CAMPAIGNS.CID))
        );
    }

    @Step
    public CampaignsRecord getCampaignByOrderId(Long orderId) {
        return exec(db -> db.selectFrom(CAMPAIGNS)
                .where(CAMPAIGNS.ORDERID.eq(orderId))
                .fetchOne()
        );
    }

    @Step("DB: Получение максимальных cid в количестве равном limit={0}")
    public List<Long> getMaxCampaignIds(int limit) {
        return exec(db -> db.select(CAMPAIGNS.CID)
                .from(CAMPAIGNS)
                .orderBy(CAMPAIGNS.CID.desc())
                .limit(limit)
                .fetch()
                .map(rec -> rec.getValue(CAMPAIGNS.CID)));
    }

    @Step("DB: Получение времени старта кампании по cid={0}")
    public String getCampaignStartTimeByCid(Long cid) {
        return exec(db -> db.select(CAMPAIGNS.START_TIME)
                .from(CAMPAIGNS)
                .where(CAMPAIGNS.CID.eq(cid))
                .fetchOne()
                .get(CAMPAIGNS.START_TIME)
                .toString());
    }

    @Step("DB: Получение ид общего счета пользователя {0}")
    public CampaignsRecord getWallet(Long clientId) {
        return exec(db -> db.selectFrom(CAMPAIGNS)
                .where(CAMPAIGNS.CLIENTID.eq(clientId)
                        .and(CAMPAIGNS.TYPE.eq(CampaignsType.wallet)))
                .fetchOne()
        );
    }

    @Step("DB: Oбновление записи в таблице ppc.campaigns")
    public void updateCampaigns(CampaignsRecord campaigns) {
        run(db -> db.update(CAMPAIGNS)
                .set(campaigns)
                .where(CAMPAIGNS.CID.eq(campaigns.getCid()))
                .execute()
        );
    }

    @Step("DB: выставление типа {1} для кампании {0}")
    public void setType(Long cid, CampaignsType campaignsType) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.TYPE, campaignsType)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: выставление brandsafety_ret_cond_id {1} для кампании {0}")
    public void setBrandSafetyRetCondId(long cid, long retCondId) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.BRANDSAFETY_RET_COND_ID, retCondId)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    //выставляет название стратегии. для установки данных нужно заполнять поле strategy_data
    @Step("DB: выставление название стратегии {1} для кампании {0}")
    public void setStrategyName(Long cid, CampaignsStrategyName campaignsStrategyName) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.STRATEGY_NAME, campaignsStrategyName)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: выставление поля pay_for_conversion в параметрах стратегии")
    public void setStrategyDataPayForConversion(Long cid, Long payForConversion) {
        CampaignsRecord campaignsRecord = getCampaignById(cid);
        JsonObject strategyData = campaignsRecord.getStrategyData().getAsJsonObject();
        strategyData.addProperty("pay_for_conversion", payForConversion);
        campaignsRecord.setStrategyData(strategyData);
        updateCampaigns(campaignsRecord);
    }

    @Step("DB: установка полей strategy_name и strategy_data")
    public void setStrategyData(long cid, CampaignsStrategyName strategyName, String strategyData) {
        CampaignsRecord campaignsRecord = getCampaignById(cid);
        campaignsRecord.setStrategyName(strategyName);
        JsonElement strategyDataJson = new Gson().fromJson(strategyData, JsonElement.class);
        campaignsRecord.setStrategyData(strategyDataJson);
        updateCampaigns(campaignsRecord);
    }

    @Step("DB: изменение поля start в {1} в ppc.campaigns.strategyData для cid:{0}")
    public void setStrategyDataStartIfExists(Long cid, String start) {
        CampaignsRecord campaignsRecord = getCampaignById(cid);
        JsonObject strategyData = campaignsRecord.getStrategyData().getAsJsonObject();
        if (strategyData.get("start") != null) {
            strategyData.addProperty("start", start);
            campaignsRecord.setStrategyData(strategyData);
            updateCampaigns(campaignsRecord);
        }
    }

    @Step("DB: изменение поля last_bidder_restart_time в {1} в ppc.campaigns.strategyData для cid:{0}")
    public void setStrategyDataLastBidderRestartTimeIfExists(Long cid, String start) {
        CampaignsRecord campaignsRecord = getCampaignById(cid);
        JsonObject strategyData = campaignsRecord.getStrategyData().getAsJsonObject();
        if (strategyData.get("last_bidder_restart_time") != null) {
            strategyData.addProperty("last_bidder_restart_time", start);
            campaignsRecord.setStrategyData(strategyData);
            updateCampaigns(campaignsRecord);
        }
    }

    @Step("DB: выставление поля startTime в {1} в таблице ppc.campaigns для cid:{0}")
    public void setStartDate(Long cid, Date startDate) {
        CampaignsRecord campaignsRecord = getCampaignById(cid);
        campaignsRecord.setStartTime(startDate);
        updateCampaigns(campaignsRecord);
    }

    @Step("DB: установка платформы {1} для кампании {0}")
    public void setPlatform(Long cid, CampaignsPlatform campaignsPlatform) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.PLATFORM, campaignsPlatform)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: установка statusModerate={1} в таблице ppc.campaigns для cid:{0}")
    public void setCampaignsStatusModerate(Long cid, CampaignsStatusmoderate campaignsStatusmoderate) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.STATUSMODERATE, campaignsStatusmoderate)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: установка statusBsSynced={1} в таблице ppc.campaigns для cid:{0}")
    public void setCampaignsStatusBsSynced(Long cid, CampaignsStatusbssynced campaignsStatusbssynced) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.STATUSBSSYNCED, campaignsStatusbssynced)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step
    public CampOptionsRecord getCampOptionsById(Long cid) {
        return exec(db -> db.selectFrom(CAMP_OPTIONS)
                .where(CAMP_OPTIONS.CID.eq(cid))
                .fetchOne()
        );
    }

    @Step("DB: установка strategy в таблице ppc.camp_options для cid:{0}, strategy:{1}")
    public void setCampOptionsStrategy(Long cid, CampOptionsStrategy strategy) {
        run(db -> db.update(CAMP_OPTIONS)
                .set(CAMP_OPTIONS.STRATEGY, strategy)
                .where(CAMP_OPTIONS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: Oбновление записи в таблице ppc.camp_options")
    public void updateCampOptions(CampOptionsRecord campOptions) {
        run(db -> db.update(CAMP_OPTIONS)
                .set(campOptions)
                .where(CAMP_OPTIONS.CID.eq(campOptions.getCid()))
                .execute()
        );
    }

    @Step("DB: добавление записи в таблице ppc.campaigns_performance для cid:{0} с now_optimizing_by:{1}")
    public void addCampaignsPerformanceWithNowOptimizingBy(Long cid,
                                                           CampaignsPerformanceNowOptimizingBy nowOptimizingBy) {
        run(db -> db.insertInto(CAMPAIGNS_PERFORMANCE)
                .set(CAMPAIGNS_PERFORMANCE.NOW_OPTIMIZING_BY, nowOptimizingBy)
                .set(CAMPAIGNS_PERFORMANCE.CID, cid)
                .execute()
        );
    }

    @Step
    public CampaignsPerformanceRecord getCampaignsPerformance(Long cid) {
        return exec(db -> db.selectFrom(CAMPAIGNS_PERFORMANCE)
                .where(CAMPAIGNS_PERFORMANCE.CID.eq(cid))
                .fetchOne()
        );
    }


    @Step("DB: Установка minus_words в таблице ppc.camp_options для cid={0}")
    public void setCampOptionsMinusWords(Long cid, String minusWords) {
        run(db -> db.update(CAMP_OPTIONS)
                .set(CAMP_OPTIONS.MINUS_WORDS, minusWords)
                .where(CAMP_OPTIONS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: установка OrderID = {1} в таблице ppc.campaigns для cid = {0}")
    public void setOrderId(Long cid, Long orderId) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.ORDERID, orderId)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
        shardingSteps().createOrderIdMapping(orderId, shardingSteps().getClientIdByCid(cid));
    }

    @Step("DB: установка AgencyId = {1} в таблице ppc.campaigns для cid = {0}")
    public void setAgencyId(Long cid, Long agencyId) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.AGENCYID, agencyId)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: установка LastChange = {1} в таблице ppc.campaigns для cid = {0}")
    public void setCampaignsLastChange(Long cid, Timestamp lastChange) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.LASTCHANGE, lastChange)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: установить случайный OrderID в таблице ppc.campaigns для cid = {0}")
    public Long setRandomOrderId(Long cid) {
        long orderId = Integer.MAX_VALUE - Math.abs(RandomUtils.getNextInt(2000000));
        setOrderId(cid, orderId);
        return orderId;
    }

    @Step("DB: установка FinishTime в таблице ppc.campaigns для cid:{0}")
    public void setFinishTime(Long cid, Date finishTime) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.FINISH_TIME, finishTime)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: подготовить кампанию к архивации (в т.ч. остановить)")
    public void makeCampaignReadyForArchive(long cid) {
        CampaignsRecord campaignsRecord = getCampaignById(cid)
                .setStatusshow(CampaignsStatusshow.No)
                .setSum(BigDecimal.ZERO);
        updateCampaigns(campaignsRecord);
        // для архивации должно пройти не меньше часа после остановки
        CampOptionsRecord campOptionsRecord = getCampOptionsById(cid)
                .setStoptime(new Timestamp(Instant.now().minus(2, HOURS).toEpochMilli()));
        updateCampOptions(campOptionsRecord);
    }

    @Step("DB: добавить таргетинг на устройства для кампании, таблица ppc.camp_options")
    public void addDeviceTargeting(long cid, String deviceTargeting) {
        CampOptionsRecord campOptionsRecord = getCampOptionsById(cid)
                .setDeviceTargeting(deviceTargeting);
        updateCampOptions(campOptionsRecord);
    }

    @Step("DB: обновить шаблон href_params на кампании, таблица ppc.camp_options")
    public void updateHrefParams(long cid, String hrefParams) {
        CampOptionsRecord campOptionsRecord = getCampOptionsById(cid)
                .setHrefParams(hrefParams);
        updateCampOptions(campOptionsRecord);
    }

    // лучше использовать CampMetrikaGoalsSteps
    @Deprecated
    @Step("DB: Oбновление записи в таблице ppc.camp_metrika_goals")
    public void addCampMetrikaGoals(Long cid, Long goalId, Long goalsCount, Long contextGoalsCount) {
        run(db -> db.insertInto(CAMP_METRIKA_GOALS)
                .set(CAMP_METRIKA_GOALS.CID, cid)
                .set(CAMP_METRIKA_GOALS.GOAL_ID, goalId)
                .set(CAMP_METRIKA_GOALS.GOALS_COUNT, goalsCount)
                .set(CAMP_METRIKA_GOALS.CONTEXT_GOALS_COUNT, contextGoalsCount)
                .execute()
        );
    }

    // лучше использовать CampMetrikaGoalsSteps
    @Deprecated
    @Step("DB: Удаление записи в таблице ppc.camp_metrika_goals")
    public void deleteCampMetrikaGoals(Long cid, Long goalId) {
        run(db -> db.deleteFrom(CAMP_METRIKA_GOALS)
                .where(CAMP_METRIKA_GOALS.CID.eq(cid))
                .and(CAMP_METRIKA_GOALS.GOAL_ID.eq(goalId))
                .execute()
        );
    }

    @Step("DB: установить opts=hide_permalink_info в таблице ppc.campaigns для cid = {0}")
    public void setHidePermalinkInfo(long cid) {
        String opts = exec(db -> db.select(CAMPAIGNS.OPTS)
                .from(CAMPAIGNS)
                .where(CAMPAIGNS.CID.eq(cid))
                .fetchOne(CAMPAIGNS.OPTS)
        );

        Set<String> set = new HashSet<>(asList(opts.split(",")));
        set.add("hide_permalink_info");
        String result = set.stream().collect(joining(","));

        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.OPTS, result)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: удаление записи в таблице ppc.campaigns для cid = {0}")
    public void deleteCampaign(Long cid) {
        exec(db -> db.deleteFrom(CAMPAIGNS)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute());
    }

    @Step("DB: удаление записи в таблице ppc.campaigns_performance для cid = {0}")
    public void deletePerformanceCampaign(Long cid) {
        exec(db -> db.deleteFrom(CampaignsPerformance.CAMPAIGNS_PERFORMANCE)
                .where(CampaignsPerformance.CAMPAIGNS_PERFORMANCE.CID.eq(cid))
                .execute());
    }

    @Step("DB: поиск в ppc.campaigns скопированной кампании cid = {1} у клиента ClientId = {0}")
    public Long findCampaignCopy(long clientId, long cidCopiedFrom) {
        return exec(db -> db.select(CAMPAIGNS.CID)
                .from(CAMPAIGNS)
                .where(CAMPAIGNS.CLIENTID.eq(clientId)
                        .and(CAMPAIGNS.COPIEDFROM.eq(cidCopiedFrom))
                        .and(CAMPAIGNS.STATUSEMPTY.eq(CampaignsStatusempty.No))
                )
                .fetchOne(CAMPAIGNS.CID)
        );
    }

    @Step("DB: установить ограничение ставки для автобюджета для cid = {0}")
    public void setAutobudgetBid(long cid, double autobudgetBid) {
        CampaignsRecord record = getCampaignById(cid);
        JsonElement strategyData = record.getStrategyData();
        strategyData.getAsJsonObject().addProperty("bid", autobudgetBid);
        record.setStrategyData(strategyData);
        updateCampaigns(record);
    }

    @Step("DB: установка значения statusEmpty = {1} для cid = {0}")
    public void setStatusEmpty(long cid, CampaignsStatusempty statusEmpty) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.STATUSEMPTY, statusEmpty)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: установка значения statusshow = {1} для cid = {0}")
    public void setStatusShow(long cid, CampaignsStatusshow statusshow) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.STATUSSHOW, statusshow)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: установка значения statusBehavior = {1} для cid = {0}")
    public void setStatusBehavior(long cid, CampaignsStatusbehavior statusBehavior) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.STATUSBEHAVIOR, statusBehavior)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: Выключаем кампаниии с cid = {0} enable_cpc_hold")
    public void disableCPCHold(long cid) {
        resetOpts(cid);
    }

    @Step("DB: Сбрасываем opts кампаниии с cid = {0}")
    public void resetOpts(long cid) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.OPTS, "")
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: Выставляем кампании с cid = {0} флаги opts = {1}")
    public void setOpts(long cid, Collection<JooqCampaignsOpts> opts) {
        String optsToDb = opts.stream().map(JooqCampaignsOpts::dbValue).collect(joining(","));
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.OPTS, optsToDb)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: Получаем флаги opts с кампании cid = {0} ")
    public Set<String> getOptsStr(long cid) {
        String opts = exec(db -> db.select(CAMPAIGNS.OPTS)
                .from(CAMPAIGNS)
                .where(CAMPAIGNS.CID.eq(cid))
                .fetchOne(CAMPAIGNS.OPTS)
        );
        return Arrays.stream(opts.split(",")).collect(Collectors.toSet());
    }

    @Step("DB: включаем кампаниии с cid = {0} enable_cpc_hold")
    public void enableCpcHold(long cid) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.OPTS, JooqCampaignsOpts.ENABLE_CPC_HOLD.dbValue())
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: выставление аттрибуционной модели {1} для кампании {0}")
    public void setAttributionModel(Long cid, @Nullable String attributionModel) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.ATTRIBUTION_MODEL, (attributionModel != null)
                        ? CampaignsAttributionModel.valueOf(attributionModel)
                        : null)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: Сбрасываем аттрибуционную модель {1} для кампании {0}")
    public void resetAttributionModel(Long cid) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.ATTRIBUTION_MODEL, (CampaignsAttributionModel) null)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: выставление rf {1} для кампании {0}")
    public void setRf(Long cid, Short rf) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.RF, rf)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: выставление strategyId {1} для кампании {0}")
    public void setStrategyId(Long cid, Long strategyId) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.STRATEGY_ID, strategyId)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: выставление rfReset {1} для кампании {0}")
    public void setRfReset(Long cid, Integer rfReset) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.RFRESET, rfReset)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: выставление balance_tid {1} для кампании {0}")
    public void setBalanceTid(Long cid, Long balanceTid) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.BALANCE_TID, balanceTid)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: выставление content_lang {1} для кампании {0}")
    public void setCampOptionsContentLang(Long cid, String contentLang) {
        run(db -> db.update(CAMP_OPTIONS)
                .set(CAMP_OPTIONS.CONTENT_LANG, contentLang)
                .where(CAMP_OPTIONS.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: получение приложения привязанного к кампании cid={0}")
    @Nullable
    public Long getCampaignMobileAppId(Long cid) {
        return exec(db -> db.select(CAMPAIGNS_MOBILE_CONTENT.MOBILE_APP_ID)
                .from(CAMPAIGNS_MOBILE_CONTENT)
                .where(CAMPAIGNS_MOBILE_CONTENT.CID.eq(cid))
                .fetchOne(CAMPAIGNS_MOBILE_CONTENT.MOBILE_APP_ID)
        );
    }

    @Step("DB: привязка мобильного приложения mobileAppId={1} к кампании cid={0}")
    public void setCampaignMobileAppId(Long cid, Long mobileAppId) {
        exec(db -> db.insertInto(CAMPAIGNS_MOBILE_CONTENT)
                .set(CAMPAIGNS_MOBILE_CONTENT.CID, cid)
                .set(CAMPAIGNS_MOBILE_CONTENT.MOBILE_APP_ID, mobileAppId)
                .onDuplicateKeyUpdate()
                .set(CAMPAIGNS_MOBILE_CONTENT.MOBILE_APP_ID, mobileAppId)
                .execute()
        );
    }

    @Step("DB: отвязать от кампании cid={0} привязанное мобильное приложение")
    public void unsetCampaignMobileAppId(Long cid) {
        exec(db -> db.update(CAMPAIGNS_MOBILE_CONTENT)
                .set(CAMPAIGNS_MOBILE_CONTENT.MOBILE_APP_ID, 0L)
                .where(CAMPAIGNS_MOBILE_CONTENT.CID.eq(cid))
                .execute()
        );
    }

    @Step("DB: отвязать мобильное приложение mobileAppId={0} от всех кампаний клиента clientId={1}")
    public void unsetCampaignsMobileAppId(Long mobileAppId, Long clientId) {
        exec(db -> db.update(CAMPAIGNS_MOBILE_CONTENT)
                .set(CAMPAIGNS_MOBILE_CONTENT.MOBILE_APP_ID, 0L)
                .where(CAMPAIGNS_MOBILE_CONTENT.CID.in(db.select(CAMPAIGNS.CID)
                        .from(CAMPAIGNS)
                        .where(CAMPAIGNS.CLIENTID.eq(clientId))
                        .and(CAMPAIGNS.TYPE.eq(CampaignsType.mobile_content)))
                )
                .and(CAMPAIGNS_MOBILE_CONTENT.MOBILE_APP_ID.eq(mobileAppId))
                .execute()
        );
    }

    @Step("DB: Получение записи из таблицы campaigns_mobile_content для cid={0}")
    public CampaignsMobileContentRecord getCampaignsMobileContent(Long campaignId) {
        return exec(db -> db.selectFrom(CAMPAIGNS_MOBILE_CONTENT)
                .where(CAMPAIGNS_MOBILE_CONTENT.CID.eq(campaignId))
                .fetchOne()
        );
    }

    @Step("DB: Обновление записи в таблице campaigns_mobile_content")
    public void updateCampaignsMobileContent(CampaignsMobileContentRecord campaignsMobileContent) {
        run(db -> db.update(CAMPAIGNS_MOBILE_CONTENT)
                .set(campaignsMobileContent)
                .where(CAMPAIGNS_MOBILE_CONTENT.CID.eq(campaignsMobileContent.getCid()))
                .execute()
        );
    }

    @Step("DB: получение площадок для кампании cid={0}")
    @Nullable
    public String getCampaignCpmYndxFrontpageAllowedTypes(Long cid) {
        return exec(db -> db.select(CAMPAIGNS_CPM_YNDX_FRONTPAGE.ALLOWED_FRONTPAGE_TYPES)
                .from(CAMPAIGNS_CPM_YNDX_FRONTPAGE)
                .where(CAMPAIGNS_CPM_YNDX_FRONTPAGE.CID.eq(cid))
                .fetchOne(CAMPAIGNS_CPM_YNDX_FRONTPAGE.ALLOWED_FRONTPAGE_TYPES)
        );
    }

    @Step("DB: сохранение площадок для кампании cid={0}")
    public void setCampaignCpmYndxFrontpageAllowedTypes(Long cid, String allowedFrontpageTypes) {
        exec(db -> db.insertInto(CAMPAIGNS_CPM_YNDX_FRONTPAGE)
                .set(CAMPAIGNS_CPM_YNDX_FRONTPAGE.CID, cid)
                .set(CAMPAIGNS_CPM_YNDX_FRONTPAGE.ALLOWED_FRONTPAGE_TYPES, allowedFrontpageTypes)
                .onDuplicateKeyUpdate()
                .set(CAMPAIGNS_CPM_YNDX_FRONTPAGE.ALLOWED_FRONTPAGE_TYPES, allowedFrontpageTypes)
                .execute()
        );
    }

    @Step("DB: Получение записи из таблицы campaigns_cpm_yndx_frontpage для cid={0}")
    public CampaignsCpmYndxFrontpageRecord getCampaignCpmYndxFrontpage(Long campaignId) {
        return exec(db -> db.selectFrom(CAMPAIGNS_CPM_YNDX_FRONTPAGE)
                .where(CAMPAIGNS_CPM_YNDX_FRONTPAGE.CID.eq(campaignId))
                .fetchOne()
        );
    }

    @Step("DB: Обновление записи в таблице campaigns_cpm_yndx_frontpage")
    public void updateCampaignCpmYndxFrontpage(CampaignsCpmYndxFrontpageRecord campaignCpmYndxFrontpage) {
        run(db -> db.update(CAMPAIGNS_CPM_YNDX_FRONTPAGE)
                .set(campaignCpmYndxFrontpage)
                .where(CAMPAIGNS_CPM_YNDX_FRONTPAGE.CID.eq(campaignCpmYndxFrontpage.getCid()))
                .execute()
        );
    }

    @Step
    public CampaignsCpmPriceRecord getCampaignsCpmPriceById(Long cid) {
        return exec(db -> db.selectFrom(CAMPAIGNS_CPM_PRICE)
                .where(CAMPAIGNS_CPM_PRICE.CID.eq(cid))
                .fetchOne()
        );
    }

    @Step("DB: сохранение статусов прайсовой кампании cid={0}, statusApprove={1}, statusCorrect={2}")
    public void setCampaignCpmPriceStatuses(Long cid, CampaignsCpmPriceStatusApprove statusApprove,
                                                        CampaignsCpmPriceStatusCorrect statusCorrect) {
        exec(db -> db.insertInto(CAMPAIGNS_CPM_PRICE)
                .set(CAMPAIGNS_CPM_PRICE.CID, cid)
                .set(CAMPAIGNS_CPM_PRICE.PACKAGE_ID, 1L)
                .set(CAMPAIGNS_CPM_PRICE.ORDER_VOLUME, 1L)
                .set(CAMPAIGNS_CPM_PRICE.TARGETINGS_SNAPSHOT, "{\"viewTypes\" : [\"NEW_TAB\"]}")
                .set(CAMPAIGNS_CPM_PRICE.STATUS_APPROVE, statusApprove)
                .set(CAMPAIGNS_CPM_PRICE.STATUS_CORRECT, statusCorrect)
                .onDuplicateKeyUpdate()
                .set(CAMPAIGNS_CPM_PRICE.STATUS_APPROVE, statusApprove)
                .set(CAMPAIGNS_CPM_PRICE.STATUS_CORRECT, statusCorrect)
                .execute()
        );
    }

    @Step("DB: Обновление записи в таблице campaigns_cpm_yndx_frontpage")
    public void updateCampaignCpmPrice(CampaignsCpmPriceRecord campaignCpmYndxPrice) {
        run(db -> db.update(CAMPAIGNS_CPM_PRICE)
                .set(campaignCpmYndxPrice)
                .where(CAMPAIGNS_CPM_PRICE.CID.eq(campaignCpmYndxPrice.getCid()))
                .execute()
        );
    }

    @Step("DB: привязка диалога skill_id={2}/bot_guid={3}/name={4}/is_active={5} к кампании cid={1} и клиенту clientId={0}")
    public void setDialog(Long clientId, Long cid, String skill_id, String bot_guid, String name, Boolean is_active) {
        Long dialogId = autoIncSteps().getNewClientDialogId();
        exec(db -> db.insertInto(CAMP_DIALOGS)
                .set(CAMP_DIALOGS.CID, cid)
                .set(CAMP_DIALOGS.CLIENT_DIALOG_ID, dialogId)
                .execute()
        );
        exec(db -> db.insertInto(CLIENT_DIALOGS)
                .set(CLIENT_DIALOGS.CLIENTID, clientId)
                .set(CLIENT_DIALOGS.CLIENT_DIALOG_ID, dialogId)
                .set(CLIENT_DIALOGS.SKILL_ID, skill_id)
                .set(CLIENT_DIALOGS.BOT_GUID, bot_guid)
                .set(CLIENT_DIALOGS.NAME, name)
                .set(CLIENT_DIALOGS.IS_ACTIVE, is_active ? 1 : 0)
                .set(CLIENT_DIALOGS.LAST_SYNC_TIME, Timestamp.valueOf(LocalDateTime.now()))
                .onDuplicateKeyUpdate()
                .set(CLIENT_DIALOGS.CLIENT_DIALOG_ID, dialogId)
                .set(CLIENT_DIALOGS.BOT_GUID, bot_guid)
                .set(CLIENT_DIALOGS.NAME, name)
                .set(CLIENT_DIALOGS.IS_ACTIVE, is_active ? 1 : 0)
                .set(CLIENT_DIALOGS.LAST_SYNC_TIME, Timestamp.valueOf(LocalDateTime.now()))
                .execute()
        );
    }

    @Step("DB: выставление источника {1} для кампании {0}")
    public void setSource(long cid, CampaignsSource source) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.SOURCE, source)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }

    public void makeCampaignReadyForDelete(Long cid, boolean keepType) {
        run(db -> {
            UpdateSetMoreStep<CampaignsRecord> step = db.update(CAMPAIGNS)
                    .set(CAMPAIGNS.STATUSEMPTY, CampaignsStatusempty.No)
                    .set(CAMPAIGNS.SUM, BigDecimal.ZERO)
                    .set(CAMPAIGNS.SUM_SPENT, BigDecimal.ZERO)
                    .set(CAMPAIGNS.SUM_TO_PAY, BigDecimal.ZERO)
                    .set(CAMPAIGNS.SUM_LAST, BigDecimal.ZERO)
                    .set(CAMPAIGNS.SHOWS, 0L)
                    .set(CAMPAIGNS.CLICKS, 0L)
                    .set(CAMPAIGNS.ORDERID, 0L)
                    .set(CAMPAIGNS.STATUSACTIVE, CampaignsStatusactive.No)
                    .set(CAMPAIGNS.STATUSBSSYNCED, CampaignsStatusbssynced.No)
                    .set(CAMPAIGNS.STATUSMODERATE, CampaignsStatusmoderate.No)
                    .set(CAMPAIGNS.ARCHIVED, CampaignsArchived.No)
                    .set(CAMPAIGNS.CURRENCYCONVERTED, CampaignsCurrencyconverted.No);
            if (!keepType) {
                step.set(CAMPAIGNS.TYPE, CampaignsType.text);
            }
            // в оригинале было different_places — но такой уже нету :)
            step.set(CAMPAIGNS.STRATEGY_NAME, CampaignsStrategyName.default_)
                    .where(CAMPAIGNS.CID.eq(cid))
                    .execute();
                }
        );
    }

    @Step("DB: сохранение кц для кампании cid={0}")
    public void setCampaignMeaningfulGoals(Long cid, String meaningfulGoals) {
        exec(db -> db.insertInto(CAMP_OPTIONS)
                .set(CAMP_OPTIONS.CID, cid)
                .set(CAMP_OPTIONS.CONTACTINFO, "")
                .onDuplicateKeyUpdate()
                .set(CAMP_OPTIONS.MEANINGFUL_GOALS, meaningfulGoals)
                .execute()
        );
    }

    @Step("DB: установка Metatype = {1} в таблице ppc.campaigns для cid = {0}")
    public void setCampaignMetaType(Long cid, CampaignsMetatype metatype) {
        run(db -> db.update(CAMPAIGNS)
                .set(CAMPAIGNS.METATYPE, metatype)
                .where(CAMPAIGNS.CID.eq(cid))
                .execute()
        );
    }
}
