package it.danieleverducci.openweddingapp.utils

import android.R.attr.bitmap
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.graphics.drawable.Drawable
import android.media.ExifInterface
import android.net.Uri
import android.util.Log
import androidx.core.content.FileProvider
import com.squareup.picasso.Picasso
import com.squareup.picasso.RequestCreator
import com.squareup.picasso.Target
import it.danieleverducci.openweddingapp.Config
import it.danieleverducci.openweddingapp.R
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.OutputStream


class ImageUtils {
    companion object {
        private const val MAX_SIZE = 2048
        private const val TAG = "ImageUtils"
        private const val CACHE_DIRECTORY = "${Config.SAVED_FILES_BASE_NAME}_cache/"
        const val SHARE_FILE_NAME = "share.jpg"
        private var shareImgTarget: Target? = null

        fun resizeImage(file: File) {
            Log.d("FILESIZE", "Old: ${file.length()}")

            val bfOpts = BitmapFactory.Options()
            bfOpts.inJustDecodeBounds = true
            BitmapFactory.decodeFile(file.path, bfOpts)
            var scale = 1
            while (bfOpts.outWidth / scale / 2 > MAX_SIZE && bfOpts.outHeight / scale / 2 > MAX_SIZE) {
                scale *= 2
            }
            val outOptions = BitmapFactory.Options()
            outOptions.inSampleSize = scale
            val resizedBmp = BitmapFactory.decodeFile(file.path, outOptions)
            val os = FileOutputStream(file.path);
            resizedBmp.compress(Bitmap.CompressFormat.JPEG, 80, os)
            os.flush()
            os.close()

            val f2 = File(file.path)
            Log.d("FILESIZE", "New: ${f2.length()}")
        }

        fun shareImage(context: Context, urlOrPath: String, onImageSharedListener: OnImageSharedListener?) {
            shareImgTarget = object: Target {
                override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) {
                    if (bitmap != null) {
                        // Bitmap loaded: share!
                        shareBitmap(context, bitmap)
                        onImageSharedListener?.onImageShared()
                    } else {
                        Log.e(TAG, "Error loading bitmap for sharing image: bitmap is null!")
                        onImageSharedListener?.onImageShareFailed()
                    }
                }
                override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?) {
                    Log.e(TAG, "Unable to load bitmap for sharing image!")
                    onImageSharedListener?.onImageShareFailed()
                }
                override fun onPrepareLoad(placeHolderDrawable: Drawable?) {
                    Log.d(TAG, "onPrepareLoad")
                }
            }

            val picasso: RequestCreator
            picasso = if (urlOrPath.startsWith("http"))
                Picasso.get().load(urlOrPath)
            else
                Picasso.get().load(File(urlOrPath))

            picasso.into(shareImgTarget!!)
        }

        interface OnImageSharedListener {
            fun onImageShared()
            fun onImageShareFailed()
        }
        
        private fun shareBitmap(context: Context, bmp: Bitmap) {

            val cachePath = File(context.externalCacheDir, CACHE_DIRECTORY)
            cachePath.mkdirs()

            val sharedFile = File(cachePath, SHARE_FILE_NAME).also { file ->
                FileOutputStream(file).use { fileOutputStream -> bmp.compress(Bitmap.CompressFormat.JPEG, 80, fileOutputStream) }
            }.apply {
                deleteOnExit()
            }

            val shareImageFileUri: Uri = FileProvider.getUriForFile(context, context.applicationContext.packageName + ".fileprovider", sharedFile)
            val shareMessage = context.getString(R.string.share_text)

            // Create the intent
            val intent = Intent(Intent.ACTION_SEND).apply {
                flags = Intent.FLAG_ACTIVITY_NEW_TASK
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                putExtra(Intent.EXTRA_STREAM, shareImageFileUri)
                putExtra(Intent.EXTRA_TEXT, shareMessage)
                type = "image/jpeg"
            }

            // Initialize the share chooser
            val chooserTitle = context.getString(R.string.share_chooser_text)
            val chooser = Intent.createChooser(intent, chooserTitle)
            val resInfoList: List<ResolveInfo> = context.packageManager.queryIntentActivities(chooser, PackageManager.MATCH_DEFAULT_ONLY)
            for (resolveInfo in resInfoList) {
                val packageName: String = resolveInfo.activityInfo.packageName
                context.grantUriPermission(packageName, shareImageFileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
            }

            context.startActivity(chooser)
        }

        /**
         * Rotate an image if required.
         *
         * @param imgPath       Image file path
         * @return the rotated img path, or the original one if didn't need rotation
         */
        fun rotateImageIfRequired(imgPath: File) {
            val ei = ExifInterface(imgPath.path)
            val orientation: Int =
                ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
            when (orientation) {
                ExifInterface.ORIENTATION_ROTATE_90 -> rotateImage(imgPath, 90)
                ExifInterface.ORIENTATION_ROTATE_180 -> rotateImage(imgPath, 180)
                ExifInterface.ORIENTATION_ROTATE_270 -> rotateImage(imgPath, 270)
            }
        }

        private fun rotateImage(imgPath: File, degree: Int) {
            val img = BitmapFactory.decodeFile(imgPath.path)
            val matrix = Matrix()
            matrix.postRotate(degree.toFloat())
            val rotatedImg = Bitmap.createBitmap(img, 0, 0, img.width, img.height, matrix, true)
            img.recycle()
            val os: OutputStream = BufferedOutputStream(FileOutputStream(imgPath))
            rotatedImg.compress(Bitmap.CompressFormat.JPEG, 80, os)
            os.close()
            rotatedImg.recycle()
        }
    }
}