package xyz.r0r5chach.dermy_app.fragments

import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCapture.OutputFileOptions
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import com.google.common.util.concurrent.ListenableFuture
import org.bson.types.ObjectId
import xyz.r0r5chach.dermy_app.PredictionMode
import xyz.r0r5chach.dermy_app.R
import xyz.r0r5chach.dermy_app.db.DermyDatabase
import xyz.r0r5chach.dermy_app.db.Entities
import xyz.r0r5chach.dermy_app.map.locations.Location
import java.io.File
import java.time.Instant
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

class CameraFragment(val location: Location, val db: DermyDatabase, val mode: PredictionMode, var mole: Entities.Mole?) : Fragment(R.layout.fragment_camera) {
    private lateinit var previewView: PreviewView
    private lateinit var imageCapture: ImageCapture
    private lateinit var cameraExecutor: ExecutorService

    private val requestPermissionLauncher = registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) {isGranted: Boolean ->
       if (isGranted) {
           startCamera()
       }
       else {
           Toast.makeText(context, "Camera permission is required", Toast.LENGTH_SHORT).show()
       }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        previewView = requireView().findViewById(R.id.camera_preview)!!

        if (context?.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            requestPermissionLauncher.launch(Manifest.permission.CAMERA)
        }
        else {
            startCamera()
        }

        previewView.setOnClickListener { takePhoto() }
        cameraExecutor = Executors.newSingleThreadExecutor()
    }

    private fun startCamera() {
        val cameraProviderFuture: ListenableFuture<ProcessCameraProvider> = ProcessCameraProvider.getInstance(requireContext())

        cameraProviderFuture.addListener({
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

            val preview = Preview.Builder().build().also {
                it.setSurfaceProvider(previewView.surfaceProvider)
            }

            imageCapture = ImageCapture.Builder().build()

            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

            try {
                cameraProvider.unbindAll()
                cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
            } catch (exc: Exception) {
                exc.printStackTrace()
            }

        }, ContextCompat.getMainExecutor(requireContext()))
    }

    private fun takePhoto() {
        val id = when(mole) {
                null -> ObjectId().toString()
                else -> mole!!.id
        }
        val photoFile = File(context?.filesDir, "$id.jpg")
        val outputFileOptions: OutputFileOptions = OutputFileOptions.Builder(photoFile).build()
        imageCapture.takePicture(
            outputFileOptions,
            ContextCompat.getMainExecutor(requireContext()),
            object : ImageCapture.OnImageSavedCallback {
                @SuppressLint("NewApi")
                override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                    if (mole == null) {
                        mole = Entities.Mole(id, null, Instant.now(), location, null)
                    }
                    parentFragmentManager.commit {
                        setReorderingAllowed(true)
                        replace(R.id.fragment_container, MoleFragment(mole!!, mode, db), null)
                        addToBackStack(null)
                    }
                }

                override fun onError(exception: ImageCaptureException) {
                    Toast.makeText(
                        requireContext(),
                        "Error saving photo: ${exception.message}",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            })
    }


    override fun onDestroy() {
        super.onDestroy()
        cameraExecutor.shutdown()
    }
}
