package ru.yandex.direct.web.entity.uac.model

import com.fasterxml.jackson.annotation.JsonFormat
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonValue
import com.fasterxml.jackson.databind.PropertyNamingStrategy
import com.fasterxml.jackson.databind.annotation.JsonNaming
import java.math.BigDecimal
import java.time.LocalDateTime
import ru.yandex.direct.core.entity.campaign.model.BrandSurveyStatus
import ru.yandex.direct.core.entity.hypergeo.model.HyperGeo
import ru.yandex.direct.core.entity.uac.model.AdvType
import ru.yandex.direct.core.entity.uac.model.AltAppStore
import ru.yandex.direct.core.entity.uac.model.AppInfo
import ru.yandex.direct.core.entity.uac.model.Content
import ru.yandex.direct.core.entity.uac.model.DeviceType
import ru.yandex.direct.core.entity.uac.model.InventoryType
import ru.yandex.direct.core.entity.uac.model.LimitPeriodType
import ru.yandex.direct.core.entity.uac.model.Sitelink
import ru.yandex.direct.core.entity.uac.model.Socdem
import ru.yandex.direct.core.entity.uac.model.Status
import ru.yandex.direct.core.entity.uac.model.TargetStatus
import ru.yandex.direct.core.entity.uac.model.TargetType
import ru.yandex.direct.core.entity.uac.model.TimeTarget
import ru.yandex.direct.core.entity.uac.model.UacAdjustment
import ru.yandex.direct.core.entity.uac.model.UacFeedFilter
import ru.yandex.direct.core.entity.uac.model.UacGoal
import ru.yandex.direct.core.entity.uac.model.UacRetargetingCondition
import ru.yandex.direct.core.entity.uac.model.UacShowsFrequencyLimit
import ru.yandex.direct.core.entity.uac.model.UacStrategy
import ru.yandex.direct.core.entity.uac.model.UacStrategyPlatform
import ru.yandex.direct.core.entity.uac.model.relevance_match.UacRelevanceMatchCategories
import ru.yandex.direct.core.entity.uac.repository.ydb.UacYdbUtils
import ru.yandex.direct.core.entity.uac.repository.ydb.model.UacBrandsafety
import ru.yandex.direct.core.entity.uac.repository.ydb.model.UacCampaignMeasurer
import ru.yandex.direct.core.entity.uac.repository.ydb.model.UacCpmAsset
import ru.yandex.direct.core.entity.uac.repository.ydb.model.UacDisabledPlaces
import ru.yandex.direct.core.entity.uac.repository.ydb.model.UacSearchLift
import ru.yandex.direct.grid.model.campaign.GdCampaignAccess
import ru.yandex.direct.grid.model.campaign.GdCampaignAction
import ru.yandex.direct.grid.model.campaign.GdCampaignServicedState

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
data class UacCampaign(
    val id: String,
    val accessKt: UacCampaignAccess,
    val agencyInfoKt: UacCampaignAgencyInfo?,
    val managerInfoKt: UacCampaignManagerInfo?,
    val showsKt: Long,
    val sumKt: BigDecimal,
    val displayName: String,
    val advType: AdvType,
    val appInfo: AppInfo?,
    val contents: List<Content>,
    val texts: List<String>?,
    val titles: List<String>?,
    val regions: List<Long>?,
    val regionNames: List<String>?,
    val minusRegions: List<Long>?,
    val minusRegionNames: List<String>?,
    val trackingUrl: String?,
    val impressionUrl: String?,
    val href: String,
    val faviconLink: String?,
    val targetId: TargetType?,
    val weekLimit: BigDecimal?,
    val cpa: BigDecimal?,
    @JsonIgnore
    val createdTime: LocalDateTime,
    @JsonIgnore
    val updatedTime: LocalDateTime,
    @JsonIgnore
    val startedTime: LocalDateTime?,
    val targetStatus: TargetStatus,
    val status: Status,
    val isStatusObsolete: Boolean,
    val extStatus: String?,
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    val directId: Long?,
    val rejectReasons: String?,
    val contentFlags: Map<String, Any>?,
    val stateReasons: List<String>?,
    val limitPeriod: LimitPeriodType?,
    val skadNetworkEnabled: Boolean?,
    val adultContentEnabled: Boolean?,
    val hyperGeo: HyperGeo?,
    val keywords: List<String>?,
    val minusKeywords: List<String>?,
    val socdem: Socdem?,
    val deviceTypes: Set<DeviceType>?,
    val inventoryTypes: Set<InventoryType>?,
    val goals: List<UacGoal>?,
    val counters: List<Int>?,
    val permalinkId: Long?,
    val phoneId: Long?,
    val calltrackingSettingsId: Long?,
    val sitelinks: List<Sitelink>?,
    val timeTarget: TimeTarget?,
    val bid: Long? = null, // Костыль для UC
    val strategy: UacStrategy?,
    val retargetingCondition: UacRetargetingCondition?,
    val videosAreNonSkippable: Boolean?,
    val zenPublisherId: String?,
    val brandSurveyId: String?,
    val brandSurveyName: String?,
    val showsFrequencyLimit: UacShowsFrequencyLimit?,
    val strategyPlatform: UacStrategyPlatform?,
    val brandSurveyStatus: BrandSurveyStatus?,
    val adjustments: List<UacAdjustment>?,
    val isEcom: Boolean?,
    val crr: Long?,
    val feedId: Long?,
    val feedFilters: List<UacFeedFilter>?,
    // Временный флаг для фронта, показывать ли Товарную статистику. Используется только для Ecom, иначе всегда false.
    val showOfferStats: Boolean,
    val trackingParams: String?,
    val cpmAssets: Map<String, UacCpmAsset>?,
    val campaignMeasurers: List<UacCampaignMeasurer>?,
    val uacBrandsafety: UacBrandsafety?,
    val uacDisabledPlaces: UacDisabledPlaces?,
    val isRecommendationsManagementEnabled: Boolean?,
    val isPriceRecommendationsManagementEnabled: Boolean?,
    val showTitleAndBody: Boolean?,
    // Используется только для фронта, для получения данных по выбранным категориям
    val relevanceMatchCategories: UacRelevanceMatchCategories? = null,
    val altAppStores: Set<AltAppStore>? = null,
    val bizLandingId: Long?,
    val searchLift: UacSearchLift?,
) {
    @get:JsonProperty
    private val createdAt: String
        get() = UacYdbUtils.toEpochSecond(createdTime).toString()

    @get:JsonProperty
    private val updatedAt: String
        get() = UacYdbUtils.toEpochSecond(updatedTime).toString()

    @get:JsonProperty
    private val startedAt: String?
        get() = startedTime?.let { UacYdbUtils.toEpochSecond(it) }?.toString()
}

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
data class UacCampaignAccess(
    val canEdit: Boolean,
    val noActions: Boolean,
    val actions: Set<UacCampaignAction>,
    val pseudoActions: Set<UacCampaignAction>,
    val servicedState: UacCampaignServicedState,
) {

    companion object {
        fun fromGdCampaignAccess(access: GdCampaignAccess): UacCampaignAccess =
            UacCampaignAccess(
                actions = access.actions.map { UacCampaignAction.fromGdCampaignAction(it) }.toSet(),
                canEdit = access.canEdit,
                noActions = access.noActions,
                pseudoActions = access.pseudoActions.map { UacCampaignAction.fromGdCampaignAction(it) }.toSet(),
                servicedState = UacCampaignServicedState.fromGdCampaignServicedState(access.servicedState),
            )
    }
}

