package dev.inmo.postssystem.services.posts.client

import dev.inmo.micro_utils.common.*
import dev.inmo.micro_utils.ktor.client.UnifiedRequester
import dev.inmo.micro_utils.ktor.common.buildStandardUrl
import dev.inmo.micro_utils.ktor.common.encodeHex
import dev.inmo.micro_utils.repos.ktor.common.crud.createRouting
import dev.inmo.micro_utils.repos.ktor.common.crud.updateRouting
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.removeRoute
import dev.inmo.postssystem.features.common.common.FileBasedInputProvider
import dev.inmo.postssystem.features.common.common.SimpleInputProvider
import dev.inmo.postssystem.features.content.common.*
import dev.inmo.postssystem.features.posts.common.PostId
import dev.inmo.postssystem.features.posts.common.RegisteredPost
import dev.inmo.postssystem.services.posts.common.*
import io.ktor.client.request.forms.InputProvider
import io.ktor.client.request.forms.formData
import io.ktor.client.request.headers
import io.ktor.client.request.post
import io.ktor.http.HttpHeaders
import kotlinx.serialization.builtins.*
import kotlinx.serialization.modules.polymorphic

class ClientWritePostsService(
    private val baseUrl: String,
    unifiedRequester: UnifiedRequester
) : WritePostsService {
    private val root = buildStandardUrl(baseUrl, postsRootPath)
    private val unifiedRequester = UnifiedRequester(
        unifiedRequester.client,
        unifiedRequester.serialFormat.createWithSerializerModuleExtension {
            polymorphic(Content::class) {
                subclass(BinaryContent::class, BinaryContentSerializer(TempFileIdentifierInputProvider::class, TempFileIdentifierInputProvider.serializer()))
            }
        }
    )

    private val contentEitherSerializer = EitherSerializer(ContentId.serializer(), ContentSerializer)
    private val contentsEitherSerializer = ListSerializer(contentEitherSerializer)
    private val contentsSerializer = ListSerializer(ContentSerializer)

    private val createFullPath = buildStandardUrl(
        root,
        createRouting
    )
    private val removeFullPath = buildStandardUrl(
        root,
        removeRoute
    )
    private val tempUploadFullPath = buildStandardUrl(
        root,
        postsCreateTempPathPart
    )

    private suspend fun prepareContent(content: Content): Content? {
        return (content as? BinaryContent) ?.let {
            when (val provider = it.inputProvider) {
                is FileBasedInputProvider -> {
                    val fileId = unifiedRequester.tempUpload(
                        tempUploadFullPath,
                        provider.file
                    )
                    println(fileId)
                    it.copy(inputProvider = TempFileIdentifierInputProvider(fileId))
                }
                is TempFileIdentifierInputProvider -> it
                else -> return@prepareContent null
            }
        } ?: content
    }

    override suspend fun create(newPost: FullNewPost): RegisteredPost? {
        val mappedContent = newPost.content.mapNotNull {
            prepareContent(it)
        }
        val mappedPost = newPost.copy(
            content = mappedContent
        )
        return unifiedRequester.unipost(
            createFullPath,
            contentsSerializer to mappedPost.content,
            RegisteredPost.serializer().nullable
        )
    }

    override suspend fun update(
        postId: PostId,
        content: List<Either<ContentId, Content>>
    ): RegisteredPost? {
        val mappedContent = content.mapNotNull {
            it.mapOnSecond { content ->
                prepareContent(content) ?.either() ?: return@mapNotNull null
            } ?: it
        }
        return unifiedRequester.unipost(
            buildStandardUrl(
                root,
                updateRouting,
                postsPostIdParameter to unifiedRequester.encodeUrlQueryValue(PostId.serializer(), postId)
            ),
            contentsEitherSerializer to mappedContent,
            RegisteredPost.serializer().nullable
        )
    }

    override suspend fun remove(postId: PostId) = unifiedRequester.unipost(
        removeFullPath,
        PostId.serializer() to postId,
        Unit.serializer()
    )
}
