package com.adealink.weparty.imageselect.util

import android.media.MediaMetadataRetriever
import android.net.Uri
import android.os.Build
import com.adealink.frame.base.CommonIOError
import com.adealink.frame.base.IError
import com.adealink.frame.base.Rlt
import com.adealink.frame.coroutine.dispatcher.Dispatcher
import com.adealink.frame.log.Log
import com.adealink.frame.storage.file.videoProgressPath
import com.adealink.frame.util.AppUtil
import com.adealink.frame.util.ImageUtil
import com.adealink.frame.util.getFileSizeKB
import com.adealink.frame.util.isFileExists
import com.adealink.weparty.App
import com.adealink.weparty.BuildConfig
import com.hw.videoprocessor.VideoProcessor
import id.zelory.compressor.Compressor
import id.zelory.compressor.constraint.quality
import id.zelory.compressor.constraint.resolution
import id.zelory.compressor.constraint.size
import kotlinx.coroutines.withContext
import java.io.File

private const val TAG_COMPRESS = "tag_compress"

data class CompressResult(val path: String, val width: Int, val height: Int)

suspend fun compressImage(
    path: String,
    reqWidth: Int,
    reqHeight: Int,
    maxSizeKB: Int,
    minQuality: Int
): Rlt<CompressResult> {
    return withContext(Dispatcher.WENEXT_THREAD_POOL) {
        if (isFileExists(path).not()) {
            return@withContext Rlt.Failed(IError(""))
        }
        var compressedImageFile = File(path)
        try {
            compressedImageFile = Compressor.compress(
                App.instance,
                File(path),
                coroutineContext = Dispatcher.WENEXT_THREAD_POOL
            ) {
                resolution(reqWidth, reqHeight)
                quality(minQuality)
                size(maxSizeKB * 1024L)
            }
        } catch (e: Exception) {
            Log.e(TAG_COMPRESS, "failed to compress image: ${path} error: ${e.message}")
        }
        var compressedPath = path
        if (compressedImageFile.exists()) {
            compressedPath = compressedImageFile.path
        }
        if (BuildConfig.DEBUG) {
            Log.d(
                TAG_COMPRESS, "compressImage, originPath:${path}, " +
                        "compressPath:${compressedPath}, " +
                        "originSize:${getFileSizeKB(File(path))}KB, " +
                        "compressSize:${getFileSizeKB(compressedImageFile)}KB"
            )
        }
        val size = ImageUtil.getPictureSize(compressedPath)
        return@withContext Rlt.Success(CompressResult(compressedPath, size.first, size.second))
    }
}

suspend fun compressVideo(path: String, minSizeKB: Int): Rlt<CompressResult> {
    return withContext(Dispatcher.WENEXT_THREAD_POOL) {
        var originWidth = 0
        var originHeight = 0
        try {
            val file = File(path)
            val retriever = MediaMetadataRetriever()
            retriever.setDataSource(AppUtil.appContext, Uri.fromFile(file))
            originWidth =
                retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)
                    ?.toInt() ?: 0
            if (originWidth <= 0) {
                Log.e(TAG_COMPRESS, "compressVideo, originWidth <= 0, path:${path}")
                return@withContext Rlt.Failed(IError())
            }

            originHeight =
                retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)
                    ?.toInt() ?: 0
            if (originHeight <= 0) {
                Log.e(TAG_COMPRESS, "compressVideo, originHeight <= 0, path:${path}")
                return@withContext Rlt.Failed(IError())
            }

            val originSize = getFileSizeKB(file)
            if (originSize <= minSizeKB) {
                Log.d(
                    TAG_COMPRESS,
                    "compressVideo, originSize:${originSize}KB less 400KB, path:${path}"
                )
                return@withContext Rlt.Success(CompressResult(path, originWidth, originHeight))
            }

            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                return@withContext Rlt.Success(CompressResult(path, originWidth, originHeight))
            }

            val bitrate =
                retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE)
                    ?.toInt() ?: 0
            if (bitrate <= 0) {
                Log.e(TAG_COMPRESS, "compressVideo, bitrate <= 0, path:${path}")
                return@withContext Rlt.Success(CompressResult(path, originWidth, originHeight))
            }

            val filePath = File(
                videoProgressPath,
                "${System.currentTimeMillis()}_compress.mp4"
            ).absolutePath
            val outWidth = originWidth / 2
            val outHeight = originHeight / 2
            VideoProcessor.processor(AppUtil.appContext)
                .input(path)
                .output(filePath)
                .outWidth(outWidth)
                .outHeight(outHeight)
                .bitrate(bitrate / 2)
                .process()
            if (BuildConfig.DEBUG) {
                Log.d(
                    TAG_COMPRESS, "compressVideo, originPath:${path}, " +
                            "compressPath:${filePath}, " +
                            "originSize:${originSize}KB, " +
                            "compressSize:${getFileSizeKB(File(filePath))}KB"
                )
            }
            return@withContext Rlt.Success(CompressResult(path, outWidth, outHeight))
        } catch (e: Exception) {
            Log.e(TAG_COMPRESS, "compressVideo, e:${e}, path:${path}")
            if (originWidth > 0 && originHeight > 0) {
                return@withContext Rlt.Success(CompressResult(path, originWidth, originHeight))
            }

            return@withContext Rlt.Failed(CommonIOError(exception = e))
        }
    }
}