enum class UacCampaignAction {
    STOP_CAMP,
    SHOW_CAMP_STAT,
    SHOW_CAMP_SETTINGS,
    EDIT_CAMP,
    RESUME_CAMP,
    COPY_CAMP_CLIENT,
    LOOKUP,
    PAY,
    PAY_BY_CASH,
    ARCHIVE_CAMP,
    UNARCHIVE_CAMP,
    DELETE_CAMP,
    SET_AUTO_PRICE,
    AJAX_SET_AUTO_RESOURCES,
    EDIT_METRICA_COUNTERS,
    ACCEPT_SERVICING,
    OFFER_SERVICING,
    SERVICED,
    AGENCY_SERVICED,
    ALLOW_TRANSFER_MONEY_SUBCLIENT,
    OTHER_MANAGER_SERVICED,
    MODERATE_CAMP,
    REMODERATE_CAMP,
    SET_BIDS,
    EXPORT_IN_EXCEL,
    SHOW_BS_LINK,
    CAN_BE_AUTODELETED,
    RESET_FLIGHT_STATUS_APPROVE,
    VIEW_OFFLINE_REPORTS,
    MANAGE_VCARDS,
    BAN_PAY,
    UNBAN_PAY,
    SERVICING_STOPPED,
    REDIRECT_VIEW,
    REDIRECT_EDIT,
    MANAGE_PROMO_EXTENSION,
    DISABLE_WEEKLY_BUDGET,
    EDIT_WEEKLY_BUDGET
    ;

    companion object {
        fun fromGdCampaignAction(state: GdCampaignAction): UacCampaignAction {
            return UacCampaignAction.valueOf(state.name)
        }
    }

    @JsonValue
    open fun getAction() = name.lowercase()
}

enum class UacCampaignServicedState {
    SELF_SERVICED,
    ACCEPT_SERVICING,
    SERVICED,
    ;

    companion object {
        fun fromGdCampaignServicedState(state: GdCampaignServicedState): UacCampaignServicedState {
            return valueOf(state.name)
        }
    }

    @JsonValue
    open fun getServicedState() = name.lowercase()
}

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
data class UacCampaignAgencyInfo(
    val name: String?,
    val email: String?,
    val phone: String?,
    val representativeName: String?,
    val showAgencyContacts: Boolean,
)

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
data class UacCampaignManagerInfo(
    val name: String?,
    val email: String?,
    val contactInfo: List<UacContactPhone>?,
)

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
data class UacContactPhone(
    val phone: String?,
    val extension: Long?,
)
