package com.dlc.chemical.camera

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Point
import android.hardware.Camera
import android.media.CamcorderProfile
import android.media.MediaRecorder
import android.os.*
import android.view.TextureView
import android.view.WindowManager
import com.dlc.chemical.arcsoft.util.camera.CameraHelper
import com.dlc.chemical.arcsoft.util.camera.CameraListener
import com.rc.core.log.RcLog
import com.rc.core.util.MediaUtils
import com.rc.core.util.Weak
import java.io.File
import java.io.IOException
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*

/**
 * info
 *
 * @author ReiChin_
 */
class TakeVideoHelper(
    val context: Context,
    private val previewView: TextureView,
    private val cameraId: Int
) : ISafetyCheck, CameraListener {

    private val mContext: Context? by Weak { context }

    companion object {
        private const val WHAT_RECORD_END = 1

        private const val RECORD_TIME = 2 * 60 * 1000L
    }

    private var mOutMediaFile: File? = null
    private var mOutCameraPath: String = ""

    private var mRecorder: MediaRecorder? = null
    private var mCameraHelper: CameraHelper? = null

    private var mRecording = false
    private var mIsTimeout = false

    private var mOnMediaResultListener: OnMediaResultListener? = null

    override fun registerMediaResultListener(listener: OnMediaResultListener?) {
        this.mOnMediaResultListener = listener
    }

    override fun initCamera() {
        val context = mContext ?: return

        val windowManager =
            context.getSystemService(Context.WINDOW_SERVICE) as WindowManager? ?: return

        val numberOfCameras = Camera.getNumberOfCameras()
        RcLog.info("[TakeVideoHelper] numberOfCameras:${numberOfCameras}, cameraId:${cameraId}")

        mCameraHelper = CameraHelper.Builder()
            .previewViewSize(
                Point(
                    previewView.measuredWidth,
                    previewView.measuredHeight
                )
            )
            .rotation(windowManager.defaultDisplay.rotation)
            .specificCameraId(cameraId)
            .isMirror(false)
            .previewOn(previewView)
            .cameraListener(this)
            .build().apply {
                init()
                start()
            }
    }

    private fun prepareVideoRecorder(): Boolean {
        if (null == mCameraHelper) return false

        // BEGIN_INCLUDE (configure_preview)
        val camera = mCameraHelper!!.camera

        val optimalSize = mCameraHelper!!.previewSize
        val profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)
        profile.videoFrameWidth = optimalSize.width
        profile.videoFrameHeight = optimalSize.height
        // END_INCLUDE (configure_preview)

        // BEGIN_INCLUDE (configure_media_recorder)
        mRecorder = MediaRecorder()

        // Step 1: Unlock and set camera to MediaRecorder
        camera.unlock()
        mRecorder!!.setCamera(camera)


        // Step 2: Set sources
        mRecorder!!.setAudioSource(MediaRecorder.AudioSource.DEFAULT)
        mRecorder!!.setVideoSource(MediaRecorder.VideoSource.CAMERA)

        // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
        mRecorder!!.setProfile(profile)
//        mRecorder!!.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)//静音录制
//        mRecorder!!.setVideoEncodingBitRate(900*1024);   //设置编码比特率,不设置会使视频图像模糊
        // Step 4: Set output file
        val context = mContext ?: return false
        mOutMediaFile = createVideoFile(context)
        mOutMediaFile ?: return false
        mRecorder!!.setOutputFile(mOutMediaFile!!.path)

        // Step 5: Prepare configured MediaRecorder
        try {
            mRecorder!!.prepare()
        } catch (e: IllegalStateException) {
            RcLog.warn("[TakeVideoHelper] IllegalStateException preparing MediaRecorder: ${e.message}")
            mOnMediaResultListener?.onError("preparing MediaRecorder: ${e.message}")
            releaseMediaRecorder()
            return false
        } catch (e: IOException) {
            RcLog.warn("[TakeVideoHelper] IOException preparing MediaRecorder: ${e.message}")
            mOnMediaResultListener?.onError("preparing MediaRecorder: ${e.message}")
            releaseMediaRecorder()
            return false
        }
        return true
    }

    private fun releaseMediaRecorder() {
        // clear recorder configuration
        mRecorder?.reset()
        // release the recorder object
        mRecorder?.release()
        mRecorder = null
        // Lock camera for later use i.e taking it back from MediaRecorder.
        // MediaRecorder doesn't need it anymore and we will release it if the activity pauses.
        mCameraHelper?.camera?.lock()
    }

    override fun capture() {
        if (prepareVideoRecorder()) {
            try {
                mRecorder?.start()
                mRecording = true
            } catch (e: Exception) {
                RcLog.warn("[TakeVideoHelper] Exception start MediaRecorder: ${e.message}")
                mOnMediaResultListener?.onError("start MediaRecorder: ${e.message}")
                releaseMediaRecorder()
            }
        }

        mRecordHandler.sendEmptyMessageDelayed(WHAT_RECORD_END, RECORD_TIME)
    }

    override fun stopRecording() {
        RcLog.info("TakeVideoHelper#stopRecording()")
        mRecording = false
        mRecordHandler.removeMessages(WHAT_RECORD_END)
        mRecorder?.setOnErrorListener(null)
        mRecorder?.setOnInfoListener(null)
        mRecorder?.setPreviewDisplay(null)
        try {
            mRecorder?.stop()
        } catch (e: Exception) {
            RcLog.warn("[TakeVideoHelper] Exception stop MediaRecorder: ${e.message}")
            mOnMediaResultListener?.onError("stop MediaRecorder: ${e.message}")
            releaseMediaRecorder()
            return
        }

        releaseMediaRecorder()

        // 回调视频文件到前台
        mOnMediaResultListener?.onMedia(mOutMediaFile!!.path, MediaType.VIDEO, mIsTimeout)
    }

    override fun releaseCamera() {
        RcLog.info("TakeVideoHelper#releaseCamera()")

        mCameraHelper?.release()

        mOnMediaResultListener = null
        mOutMediaFile?.let { MediaUtils.deleteFile(it.absolutePath) }
    }

    override fun cancel() {
        RcLog.info("TakeVideoHelper#cancel()")
        mOnMediaResultListener = null
        stopRecording()
    }

    private fun createVideoFile(context: Context): File {
        val fileName = "VID_${
            SimpleDateFormat(
                "yyyyMMddHH_mmssSSS",
                Locale.getDefault()
            ).format(System.currentTimeMillis())
        }.mp4"
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val diskCacheDir =
                context.getExternalFilesDir(Environment.DIRECTORY_MOVIES)?.path ?: ""
            val rootDir = File(diskCacheDir)
            if (!rootDir.exists()) {
                rootDir.mkdirs()
            }
            val cameraFile = File(rootDir, fileName)
            val outUri = MediaUtils.createVideoUri(context, fileName, "video/mp4")
            if (outUri != null) {
                mOutCameraPath = outUri.path!!
            }
            return cameraFile
        } else {
            val cameraFile = MediaUtils.createCameraFile(context, fileName)
            mOutCameraPath = cameraFile.absolutePath
            return cameraFile
        }
    }

    private val mRecordHandler = object : Handler(Looper.getMainLooper()) {

        @SuppressLint("RestrictedApi")
        override fun handleMessage(msg: Message) {
            RcLog.info("[TakeVideoHelper] mRecordHandler handle record end message.")
            mContext ?: return

            if (WHAT_RECORD_END == msg.what) {
                RcLog.warn("${RECORD_TIME/1000}s record end.")
                stopRecording()
            }
        }
    }

    override fun onCameraOpened(
        camera: Camera?,
        cameraId: Int,
        displayOrientation: Int,
        isMirror: Boolean
    ) {
        RcLog.info("TakeVideoHelper#onCameraOpened..... ")
    }

    override fun onPreview(data: ByteArray?, camera: Camera?) {
    }

    override fun onCameraClosed() {
        RcLog.info("TakeVideoHelper#onCameraClosed: ")
    }

    override fun onCameraError(e: Exception?) {
        e?.printStackTrace()
        val info = "onCameraError: ${e?.message}"
        RcLog.info("[TakeVideoHelper] $info")
        mOnMediaResultListener?.onError(info)
    }

    override fun onCameraConfigurationChanged(cameraID: Int, displayOrientation: Int) {
        RcLog.info("TakeVideoHelper#onCameraConfigurationChanged: $cameraID  $displayOrientation")
    }

}