package com.gh.gamecenter.common.utils

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.gamecenter.common.HaloApp
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IConfigProvider
import com.github.piasy.biv.metadata.ImageInfoExtractor
import java.io.File
import java.io.FileOutputStream

/**
 * Created by khy on 02/08/18.
 * 图片压缩工具类
 * 资料参考:https://github.com/zetbaitsu/Compressor
 * 压缩算法:http://gitlab.ghzhushou.com/pm/halo-app-issues/issues/298
 */
object CompressImageUtils {

    private const val compressLimitSize: Long = 50 * 1024
    private const val defaultQuality = 90
    private const val defaultRatio = 2
    private const val defaultCompressBorder = 1280

    /**
     * 压缩图片并保存到目标文件
     * 该压缩方法是同步执行 请勿在主线程执行
     * 返回源文件的三种情况:小于特定值,图片类型为GIF,压缩失败
     * ---------------------------------------------------------------------------------------------
     * 关于压缩格式问题：
     * 1.图片详情对动态Webp/静态Webp的判断存在问题，导致部分静态Webp图片误判为动态Webp而直接委托Fresco处理，出现无法缩放问题
     * 2.为了解决上述问题，如果压缩是检测到是动态Webp时直接压缩为JPEG，这样就能解决图片详情无法缩放问题（todo 这样会导致动态Webp无法播放）
     */
    @Throws(Exception::class)
    fun compressImageAndSaveToFile(imageFile: File, compressGif: Boolean): File {
        val configProvider = ARouter.getInstance().build(RouteConsts.provider.config).navigation() as? IConfigProvider
        val imageType = ImageInfoExtractor.getImageType(imageFile)
        // 小于某一个设定的值时，直接返回原图
        if (imageType != ImageInfoExtractor.TYPE_ANIMATED_WEBP && imageFile.length() < configProvider?.getUploadLimitSize() ?: compressLimitSize) {
            return imageFile
        }

        val cacheDir = getImageCachePatch()
        val parentFile = cacheDir.parentFile
        if (!parentFile.exists()) parentFile.mkdirs()
        var fileOutputStream: FileOutputStream? = null

        try {
            // 确定图片类型
            val options = BitmapFactory.Options()
            options.inJustDecodeBounds = true
            BitmapFactory.decodeFile(imageFile.absolutePath, options)
            val formatType = if (options.outMimeType.contains("png")) {
                Bitmap.CompressFormat.PNG
            } else if (options.outMimeType.contains("gif") && !compressGif) { // gif直接返回原图
                return imageFile
            } else {
                Bitmap.CompressFormat.JPEG
            }

            fileOutputStream = FileOutputStream(cacheDir)
            // write the compressed bitmap at the destination specified by destinationPath.
            decodeSampledBitmapFromFile(imageFile).compress(
                formatType,
                configProvider?.getQuality() ?: defaultQuality,
                fileOutputStream
            )

            if (cacheDir.length() == 0L) {
                return imageFile //预防压缩失败
            }
            return cacheDir
        } catch (e: Exception) {
            e.printStackTrace()
            if (cacheDir.exists()) {
                cacheDir.delete()
            }
        } finally {
            if (fileOutputStream != null) {
                fileOutputStream.flush()
                fileOutputStream.close()
            }
        }
        return imageFile
    }

    private fun getImageCachePatch(): File {
//        return File(Environment.getExternalStorageDirectory().absolutePath + "/Pictures/test/" + System.currentTimeMillis() + ".jpg")
        // 统一用jpg保存应该没有影响吧
        return File(HaloApp.getInstance().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg")
    }

    // 根据图片获取压缩后的位图
    @Throws(Exception::class)
    private fun decodeSampledBitmapFromFile(imageFile: File): Bitmap {
        // First decode with inJustDecodeBounds=true to check dimensions
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(imageFile.absolutePath, options)

        // Raw height and width of image
        val height = options.outHeight
        val width = options.outWidth
        var inSampleSize = 1

        var compressType: CompressType? = null

        val longSide = Math.max(height, width) //最长边
        val shortSide = Math.min(height, width) //最短边
        val scale = longSide.toFloat() / shortSide  // 长短边比例
        val configProvider = ARouter.getInstance().build(RouteConsts.provider.config).navigation() as? IConfigProvider
        val compressLimit = configProvider?.getSize() ?: defaultCompressBorder

        if (longSide > compressLimit && shortSide > compressLimit) {
            if (scale > configProvider?.getRatio() ?: defaultRatio) {
                inSampleSize = if (shortSide / compressLimit == 0) 1 else shortSide / compressLimit
                compressType = CompressType.LIMIT_SHORT // 横向长方形
            } else {
                inSampleSize = if (longSide / compressLimit == 0) 1 else longSide / compressLimit
                compressType = CompressType.LIMIT_LONG // 纵向长方形
            }
        } else if (longSide > compressLimit && shortSide < compressLimit) {
            if (scale <= configProvider?.getRatio() ?: defaultRatio) {
                inSampleSize = if (longSide / compressLimit == 0) 1 else longSide / compressLimit
                compressType = CompressType.LIMIT_LONG
            }
        }

        // Calculate inSampleSize
        options.inSampleSize = inSampleSize

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false

        var scaledBitmap = BitmapFactory.decodeFile(imageFile.absolutePath, options)

        val matrix = Matrix() // 精确缩放
        if (compressType != null) {
            val targetMatrixScale = if (compressType == CompressType.LIMIT_SHORT) {
                if (scaledBitmap.width > scaledBitmap.height) {
                    compressLimit.toFloat() / scaledBitmap.height
                } else {
                    compressLimit.toFloat() / scaledBitmap.width
                }
            } else {
                if (scaledBitmap.width > scaledBitmap.height) {
                    compressLimit.toFloat() / scaledBitmap.width
                } else {
                    compressLimit.toFloat() / scaledBitmap.height
                }
            }
            matrix.setScale(targetMatrixScale, targetMatrixScale)
            try {
                scaledBitmap =
                    Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.width, scaledBitmap.height, matrix, true)
            } catch (ignore: OutOfMemoryError) {

            }
        }
        return scaledBitmap
    }

//    private fun getImageSetting(): SettingsEntity.Image {
//        val settings = Config.getSettings()
//        if (settings?.image != null) {
//            return settings.image!!
//        }
//        val image = SettingsEntity.Image()
//        image.processLimitSize = compressLimitSize
//        image.size = defaultCompressBorder
//        image.ratio = defaultRatio
//        image.quality = defaultQuality
//        return image
//    }
}

enum class CompressType {
    //  0: 短边等比压缩至1280 H:长边 W:短边
    LIMIT_SHORT,

    //  1: 取长边等比压缩至1280 H:短边 W: 长边
    LIMIT_LONG
}