package com.za.ui.camera

import android.Manifest
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.location.Location
import android.location.LocationManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.view.Gravity
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.OrientationEventListener
import android.view.SoundEffectConstants
import android.view.Surface
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.PopupWindow
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatSeekBar
import androidx.camera.core.AspectRatio
import androidx.camera.core.Camera
import androidx.camera.core.CameraInfo
import androidx.camera.core.CameraSelector
import androidx.camera.core.ExposureState
import androidx.camera.core.FocusMeteringAction
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.core.ZoomState
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.constraintlayout.utils.widget.ImageFilterView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.Group
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.exifinterface.media.ExifInterface
import androidx.lifecycle.LiveData
import com.blankj.utilcode.util.ThreadUtils
import com.blankj.utilcode.util.ToastUtils
import com.blankj.utilcode.util.UriUtils
import com.bumptech.glide.Glide
import com.permissionx.guolindev.PermissionX
import com.za.common.log.LogUtil.print
import com.za.common.util.ClickProxy
import com.za.servicing.R
import com.za.ui.camera.CameraXPreviewViewTouchListener.CustomTouchListener
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.ExecutionException
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

class ZdCameraXActivity : AppCompatActivity() {
	private var exposurePopupWindow : PopupWindow? = null

	internal enum class FlashMode {
		auto, open, light, close
	}

	private var rootView : ConstraintLayout? = null
	private var imageCapture : ImageCapture? = null
	private var cameraInfo : CameraInfo? = null

	private var exposureState : ExposureState? = null
	private var cameraExecutor : ExecutorService? = null
	private var zoomState : LiveData<ZoomState>? = null
	private var viewFinder : PreviewView? = null
	private var takePhoto : TakePhotoButtonView? = null
	private var ivFlash : ImageView? = null
	private var ivChangeCamera : ImageView? = null
	private var ivConfirm : ImageView? = null
	private var ivCancel : ImageView? = null
	private lateinit var ivPreview : ImageFilterView
	private var ivBack : ImageView? = null
	private var sliderExposure : AppCompatSeekBar? = null
	private var groupOperation : Group? = null
	private var groupPreview : Group? = null
	private var uri : Uri? = null
	private var animatorSet : AnimatorSet? = null
	private var location : Location? = null
	private var camera : Camera? = null
	private var isBack = true

	private var orientationEventListener : OrientationEventListener? = null
	private var flashPopWindow : PopupWindow? = null
	private var flashMode = FlashMode.close


	override fun onCreate(savedInstanceState : Bundle?) {
		super.onCreate(savedInstanceState)
		setContentView(R.layout.activity_zd_camera_xactivity)
		isBack = intent.getBooleanExtra("isBack", true)
		setWindowBrightness()
		initView()
		initLocation()
		startCamera()
		setOnClick()

		orientationEventListener = object : OrientationEventListener(this) {
			override fun onOrientationChanged(orientation : Int) {
				if (orientation == ORIENTATION_UNKNOWN || imageCapture == null) {
					print("zdCamerax orientation", "orientation==$orientation")
					return
				}
				when (orientation) {
					in 45 .. 134 -> {
						imageCapture?.targetRotation = Surface.ROTATION_270
					}

					in 135 .. 224 -> {
						imageCapture?.targetRotation = Surface.ROTATION_180
					}

					in 225 .. 314 -> {
						imageCapture?.targetRotation = Surface.ROTATION_90
					}

					else -> {
						imageCapture?.targetRotation = Surface.ROTATION_0
					}
				}
			}
		}
	}

	@SuppressLint("ObjectAnimatorBinding")
	private fun initView() {
		cameraExecutor = Executors.newSingleThreadExecutor()
		rootView = findViewById(R.id.viewGroup_parent)
		viewFinder = findViewById(R.id.viewFinder)
		takePhoto = findViewById(R.id.iv_takePhoto)
		ivConfirm = findViewById(R.id.iv_confirm)
		ivCancel = findViewById(R.id.iv_cancel)
		ivBack = findViewById(R.id.iv_back)
		sliderExposure = findViewById(R.id.slider_exposureState)
		groupOperation = findViewById(R.id.group_opera)
		groupPreview = findViewById(R.id.group_preview)
		groupPreview?.visibility = View.GONE
		ivChangeCamera = findViewById(R.id.iv_changeCamera)
		ivPreview = findViewById(R.id.iv_preview)
		ivFlash = findViewById(R.id.iv_flash)
		animatorSet = AnimatorSet()
		animatorSet?.playTogether(ObjectAnimator.ofFloat(ivCancel, "translationX", 0f, - 200f),
			ObjectAnimator.ofFloat(ivConfirm, "translationX", 200f))

		animatorSet?.setDuration(500)
	}

