package com.aiosman.ravenow.entity

import androidx.annotation.DrawableRes
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.aiosman.ravenow.data.ListContainer
import com.aiosman.ravenow.data.MomentService
import com.aiosman.ravenow.data.ServiceException
import com.aiosman.ravenow.data.UploadImage
import com.aiosman.ravenow.data.api.AgentMomentRequestBody
import com.aiosman.ravenow.data.api.ApiClient
import com.aiosman.ravenow.data.parseErrorResponse
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import java.io.IOException
import java.util.Date

/**
 * 动态分页加载器
 */
class MomentPagingSource(
    private val remoteDataSource: MomentRemoteDataSource,
    private val author: Int? = null,
    private val timelineId: Int? = null,
    private val contentSearch: String? = null,
    private val trend: Boolean? = false,
    private val explore: Boolean? = false,
    private val favoriteUserId: Int? = null
) : PagingSource<Int, MomentEntity>() {
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MomentEntity> {
        return try {
            val currentPage = params.key ?: 1
            val moments = remoteDataSource.getMoments(
                pageNumber = currentPage,
                author = author,
                timelineId = timelineId,
                contentSearch = contentSearch,
                trend = trend,
                explore = explore,
                favoriteUserId = favoriteUserId
            )

            LoadResult.Page(
                data = moments.list,
                prevKey = if (currentPage == 1) null else currentPage - 1,
                nextKey = if (moments.list.isEmpty()) null else moments.page + 1
            )
        } catch (exception: IOException) {
            return LoadResult.Error(exception)
        }
    }

    override fun getRefreshKey(state: PagingState<Int, MomentEntity>): Int? {
        return state.anchorPosition
    }

}

class MomentRemoteDataSource(
    private val momentService: MomentService,
) {
    suspend fun getMoments(
        pageNumber: Int,
        author: Int?,
        timelineId: Int?,
        contentSearch: String?,
        trend: Boolean?,
        explore: Boolean?,
        favoriteUserId: Int?
    ): ListContainer<MomentEntity> {
        return momentService.getMoments(
            pageNumber = pageNumber,
            author = author,
            timelineId = timelineId,
            contentSearch = contentSearch,
            trend = trend,
            explore = explore,
            favoriteUserId = favoriteUserId
        )
    }
}

class MomentServiceImpl() : MomentService {
    val momentBackend = MomentBackend()

    override suspend fun getMoments(
        pageNumber: Int,
        author: Int?,
        timelineId: Int?,
        contentSearch: String?,
        trend: Boolean?,
        explore: Boolean?,
        favoriteUserId: Int?,
    ): ListContainer<MomentEntity> {
        return momentBackend.fetchMomentItems(
            pageNumber = pageNumber,
            author = author,
            timelineId = timelineId,
            contentSearch = contentSearch,
            trend = trend,
            favoriteUserId = favoriteUserId,
            explore = explore
        )
    }

    override suspend fun getMomentById(id: Int): MomentEntity {
        return momentBackend.getMomentById(id)
    }


    override suspend fun likeMoment(id: Int) {
        momentBackend.likeMoment(id)
    }

    override suspend fun dislikeMoment(id: Int) {
        momentBackend.dislikeMoment(id)
    }

    override suspend fun createMoment(
        content: String,
        authorId: Int,
        images: List<UploadImage>,
        relPostId: Int?
    ): MomentEntity {
        return momentBackend.createMoment(content, authorId, images, relPostId)
    }

    override suspend fun agentMoment(content: String): String {
        return momentBackend.agentMoment(content)
    }

    override suspend fun favoriteMoment(id: Int) {
        momentBackend.favoriteMoment(id)
    }

    override suspend fun unfavoriteMoment(id: Int) {
        momentBackend.unfavoriteMoment(id)
    }

    override suspend fun deleteMoment(id: Int) {
        momentBackend.deleteMoment(id)
    }

}

class MomentBackend {
    val DataBatchSize = 20
    suspend fun fetchMomentItems(
        pageNumber: Int,
        author: Int? = null,
        timelineId: Int?,
        contentSearch: String?,
        trend: Boolean?,
        explore: Boolean?,
        favoriteUserId: Int? = null
    ): ListContainer<MomentEntity> {
        val resp = ApiClient.api.getPosts(
            pageSize = DataBatchSize,
            page = pageNumber,
            timelineId = timelineId,
            authorId = author,
            contentSearch = contentSearch,
            trend = if (trend == true) "true" else "",
            favouriteUserId = favoriteUserId,
            explore = if (explore == true) "true" else ""
        )
        val body = resp.body() ?: throw ServiceException("Failed to get moments")
        return ListContainer(
            total = body.total,
            page = pageNumber,
            pageSize = DataBatchSize,
            list = body.list.map { it.toMomentItem() }
        )
    }

    suspend fun getMomentById(id: Int): MomentEntity {
        var resp = ApiClient.api.getPost(id)
        if (!resp.isSuccessful) {
            parseErrorResponse(resp.errorBody())?.let {
                throw it.toServiceException()
            }
            throw ServiceException("Failed to get moment")
        }
        return resp.body()?.data?.toMomentItem() ?: throw ServiceException("Failed to get moment")
    }

    suspend fun likeMoment(id: Int) {
        ApiClient.api.likePost(id)
    }

