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

import org.springframework.stereotype.Service
import ru.yandex.direct.core.entity.mobileapp.model.MobileConversions
import ru.yandex.direct.core.entity.mobileapp.repository.MobileAppConversionStatisticRepository
import ru.yandex.direct.core.entity.uac.model.AppInfo
import ru.yandex.direct.core.entity.uac.model.TrackingSystem
import ru.yandex.direct.core.entity.uac.model.TrackingUrl
import ru.yandex.direct.core.entity.uac.repository.ydb.UacYdbTrackerUrlStatRepository
import ru.yandex.direct.core.entity.uac.repository.ydb.model.TrackerAppEvent
import ru.yandex.direct.core.entity.uac.repository.ydb.model.UacTrackerUrlStat
import ru.yandex.direct.utils.model.UrlParts
import ru.yandex.direct.web.entity.uac.model.AggregatedTrackingUrlStat
import ru.yandex.direct.web.entity.uac.model.YesNoUndefined

@Service
class UacTrackingUrlStatService(
    private val uacYdbTrackerUrlStatRepository: UacYdbTrackerUrlStatRepository,
    private val mobileAppConversionStatisticRepository: MobileAppConversionStatisticRepository
) {
    companion object {
        private val APP_TRACKER_ID_BY_TRACKING_SYSTEM: Map<TrackingSystem, List<Long>> = mapOf(
            TrackingSystem.ADJUST to listOf(3),
            TrackingSystem.APPMETRICA to listOf(64),
            TrackingSystem.APPSFLYER to listOf(4),
            TrackingSystem.FLURRY to listOf(6),
            TrackingSystem.KOCHAVA to listOf(7),
            TrackingSystem.SINGULAR to listOf(71),
            TrackingSystem.MY_TRACKER to listOf(58, 75),
            TrackingSystem.TUNE to listOf(27),
            TrackingSystem.BRANCH to listOf(53),
        )
    }

    fun getAggregatedStat(
        trackingUrl: TrackingUrl,
        appInfo: AppInfo,
        daysNumber: Int
    ): AggregatedTrackingUrlStat {
        val trackerUrl: String = removeParamsAndAnchor(trackingUrl.urlParts).toUrl()
        val uacTrackerUrlStat: UacTrackerUrlStat? = uacYdbTrackerUrlStatRepository.getTrackerUrlStat(
            trackerUrl, daysNumber
        )
        val conversionStat: MobileConversions? = mobileAppConversionStatisticRepository.getCommonConversionStats(
            appInfo.bundleId!!, appInfo.platform.name.lowercase(), toAppTrackerIds(trackingUrl), daysNumber
        )
        return buildAggregatedStat(uacTrackerUrlStat, conversionStat)
    }

    private fun removeParamsAndAnchor(urlParts: UrlParts) =
        urlParts.toBuilder()
            .withParameters(null)
            .withAnchor(null)
            .build()

    private fun toAppTrackerIds(trackingUrl: TrackingUrl): List<Long> {
        return APP_TRACKER_ID_BY_TRACKING_SYSTEM[trackingUrl.system] ?: listOf()
    }

    private fun buildAggregatedStat(
        uacTrackerUrlStat: UacTrackerUrlStat?,
        mobileConversions: MobileConversions?
    ) = AggregatedTrackingUrlStat(
        anyUrlEvents = when(uacTrackerUrlStat) {
            null -> YesNoUndefined.UNDEFINED
            else -> getYesNoUndefinedFromRatio(
                uacTrackerUrlStat.conversionsByEvent.values.sum(), uacTrackerUrlStat.hitCount
            )
        },
        urlEvents = when(uacTrackerUrlStat) {
            null -> TrackerAppEvent.values().associateWith { YesNoUndefined.UNDEFINED }
            else -> uacTrackerUrlStat.conversionsByEvent.mapValues {
                getYesNoUndefinedFromRatio(it.value, uacTrackerUrlStat.hitCount)
            }
        },
        anyPackageEvents = when(mobileConversions) {
            null -> YesNoUndefined.UNDEFINED
            else -> if (mobileConversions.attributedConversions > 0) YesNoUndefined.YES else YesNoUndefined.UNDEFINED
        },
        allPackageEvents = when(mobileConversions) {
            null -> YesNoUndefined.NO
            else -> if (mobileConversions.notAttributedConversions > 0) YesNoUndefined.YES else YesNoUndefined.NO
        }
    )

    private fun getYesNoUndefinedFromRatio(applicable: Long, all: Long): YesNoUndefined {
        if (applicable > 0) {
            return YesNoUndefined.YES
        } else if (all > 0) {
            return YesNoUndefined.NO
        }
        return YesNoUndefined.UNDEFINED
    }
}