	// 在 Activity 中调整当前窗口亮度（0.0~1.0范围）
	private fun setWindowBrightness() {
		val layoutParams = window.attributes
		layoutParams.screenBrightness = 1f
		window.attributes = layoutParams
	}

	@SuppressLint("ClickableViewAccessibility")
	private fun setOnClick() {
		takePhoto?.setOnClickListener(ClickProxy { v : View? -> takePhoto() })

		ivChangeCamera?.setOnClickListener(ClickProxy { v : View? ->
			isBack = ! isBack
			if (! isBack) {
				if (flashPopWindow != null && flashPopWindow?.isShowing == true) {
					flashPopWindow?.dismiss()
				}
				flashMode = FlashMode.close
				ivFlash?.setImageResource(R.drawable.picture_ic_flash_off)
			}
			startCamera()
		})

		ivFlash?.setOnClickListener {
			if (! isBack) {
				ToastUtils.showShort("前置模式下无法开启！")
				return@setOnClickListener
			}
			if (flashPopWindow != null && flashPopWindow?.isShowing == true) {
				flashPopWindow?.dismiss()
			} else {
				showFlashView()
			}
		}

		ivCancel?.setOnClickListener {
			groupPreview?.visibility = View.GONE
			groupOperation?.visibility = View.VISIBLE
		}

		ivConfirm?.setOnClickListener {
			val intent = Intent()
			if (uri != null) {
				intent.putExtra("path", UriUtils.uri2File(uri).absolutePath)
			}
			setResult(RESULT_OK, intent)
			finish()
		}

		ivBack?.setOnClickListener { finish() }

		sliderExposure?.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
			@SuppressLint("SetTextI18n")
			override fun onProgressChanged(seekBar : SeekBar, progress : Int, fromUser : Boolean) {
				if (exposureState != null) {
					camera?.cameraControl?.setExposureCompensationIndex(Math.round(progress.toFloat()))
					if (exposurePopupWindow != null) {
						val textView =
							exposurePopupWindow?.contentView?.findViewWithTag<TextView>("tv_exposureView")
						textView?.text = progress.toString() + ""
					}
				}
			}

			override fun onStartTrackingTouch(seekBar : SeekBar) {
				showExposureView()
			}

			override fun onStopTrackingTouch(seekBar : SeekBar) {
				viewFinder?.postDelayed({ exposurePopupWindow?.dismiss() }, 1000)
			}
		})

		val cameraXPreviewViewTouchListener = CameraXPreviewViewTouchListener(this)
		viewFinder?.setOnTouchListener(cameraXPreviewViewTouchListener)
		cameraXPreviewViewTouchListener.setCustomTouchListener(object : CustomTouchListener {
			override fun zoom(delta : Float) {
				if (zoomState == null) {
					return
				}
				val currentZoomRatio = zoomState?.value?.zoomRatio
				currentZoomRatio?.let {
					camera?.cameraControl?.setZoomRatio(it.times(delta))
				}

			}

			override fun click(event : MotionEvent) {
				val action = viewFinder?.meteringPointFactory?.createPoint(event.x, event.y)
					?.let { FocusMeteringAction.Builder(it).build() }
				rootView?.post { showTapView(event.rawX.toInt(), event.rawY.toInt()) }
				action?.let {
					camera?.cameraControl?.startFocusAndMetering(action)
				}
			}

			override fun doubleClick(x : Float, y : Float) {
				if (zoomState == null) {
					return
				}
				val currentZoomRatio = zoomState?.value?.zoomRatio
				zoomState?.value?.minZoomRatio?.let {
					if (currentZoomRatio !! > it) {
						camera?.cameraControl?.setLinearZoom(0f)
					} else {
						camera?.cameraControl?.setLinearZoom(0.5f)
					}
				}

			}
		})
	}

	private fun takePhoto() {
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
			ThreadUtils.runOnUiThread {
				PermissionX.init(this@ZdCameraXActivity)
					.permissions(Manifest.permission.ACCESS_MEDIA_LOCATION)
					.request { allGranted : Boolean, grantedList : List<String?>?, deniedList : List<String?>? ->
						print("ZDCamerax ACCESS_MEDIA_LOCATION 权限请求结果",
							"allGranted==$allGranted")
						if (! allGranted) {
							ToastUtils.showLong("权限获取失败")
							finish()
						}
					}
			}
		}
		if (imageCapture == null) {
			ToastUtils.showShort("相机打开失败")
			finish()
		} //        val filename = TimeUtils.date2String(Date(), "yyyyMMddHHmmss")
		//        val contentValues = ContentValues()
		//        contentValues.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, filename)
		//        contentValues.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpeg")
		//        contentValues.put(MediaStore.Images.ImageColumns.DATE_TAKEN, System.currentTimeMillis())
		//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
		//            contentValues.put(MediaStore.Images.ImageColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
		//        } else {
		//            ImageUtils.save2Album()
		//            contentValues.put(MediaStore.Images.ImageColumns.DATA, getTakePictureParentPath() + File.separator + filename + ".jpg")
		//        }
		//
		//        val outputOptions = ImageCapture.OutputFileOptions.Builder(contentResolver,
		//            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues).build()


		// Create time stamped name and MediaStore entry.
		val filename = SimpleDateFormat("yyyyMMddHHmmss",
			Locale.getDefault()).format(System.currentTimeMillis())
		val contentValues = ContentValues().apply {
			put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
			put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
			if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
				put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/中道救援")
			}
		}

		// Create output options object which contains file + metadata
		val outputOptions = ImageCapture.OutputFileOptions.Builder(contentResolver,
			MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
			contentValues).build()


		takePhoto?.startAnimation()

		imageCapture?.takePicture(outputOptions,
			ContextCompat.getMainExecutor(this),
			object : ImageCapture.OnImageSavedCallback {
				override fun onImageSaved(outputFileResults : ImageCapture.OutputFileResults) {
					this@ZdCameraXActivity.uri = outputFileResults.savedUri //保存照片信息
					val exifInterface : ExifInterface
					try {
						exifInterface =
							ExifInterface(UriUtils.uri2File(outputFileResults.savedUri).absolutePath)
						exifInterface.setAttribute(ExifInterface.TAG_DATETIME, filename)
						if (location != null) {
							exifInterface.setGpsInfo(location)
							if (location?.latitude !! > 0f && location?.longitude != null && location?.longitude !! > 0f) {
								exifInterface.setLatLong(location?.latitude !!,
									location?.longitude !!)
							}
						}

						exifInterface.saveAttributes()
						takePhoto?.cancelAnimation()
						groupPreview?.visibility = View.VISIBLE
						if (! this@ZdCameraXActivity.isFinishing) {
							Glide.with(this@ZdCameraXActivity).load(outputFileResults.savedUri)
								.into(ivPreview)
						}
						groupOperation?.visibility = View.GONE
						animatorSet?.start()
					} catch (e : IOException) {
						takePhoto?.cancelAnimation()
						ToastUtils.showShort("照片保存失败" + e.message)
						print("照片保存失败", e)
					}
				}

				override fun onError(exception : ImageCaptureException) {
					takePhoto?.cancelAnimation()
					ToastUtils.showShort("Photo capture failed" + exception.message)
					print("onCameraError", exception)
				}
			})
	}

	private fun startCamera() {
		imageCapture =
			ImageCapture.Builder().setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
				.build()
		val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
		cameraProviderFuture.addListener({
			try {
				val cameraProvider = cameraProviderFuture.get()
				val preview = Preview.Builder().setTargetAspectRatio(AspectRatio.RATIO_4_3).build()

				preview.surfaceProvider = viewFinder?.surfaceProvider
				val cameraSelector =
					if (isBack) CameraSelector.DEFAULT_BACK_CAMERA else CameraSelector.DEFAULT_FRONT_CAMERA
				preview.targetRotation = Surface.ROTATION_0
				cameraProvider.unbindAll()
				camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
				cameraInfo = camera?.cameraInfo
				zoomState = cameraInfo?.zoomState
				exposureState = cameraInfo?.exposureState
				if (exposureState?.isExposureCompensationSupported == true) {
					sliderExposure?.visibility = View.VISIBLE
					sliderExposure?.max = exposureState?.exposureCompensationRange?.upper ?: 1
					if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
						sliderExposure?.min = exposureState?.exposureCompensationRange?.lower ?: 1
					}
				} else {
					sliderExposure?.visibility = View.GONE
				}
			} catch (e : ExecutionException) {
				finish()
				print("相机初始化失败", e)
			} catch (e : InterruptedException) {
				finish()
				print("相机初始化失败", e)
			}
		}, ContextCompat.getMainExecutor(this))
	}

	private fun initLocation() {
		val locationManager = ContextCompat.getSystemService(this, LocationManager::class.java)
		if ((ActivityCompat.checkSelfPermission(this,
				Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) && ActivityCompat.checkSelfPermission(
				this,
				Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
				this,
				Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
				this,
				Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
		) {
			ActivityCompat.requestPermissions(this,
				arrayOf(Manifest.permission.ACCESS_FINE_LOCATION,
					Manifest.permission.ACCESS_COARSE_LOCATION,
					Manifest.permission.RECORD_AUDIO,
					Manifest.permission.CAMERA),
				102)
		} else {
			if (locationManager != null) {
				location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
			}
		}
	}

	@SuppressLint("RtlHardcoded")
	private fun showTapView(x : Int, y : Int) {
		if (takePhoto?.visibility == View.GONE) {
			return
		}
		try {
			val popupWindow = PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT,
				ViewGroup.LayoutParams.WRAP_CONTENT)
			popupWindow.width = 200
			popupWindow.height = 200
			val imageView = ImageView(this)
			imageView.setImageResource(R.drawable.focus_focusing)
			imageView.scaleType = ImageView.ScaleType.CENTER_CROP
			popupWindow.contentView = imageView
			popupWindow.showAtLocation(rootView, Gravity.LEFT or Gravity.TOP, x, y)
			viewFinder?.postDelayed({ popupWindow.dismiss() }, 1000)
			viewFinder?.playSoundEffect(SoundEffectConstants.CLICK)
		} catch (e : Exception) {
			print("zdCameraX showTapView", e)
		}
	}

	@SuppressLint("RtlHardcoded", "SetTextI18n")
	private fun showExposureView() {
		if (takePhoto?.visibility == View.GONE) {
			return
		}
		exposurePopupWindow =
			PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
		exposurePopupWindow?.width = 300
		exposurePopupWindow?.height = 200
		val textView = TextView(this)
		textView.setTextColor(Color.YELLOW)
		textView.textSize = 50f
		textView.tag = "tv_exposureView"
		textView.gravity = Gravity.CENTER
		textView.text = exposureState?.exposureCompensationIndex.toString() + ""
		exposurePopupWindow?.contentView = textView
		exposurePopupWindow?.showAtLocation(rootView, Gravity.CENTER, 0, 0)
	}

	@SuppressLint("RtlHardcoded")
	private fun showFlashView() {
		if (flashPopWindow != null) {
			flashPopWindow = null
		}
		flashPopWindow =
			PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
		@SuppressLint("InflateParams") val view =
			LayoutInflater.from(this).inflate(R.layout.item_flash_mode, null)
		val tvFlashAuto = view.findViewById<TextView>(R.id.tvFlashAuto)
		val tvFlashOpen = view.findViewById<TextView>(R.id.tvFlashOpen)
		val tvFlashLight = view.findViewById<TextView>(R.id.tvFlashLight)
		val tvFlashClose = view.findViewById<TextView>(R.id.tvFlashClose)

		when (flashMode) {
			FlashMode.auto -> tvFlashAuto.setTextColor(Color.YELLOW)
			FlashMode.open -> tvFlashOpen.setTextColor(Color.YELLOW)
			FlashMode.light -> tvFlashLight.setTextColor(Color.YELLOW)
			FlashMode.close -> tvFlashClose.setTextColor(Color.YELLOW)
		}
		tvFlashAuto.setOnClickListener { v : View? ->
			if (imageCapture != null) {
				camera?.cameraControl?.enableTorch(false)
				imageCapture?.flashMode = ImageCapture.FLASH_MODE_AUTO
				ivFlash?.setImageResource(R.drawable.picture_ic_flash_auto)
				flashMode = FlashMode.auto
			}
			flashPopWindow?.dismiss()
		}
		tvFlashOpen.setOnClickListener { v : View? ->
			if (imageCapture != null) {
				camera?.cameraControl?.enableTorch(false)
				imageCapture?.flashMode = ImageCapture.FLASH_MODE_ON
				ivFlash?.setImageResource(R.drawable.picture_ic_flash_on)
				flashMode = FlashMode.open
			}
			flashPopWindow?.dismiss()
		}

		tvFlashLight.setOnClickListener { v : View? ->
			if (camera != null) {
				camera?.cameraControl?.enableTorch(true)
				ivFlash?.setImageResource(R.drawable.ic_flash_light)
				flashMode = FlashMode.light
			}
			flashPopWindow?.dismiss()
		}

		tvFlashClose.setOnClickListener { v : View? ->
			if (imageCapture != null) {
				camera?.cameraControl?.enableTorch(false)
				imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF
				ivFlash?.setImageResource(R.drawable.picture_ic_flash_off)
				flashMode = FlashMode.close
			}
			flashPopWindow?.dismiss()
		}

		flashPopWindow?.contentView = view
		flashPopWindow?.showAtLocation(ivFlash,
			Gravity.LEFT or Gravity.TOP,
			0,
			ivFlash?.y?.toInt()?.minus(view.height) ?: 0)
	}

	override fun onPause() {
		super.onPause()
		if (camera != null && imageCapture != null) {
			camera?.cameraControl?.enableTorch(false)
			imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF
			ivFlash?.setImageResource(R.drawable.picture_ic_flash_off)
		}
	}

	override fun onStart() {
		super.onStart()
		orientationEventListener?.enable()
	}

	override fun onStop() {
		super.onStop()
		orientationEventListener?.disable()
	}

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