package com.isidroid.rendering.ext

import android.app.ActivityManager
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.Config
import android.graphics.BitmapFactory
import android.graphics.Matrix
import androidx.core.graphics.scale
import com.isidroid.rendering.constant.PrintOrientation
import com.isidroid.rendering.constant.PrintSize
import com.isidroid.rendering.model.PrintCanvas
import com.isidroid.utils.sizeString
import com.isidroid.utils.tryCatch
import timber.log.Timber
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import kotlin.math.max
import kotlin.math.sqrt

internal fun isPicturePortrait(filePath: String, @PrintOrientation orientation: Int): Boolean {
    if (orientation == PrintOrientation.PORTRAIT)
        return true

    val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
    BitmapFactory.decodeFile(filePath, options)
    val isPicturePortrait = options.outWidth < options.outHeight

    return orientation == PrintOrientation.AUTO && isPicturePortrait
}

internal fun createBitmapWithScaling(dpix: Int, picture: Bitmap, printSize: Int, settingsScale: Float, canvasSize: PrintCanvas, maxSize: Int): Bitmap {
    val bitmap = createBitmap(picture, dpix, printSize, maxSize)

    Timber.i("createBitmapWithScaling bitmap=${bitmap.sizeString}")

    return bitmap.getScaled(canvasSize, printSize, settingsScale, maxSize)
}

internal fun createBitmap(picture: Bitmap, dpix: Int, @PrintSize printSize: Int, maxSize: Int): Bitmap {
    val isScale = printSize == PrintSize.PAPER_ORIGINAL_PAGE

    val bitmap = if (isScale)
        picture.scaleToMaxSize(dpix, maxSize)
    else
        picture

    val result = bitmap.copy(Config.RGB_565, isScale)
    picture.recycle()
    return result
}

private fun Bitmap.getScaled(canvasSize: PrintCanvas, @PrintSize printSize: Int, settingsScale: Float, maxSize: Int): Bitmap {
    val renderPrintScale = calculateScale(
        printSize = printSize,
        canvasSize = canvasSize,
        settingsScale = settingsScale,
        bitmapWidth = width,
        bitmapHeight = height
    )

    val matrix = Matrix()
    matrix.preScale(renderPrintScale, renderPrintScale)

    val result = Bitmap.createBitmap(this, 0, 0, width, height, matrix, false)


    return result
}


private fun Bitmap.scaleToMaxSize(dpix: Int, maxSize: Int): Bitmap {
    val imageDpiScale = calcMaxScale(dpix, maxSize)

    val matrix = Matrix()
    matrix.postScale(imageDpiScale, imageDpiScale)

    val scaled = tryCatch { Bitmap.createBitmap(this, 0, 0, width, height, matrix, false) }
    if (scaled != null) {
        recycle()
    }

    return scaled ?: this
}

private fun Bitmap.calcMaxScale(dpix: Int, maxSize: Int): Float {
    val imageDpiScale = (((width * dpix) / 72) / width).toFloat()
    val calcWidth = width * imageDpiScale
    val calcHeight = height * imageDpiScale
    val maxCalcSize = max(calcWidth, calcHeight)

    Timber.i("==> calcMaxScale")
    Timber.i("imageDpiScale=$imageDpiScale")
    Timber.i("calcSize=${calcWidth}x${calcHeight}, max=$maxCalcSize")
    Timber.i("maxSize=$maxSize")

    if (maxCalcSize < maxSize)
        return imageDpiScale

    val result = maxSize.toFloat() / max(width, height)

    Timber.i("recalcScale bitmap=${width * result}x${height * result}")

    return result
}


fun Bitmap.saveToFile(
    file: File,
    compressFormat: Bitmap.CompressFormat = Bitmap.CompressFormat.JPEG,
    compressQuality: Int = 100
) {
    val bos = ByteArrayOutputStream()
    compress(compressFormat, compressQuality, bos)
    val fos = FileOutputStream(file)
    fos.write(bos.toByteArray())
    fos.flush()
    fos.close()
}

internal fun getMaxBitmapSize(context: Context, config: Config): Int {
    val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    val memoryClassBytes = activityManager.memoryClass * 1024 * 1024 // memoryClass возвращает в МБ

    val bytes = if(config == Config.ARGB_8888) 4 else 2

    // Предположим, что наибольший размер Bitmap не должен превышать 1/4 от общей памяти
    val maxBitmapBytes = memoryClassBytes / bytes

    // Рассчитываем максимальную ширину/высоту для конфигурации ARGB_8888 (4 байта на пиксель)
    val maxBitmapSize = sqrt((maxBitmapBytes / 4).toDouble()).toInt()


    return maxBitmapSize
}
