package ru.yandex.direct.api.v5.entity.campaigns.validation

import com.yandex.direct.api.v5.campaigns.CampaignAddItem
import com.yandex.direct.api.v5.campaigns.StrategyCpAverageCpvAdd
import com.yandex.direct.api.v5.campaigns.StrategyCpDecreasedPriceForRepeatedImpressionsAdd
import com.yandex.direct.api.v5.campaigns.StrategyCpMaximumImpressionsAdd
import ru.yandex.direct.api.v5.entity.campaigns.CampaignDefectTypes
import ru.yandex.direct.api.v5.entity.campaigns.validation.CampaignsCommonRequestValidator.dateFormatValid
import ru.yandex.direct.api.v5.entity.campaigns.validation.CampaignsCommonRequestValidator.dateIsEmpty
import ru.yandex.direct.api.v5.entity.campaigns.validation.CampaignsCommonRequestValidator.timeFormatValid
import ru.yandex.direct.api.v5.validation.DefectType
import ru.yandex.direct.api.v5.validation.DefectTypes.badParamsInvalidFormat
import ru.yandex.direct.api.v5.validation.DefectTypes.emptyValue
import ru.yandex.direct.api.v5.validation.DefectTypes.invalidFormat
import ru.yandex.direct.api.v5.validation.validateObject
import ru.yandex.direct.core.entity.timetarget.model.GeoTimezone
import ru.yandex.direct.validation.builder.When
import ru.yandex.direct.validation.result.ValidationResult

/**
 * Валидирует данные за рамками структур "TextCampaign", "CpmBannerCampaign" etc. (в основном это дефекты
 * общие для всех типов кампаний).
 */
fun validateCampaignAddItemCommonDefects(
    campaignAddItem: CampaignAddItem,
    timeZones: Map<String, GeoTimezone>
): ValidationResult<CampaignAddItem, DefectType> =
    validateObject(campaignAddItem) {
        check(::duplicatesInBlockedIps)
        check(::duplicatesInNegativeKeywords)
        check { CampaignsRequestValidator.timeZoneDoesntExist(it, timeZones) }
        check(::timeTargetingDayOfTheWeekOutOfRange)
        check(::timeTargetingDayOfTheWeekHasDuplicates, When.isValid())
        check(::timeTargetingBidsIncomplete, When.isValid())
        check(::timeTargetingBidsAreNotIntegers, When.isValid())
        check(::timeTargetingBidsMustNotBeNegative, When.isValid())
        check(::timeTargetingBidsInCpmBannerCampaignMustBeOnOrOff, When.isValid())
        check(::timeTargetingBidsMustDevideTen, When.isValid())
        check(::timeTargetingBidsOutOfRange, When.isValid())
        check(::holidaysScheduleCantContainStartHourWhenSuspendOnHolidaysYes)
        check(::holidaysScheduleCantContainEndHourWhenSuspendOnHolidaysYes)
        check(::holidaysScheduleCantContainBidPercentWhenSuspendOnHolidaysYes)
        check(::holidayBidPercentMustBeOneHundredInCpmBannerCampaign)
        check(::holidayBidPercentOutOfRange)
        check(::holidayBidPercentMustDevideTen)
        check(::startHourAndEndHourMustBeSetWhenSuspendOnHolidaysNotYes)
        check(::startHourMustBeLessThanEndHour)
        check(::startHourOutOfRange)
        check(::endHourOutOfRange)
        check(::negativeKeywordsAreNotAllowedInCpmBannerCampaign)
        check(::dayBudgetAmountMustBePositiveAndNotLessThan)
        check(::startDateIsNotEmpty)
        check(::endDateIsNotEmpty)
        check(::startDateFormatValid)
        check(::endDateFormatValid)
        check(::timeFromFormatValid)
        check(::timeToFormatValid)
        check(::checkPositionIntervalValid)
    }

