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

import org.springframework.stereotype.Service
import ru.yandex.direct.core.entity.uac.UacCommonUtils.mapFromJson
import ru.yandex.direct.core.entity.uac.getAvatarsThumbSize
import ru.yandex.direct.core.entity.uac.model.CreativeType
import ru.yandex.direct.core.entity.uac.model.MediaType
import ru.yandex.direct.core.entity.uac.model.UacAvatarsResponseInfo
import ru.yandex.direct.core.entity.uac.repository.ydb.model.UacYdbContent
import ru.yandex.direct.core.entity.uac.service.UacAvatarsService
import ru.yandex.direct.core.entity.user.model.User
import ru.yandex.direct.result.Result
import ru.yandex.direct.utils.JsonUtils
import ru.yandex.direct.web.entity.uac.model.DirectImageInfo
import ru.yandex.direct.core.entity.uac.model.FileData
import ru.yandex.direct.core.entity.uac.operation.UacUploadImageByUrlToAvatarsOperation
import ru.yandex.direct.web.entity.uac.converter.DirectMdsMetaFilter.toDirectMdsMeta
import ru.yandex.direct.web.entity.uac.model.MetaFilter
import ru.yandex.direct.web.entity.uac.operation.UacUploadImageByThumbToAvatarsOperation
import ru.yandex.direct.web.entity.uac.operation.UacUploadImageToAvatarsOperation

@Service
class UacImageContentUploader(
    private val uacAvatarsService: UacAvatarsService,
    private val uacDirectImageUploader: UacDirectImageUploader,
    private val uacPropertiesService: UacPropertiesService,
) {
    fun uploadFromUrl(
        subjectUser: User, accountId: String,
        url: String, creativeType: CreativeType,
    ): Result<UacYdbContent> {
        return ByUrlUploader(subjectUser, accountId, url, creativeType).upload()
    }

    fun uploadFromThumb(
        subjectUser: User, accountId: String,
        thumb: String, creativeType: CreativeType
    ): Result<UacYdbContent> {
        return ByThumbUploader(subjectUser, accountId, thumb, creativeType).upload()
    }

    fun uploadFromFile(
            subjectUser: User, accountId: String,
            file: FileData, creativeType: CreativeType
    ): Result<UacYdbContent> {
        return ByFileUploader(subjectUser, accountId, file, creativeType).upload()
    }

    abstract inner class BaseUploader(
        private val subjectUser: User,
        private val accountId: String,
        private val creativeType: CreativeType,
    ) {
        private val metaFilter = MetaFilter()
        private lateinit var avatarInfo: UacAvatarsResponseInfo
        private lateinit var thumbSize: String
        private lateinit var thumbUrl: String
        private lateinit var directImageInfo: DirectImageInfo

        fun upload(): Result<UacYdbContent> {
            val uploadImageToAvatarsResult = uploadImageToAvatars()
            if (!uploadImageToAvatarsResult.isSuccessful) {
                return Result.broken(uploadImageToAvatarsResult.validationResult)
            }
            avatarInfo = uploadImageToAvatarsResult.result
            thumbSize = if (creativeType == CreativeType.RMP && uacPropertiesService.enableOrigThumb) "orig"
            else getAvatarsThumbSize(avatarInfo)
            thumbUrl = getThumbUrl()

            val uploadImageToDirectResult = uploadAvatarsImageToDirect()
            if (!uploadImageToDirectResult.isSuccessful) {
                return Result.broken(uploadImageToDirectResult.validationResult)
            }
            directImageInfo = uploadImageToDirectResult.result


            return Result.successful(
                fillUacYdbContent()
            )
        }

        protected abstract fun uploadImageToAvatars(): Result<UacAvatarsResponseInfo>

        private fun uploadAvatarsImageToDirect(): Result<DirectImageInfo> {
            return uacDirectImageUploader.upload(subjectUser, thumbUrl)
        }

        private fun fillUacYdbContent(): UacYdbContent {
            return UacYdbContent(
                ownerId = accountId,
                type = MediaType.IMAGE,
                thumb = thumbUrl,
                sourceUrl = getSourceUrl() ?: thumbUrl,
                mdsUrl = null,
                meta = fillContentMeta(),
                videoDuration = null,
                filename = getFilename(),
                accountId = accountId,
                directImageHash = directImageInfo.imageHash,
            )
        }

        protected open fun getSourceUrl(): String? {
            return null
        }

        protected open fun getFilename(): String? {
            return null
        }

        private fun getThumbUrl(): String {
            return uacAvatarsService.getReadUrl(avatarInfo, thumbSize)
        }

        private fun fillContentMeta(): Map<String, Any?> {
            val meta: MutableMap<String, Any?> = metaFilter.filter(avatarInfo.uacAvatarsMeta, avatarInfo.sizes).toMutableMap()
            meta["direct_image_hash"] = directImageInfo.imageHash
            meta["direct_mds_meta"] = mapFromJson(JsonUtils.toJson(toDirectMdsMeta(directImageInfo)))
            meta["avatars_thumb_size"] = thumbSize
            return meta
        }
    }

    inner class ByFileUploader(
            private val subjectUser: User,
            private val accountId: String,
            private val file: FileData,
            private val creativeType: CreativeType,
    ): BaseUploader(subjectUser, accountId, creativeType) {
        override fun uploadImageToAvatars(): Result<UacAvatarsResponseInfo> {
            return UacUploadImageToAvatarsOperation(uacAvatarsService, file.data).prepareAndApplyWithCheck()
        }

        override fun getFilename(): String? {
            return file.name
        }
    }

    open inner class ByUrlUploader(
        private val subjectUser: User,
        private val accountId: String,
        private val url: String,
        private val creativeType: CreativeType,
    ): BaseUploader(subjectUser, accountId, creativeType) {
        override fun uploadImageToAvatars(): Result<UacAvatarsResponseInfo> {
            return UacUploadImageByUrlToAvatarsOperation(uacAvatarsService, url).prepareAndApplyWithCheck()
        }

        override fun getSourceUrl(): String {
            return url
        }
    }

    open inner class ByThumbUploader(
        private val subjectUser: User,
        private val accountId: String,
        private val url: String,
        private val creativeType: CreativeType,
    ): BaseUploader(subjectUser, accountId, creativeType) {
        override fun uploadImageToAvatars(): Result<UacAvatarsResponseInfo> {
            return UacUploadImageByThumbToAvatarsOperation(uacAvatarsService, url).prepareAndApplyWithCheck()
        }

        override fun getSourceUrl(): String {
            return url
        }
    }
}