    suspend fun dislikeMoment(id: Int) {
        ApiClient.api.dislikePost(id)
    }

    fun createMultipartBody(file: File, name: String): MultipartBody.Part {
        val requestFile = RequestBody.create("image/*".toMediaTypeOrNull(), file)
        return MultipartBody.Part.createFormData(name, file.name, requestFile)
    }

    suspend fun createMoment(
        content: String,
        authorId: Int,
        imageUriList: List<UploadImage>,
        relPostId: Int?
    ): MomentEntity {
        val textContent = content.toRequestBody("text/plain".toMediaTypeOrNull())
        val imageList = imageUriList.map { item ->
            val file = item.file
            createMultipartBody(file, "image")
        }
        val response = ApiClient.api.createPost(imageList, textContent = textContent)
        val body = response.body()?.data ?: throw ServiceException("Failed to create moment")
        return body.toMomentItem()

    }

    suspend fun agentMoment(
        content: String,
    ): String {
        val textContent = content.toRequestBody("text/plain".toMediaTypeOrNull())
        val sessionId = ""
        val response = ApiClient.api.agentMoment(AgentMomentRequestBody(generateText = content, sessionId =sessionId ))
        val body = response.body()?.data ?: throw ServiceException("Failed to agent moment")
        return body.toString()

    }

    suspend fun favoriteMoment(id: Int) {
        ApiClient.api.favoritePost(id)
    }

    suspend fun unfavoriteMoment(id: Int) {
        ApiClient.api.unfavoritePost(id)
    }

    suspend fun deleteMoment(id: Int) {
        ApiClient.api.deletePost(id)
    }

}

/**
 * 动态图片
 */
data class MomentImageEntity(
    // 图片ID
    val id: Long,
    // 图片URL
    val url: String,
    // 缩略图URL
    val thumbnail: String,
    // 图片BlurHash
    val blurHash: String? = null,
    // 宽度
    var width: Int? = null,
    // 高度
    var height: Int? = null
)

/**
 * 动态
 */
data class MomentEntity(
    // 动态ID
    val id: Int,
    // 作者头像
    val avatar: String,
    // 作者昵称
    val nickname: String,
    // 区域
    val location: String,
    // 动态时间
    val time: Date,
    // 是否关注
    val followStatus: Boolean,
    // 动态内容
    val momentTextContent: String,
    // 动态图片
    @DrawableRes val momentPicture: Int,
    // 点赞数
    val likeCount: Int,
    // 评论数
    val commentCount: Int,
    // 分享数
    val shareCount: Int,
    // 收藏数
    val favoriteCount: Int,
    // 动态图片列表
    val images: List<MomentImageEntity> = emptyList(),
    // 作者ID
    val authorId: Int = 0,
    // 是否点赞
    var liked: Boolean = false,
    // 关联动态ID
    var relPostId: Int? = null,
    // 关联动态
    var relMoment: MomentEntity? = null,
    // 是否收藏
    var isFavorite: Boolean = false
)
class MomentLoaderExtraArgs(
    val explore: Boolean? = false,
    val timelineId: Int? = null,
    val authorId : Int? = null
)
class MomentLoader : DataLoader<MomentEntity,MomentLoaderExtraArgs>() {
    override suspend fun fetchData(
        page: Int,
        pageSize: Int,
        extra: MomentLoaderExtraArgs
    ): ListContainer<MomentEntity> {
        val result = ApiClient.api.getPosts(
            page = page,
            pageSize = pageSize,
            explore = if (extra.explore == true) "true" else "",
            timelineId = extra.timelineId,
            authorId = extra.authorId
        )
        val data =  result.body()?.let {
            ListContainer(
                list = it.list.map { it.toMomentItem() },
                total = it.total,
                page = page,
                pageSize = pageSize
            )
        }
        if (data == null) {
            throw ServiceException("Failed to get moments")
        }
        return data
    }

    fun updateMomentLike(id: Int,isLike:Boolean) {
        this.list = this.list.map { momentItem ->
            if (momentItem.id == id) {
                momentItem.copy(likeCount = momentItem.likeCount + if (isLike) 1 else -1, liked = isLike)
            } else {
                momentItem
            }
        }.toMutableList()
        onListChanged?.invoke(this.list)
    }

    fun updateFavoriteCount(id: Int,isFavorite:Boolean) {
        this.list = this.list.map { momentItem ->
            if (momentItem.id == id) {
                momentItem.copy(favoriteCount = momentItem.favoriteCount + if (isFavorite) 1 else -1, isFavorite = isFavorite)
            } else {
                momentItem
            }
        }.toMutableList()
        onListChanged?.invoke(this.list)
    }

    fun removeMoment(id: Int) {
        this.list = this.list.filter { it.id != id }.toMutableList()
        onListChanged?.invoke(this.list)
    }

    fun addMoment(moment: MomentEntity) {
        this.list.add(0, moment)
        onListChanged?.invoke(this.list)
    }

    fun updateFollowStatus(authorId:Int,isFollow:Boolean) {
        this.list = this.list.map { momentItem ->
            if (momentItem.authorId == authorId) {
                momentItem.copy(followStatus = isFollow)
            } else {
                momentItem
            }
        }.toMutableList()
        onListChanged?.invoke(this.list)
    }

}