fun timeTargetingDayOfTheWeekOutOfRange(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.timeTargetingDayOfTheWeekOutOfRange(item.timeTargeting?.schedule)

fun timeTargetingDayOfTheWeekHasDuplicates(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.timeTargetingDayOfTheWeekHasDuplicates(item.timeTargeting?.schedule)

fun timeTargetingBidsIncomplete(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.timeTargetingBidsIncomplete(item.timeTargeting?.schedule)

fun timeTargetingBidsMustNotBeNegative(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.timeTargetingBidsMustNotBeNegative(item.timeTargeting?.schedule)

fun timeTargetingBidsInCpmBannerCampaignMustBeOnOrOff(item: CampaignAddItem): DefectType? {
    if (item.cpmBannerCampaign == null) {
        return null
    }
    return CampaignsCommonRequestValidator.timeTargetingBidsInCpmBannerCampaignMustBeOnOrOff(item.timeTargeting?.schedule)
}

fun timeTargetingBidsMustDevideTen(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.timeTargetingBidsMustDevideTen(item.timeTargeting?.schedule)

fun timeTargetingBidsOutOfRange(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.timeTargetingBidsOutOfRange(item.timeTargeting?.schedule)

fun timeTargetingBidsAreNotIntegers(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.timeTargetingBidsAreNotIntegers(item.timeTargeting?.schedule)

fun holidaysScheduleCantContainStartHourWhenSuspendOnHolidaysYes(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.holidaysScheduleCantContainStartHourWhenSuspendOnHolidaysYes(item.timeTargeting?.holidaysSchedule)

fun holidaysScheduleCantContainEndHourWhenSuspendOnHolidaysYes(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.holidaysScheduleCantContainEndHourWhenSuspendOnHolidaysYes(item.timeTargeting?.holidaysSchedule)

fun holidaysScheduleCantContainBidPercentWhenSuspendOnHolidaysYes(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.holidaysScheduleCantContainBidPercentWhenSuspendOnHolidaysYes(item.timeTargeting?.holidaysSchedule)

fun holidayBidPercentMustBeOneHundredInCpmBannerCampaign(item: CampaignAddItem): DefectType? {
    if (item.cpmBannerCampaign == null) {
        return null
    }
    return CampaignsCommonRequestValidator.holidayBidPercentMustBeOneHundredInCpmBannerCampaign(item.timeTargeting?.holidaysSchedule)
}

fun holidayBidPercentOutOfRange(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.holidayBidPercentOutOfRange(item.timeTargeting?.holidaysSchedule)

fun holidayBidPercentMustDevideTen(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.holidayBidPercentMustDevideTen(item.timeTargeting?.holidaysSchedule)

fun startHourAndEndHourMustBeSetWhenSuspendOnHolidaysNotYes(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.startHourAndEndHourMustBeSetWhenSuspendOnHolidaysNotYes(item.timeTargeting?.holidaysSchedule)

fun startHourMustBeLessThanEndHour(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.startHourMustBeLessThanEndHour(item.timeTargeting?.holidaysSchedule)

fun startHourOutOfRange(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.startHourOutOfRange(item.timeTargeting?.holidaysSchedule)

fun endHourOutOfRange(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.endHourOutOfRange(item.timeTargeting?.holidaysSchedule)

/**
 * В ядре такой валидации не обнаружено, а в базу попадают дубликаты, поэтому сделали здесь
 */
fun duplicatesInBlockedIps(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.duplicatesIn(item.blockedIps, "BlockedIps")

/**
 * В ядре такой валидации нет, вместо неё дедубликация, сюда добавляем, чтобы показать клиенту проблему
 */
fun duplicatesInNegativeKeywords(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.duplicatesIn(item.negativeKeywords, "NegativeKeywords")

fun negativeKeywordsAreNotAllowedInCpmBannerCampaign(item: CampaignAddItem): DefectType? =
    if (item.cpmBannerCampaign == null || item.negativeKeywords?.items == null) null
    else CampaignDefectTypes.negativeKeywordsAreNotAllowedInCpmBannerCampaign()

fun dayBudgetAmountMustBePositiveAndNotLessThan(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.dayBudgetAmountMustBePositiveAndNotLessThan(item.dailyBudget)

fun startDateIsNotEmpty(item: CampaignAddItem): DefectType? =
    if (dateIsEmpty(item.startDate)) emptyValue("StartDate") else null

fun endDateIsNotEmpty(item: CampaignAddItem): DefectType? =
    if (dateIsEmpty(item.endDate)) emptyValue("EndDate") else null

fun startDateIsNotEmpty(item: StrategyCpDecreasedPriceForRepeatedImpressionsAdd): DefectType? =
    if (dateIsEmpty(item.startDate)) emptyValue("StartDate") else null

fun endDateIsNotEmpty(item: StrategyCpDecreasedPriceForRepeatedImpressionsAdd): DefectType? =
    if (dateIsEmpty(item.endDate)) emptyValue("EndDate") else null

fun startDateIsNotEmpty(item: StrategyCpAverageCpvAdd): DefectType? =
    if (dateIsEmpty(item.startDate)) emptyValue("StartDate") else null

fun endDateIsNotEmpty(item: StrategyCpAverageCpvAdd): DefectType? =
    if (dateIsEmpty(item.endDate)) emptyValue("EndDate") else null

fun startDateIsNotEmpty(item: StrategyCpMaximumImpressionsAdd): DefectType? =
    if (dateIsEmpty(item.startDate)) emptyValue("StartDate") else null

fun endDateIsNotEmpty(item: StrategyCpMaximumImpressionsAdd): DefectType? =
    if (dateIsEmpty(item.endDate)) emptyValue("EndDate") else null

fun startDateFormatValid(item: CampaignAddItem): DefectType? =
    if (dateFormatValid(item.startDate)) null else invalidFormat("StartDate")

fun endDateFormatValid(item: CampaignAddItem): DefectType? =
    if (dateFormatValid(item.endDate)) null else invalidFormat("EndDate")

fun startDateFormatValid(item: StrategyCpDecreasedPriceForRepeatedImpressionsAdd): DefectType? =
    if (dateFormatValid(item.startDate)) null else badParamsInvalidFormat("StartDate")

fun endDateFormatValid(item: StrategyCpDecreasedPriceForRepeatedImpressionsAdd): DefectType? =
    if (dateFormatValid(item.endDate)) null else badParamsInvalidFormat("EndDate")

fun startDateFormatValid(item: StrategyCpAverageCpvAdd): DefectType? =
    if (dateFormatValid(item.startDate)) null else badParamsInvalidFormat("StartDate")

fun endDateFormatValid(item: StrategyCpAverageCpvAdd): DefectType? =
    if (dateFormatValid(item.endDate)) null else badParamsInvalidFormat("EndDate")

fun startDateFormatValid(item: StrategyCpMaximumImpressionsAdd): DefectType? =
    if (dateFormatValid(item.startDate)) null else badParamsInvalidFormat("StartDate")

fun endDateFormatValid(item: StrategyCpMaximumImpressionsAdd): DefectType? =
    if (dateFormatValid(item.endDate)) null else badParamsInvalidFormat("EndDate")

fun timeFromFormatValid(item: CampaignAddItem): DefectType? =
    timeFormatValid(item.notification?.smsSettings?.timeFrom, "TimeFrom")

fun timeToFormatValid(item: CampaignAddItem): DefectType? =
    timeFormatValid(item.notification?.smsSettings?.timeTo, "TimeTo")

fun checkPositionIntervalValid(item: CampaignAddItem): DefectType? =
    CampaignsCommonRequestValidator.checkPositionIntervalValid(item.notification?.emailSettings?.checkPositionInterval)
