package com.hmg.hmgDr.ui.fragment

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.Point
import android.graphics.drawable.ColorDrawable
import android.opengl.GLSurfaceView
import android.os.*
import android.util.Log
import android.view.*
import android.widget.*
import androidx.annotation.Nullable
import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.GestureDetectorCompat
import androidx.fragment.app.DialogFragment
import com.hmg.hmgDr.Model.ChangeCallStatusRequestModel
import com.hmg.hmgDr.Model.GetSessionStatusModel
import com.hmg.hmgDr.Model.SessionStatusModel
import com.hmg.hmgDr.R
import com.hmg.hmgDr.ui.VideoCallContract.VideoCallPresenter
import com.hmg.hmgDr.ui.VideoCallContract.VideoCallView
import com.hmg.hmgDr.ui.VideoCallPresenterImpl
import com.hmg.hmgDr.ui.VideoCallResponseListener
import com.hmg.hmgDr.util.opentok.DynamicVideoRenderer
import com.hmg.hmgDr.util.ViewsUtil
import com.opentok.android.*
import com.opentok.android.PublisherKit.PublisherListener
//import pub.devrel.easypermissions.AfterPermissionGranted
//import pub.devrel.easypermissions.AppSettingsDialog
//import pub.devrel.easypermissions.EasyPermissions
//import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
import kotlin.math.ceil

// check this if it works to solve keyboard not work when dialog is opened
// https://stackoverflow.com/questions/55066977/how-to-prevent-custom-dialogfragment-from-hiding-keyboard-when-being-shown
class VideoCallFragment : DialogFragment(), Session.SessionListener,
    PublisherListener,
    SubscriberKit.VideoListener, VideoCallView {

    private var isFullScreen: Boolean = true
    private var isCircle: Boolean = false
    private var x_init_cord = 0
    private var y_init_cord: Int = 0
    private var x_init_margin: Int = 0
    private var y_init_margin: Int = 0
    private val szWindow: Point = Point()
    private lateinit var mWindowManager: WindowManager
    private var isLeft = true

    private lateinit var videoCallPresenter: VideoCallPresenter

    private var mSession: Session? = null
    private var mPublisher: Publisher? = null
    private var mSubscriber: Subscriber? = null

    private var mVolHandler: Handler? = null
    private var mConnectedHandler: Handler? = null
    private var mVolRunnable: Runnable? = null
    private var mConnectedRunnable: Runnable? = null

    private lateinit var recordContainer: FrameLayout
    private lateinit var thumbnail_container: FrameLayout
    private lateinit var activity_clingo_video_call: RelativeLayout
    private lateinit var mPublisherViewContainer: FrameLayout
    private lateinit var mPublisherViewIcon: View
    private lateinit var mSubscriberViewContainer: FrameLayout
    private lateinit var mSubscriberViewIcon: ImageView
    private lateinit var controlPanel: ConstraintLayout

    private var apiKey: String? = null
    private var sessionId: String? = null
    private var token: String? = null
    private var appLang: String? = null
    private var baseUrl: String? = null
    private var isRecording: Boolean = true

    private var isSwitchCameraClicked = false
    private var isCameraClicked = false
    private var isSpeckerClicked = false
    private var isMicClicked = false

    private lateinit var parentView: View
    private lateinit var videoCallContainer: ConstraintLayout
    private lateinit var layoutName: RelativeLayout
    private lateinit var layoutMini: RelativeLayout
    private lateinit var icMini: ImageButton
    private lateinit var mCallBtn: ImageView
    private lateinit var btnMinimize: ImageView
    private lateinit var mCameraBtn: ImageView
    private lateinit var mSwitchCameraBtn: ImageView
    private lateinit var mspeckerBtn: ImageView
    private lateinit var mMicBtn: ImageView
    private lateinit var patientName: TextView
    private lateinit var cmTimer: Chronometer

    private var elapsedTime: Long = 0
    private var resume = false

    private val progressBar: ProgressBar? = null
    private val countDownTimer: CountDownTimer? = null
    private val progressBarTextView: TextView? = null
    private val
            progressBarLayout: RelativeLayout? = null

    private var isConnected = false

    private var sessionStatusModel: GetSessionStatusModel? = null
    private var videoCallResponseListener: VideoCallResponseListener? = null
    private lateinit var mDetector: GestureDetectorCompat

    override fun onCreate(savedInstanceState: Bundle?) {
        requireActivity().setTheme(R.style.AppTheme)
        super.onCreate(savedInstanceState)
    }

    override fun onStart() {
        super.onStart()

//        val params: ViewGroup.LayoutParams = dialog!!.window!!.attributes
//        params.width = WindowManager.LayoutParams.MATCH_PARENT
//        params.height = WindowManager.LayoutParams.MATCH_PARENT
//        dialog!!.window!!.attributes = params as WindowManager.LayoutParams

        dialog?.window?.setLayout(
            LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.MATCH_PARENT
        )
//        val parentLayoutParam: FrameLayout.LayoutParams = /*parentView.layoutParams as*/ FrameLayout.LayoutParams(
//            LinearLayout.LayoutParams.MATCH_PARENT,
//            LinearLayout.LayoutParams.MATCH_PARENT
//        )
//        parentView.layoutParams = parentLayoutParam
    }

    override fun getTheme(): Int {
        return R.style.dialogTheme
    }

    @SuppressLint("UseRequireInsteadOfGet")
    override fun onCreateDialog(@Nullable savedInstanceState: Bundle?): Dialog {// FullScreenVideoTheme
        val layoutInflater = requireActivity().layoutInflater
        this.parentView = onCreateView(layoutInflater, null)

        val alertDialogBuilder: AlertDialog.Builder =
            AlertDialog.Builder(requireContext(), R.style.dialogTheme)
//            .setTitle(android.R.string.select_a_color)
                .setView(this.parentView)
//            .setPositiveButton(android.R.string.ok, { dialogInterface, i -> })
        alertDialogBuilder.setOnKeyListener { _, keyCode, keyEvent ->
            // getAction to make sure this doesn't double fire
            if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.action == KeyEvent.ACTION_UP) {
                videoCallResponseListener?.onBackHandle()
                false // Capture onKey
            } else true
            // Don't capture
        }
        return alertDialogBuilder.create()
/*

        val dialog: Dialog = super.onCreateDialog(savedInstanceState)
        // Add back button listener
        dialog.setOnKeyListener { _, keyCode, keyEvent ->
            // getAction to make sure this doesn't double fire
            if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.action == KeyEvent.ACTION_UP) {
                videoCallResponseListener?.onBackHandle()
                false // Capture onKey
            } else true
            // Don't capture
        }

        return dialog
*/
    }

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

        // This is done in a post() since the dialog must be drawn before locating.
        requireView().post {
            val dialogWindow = dialog!!.window

            if (dialog != null && dialogWindow != null) {
                dialogWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT));
            }

            // Make the dialog possible to be outside touch
            dialogWindow!!.setFlags(
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
            )
            dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
            requireView().invalidate()
        }
    }


    fun setCallListener(videoCallResponseListener: VideoCallResponseListener) {
        this.videoCallResponseListener = videoCallResponseListener
    }

    private fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?
    ): View {
        val view = inflater.inflate(R.layout.activity_video_call, container, false)

//        val parentViewLayoutParam: ConstraintLayout.LayoutParams = ConstraintLayout.LayoutParams(
//            ConstraintLayout.LayoutParams.MATCH_PARENT,
//            ConstraintLayout.LayoutParams.MATCH_PARENT
//        )
//        parentView.layoutParams = parentViewLayoutParam
        //        Objects.requireNonNull(requireActivity().actionBar)!!.hide()
        arguments?.run {
            apiKey = getString("apiKey")
            sessionId = getString("sessionId")
            token = getString("token")
            appLang = getString("appLang")
            baseUrl = getString("baseUrl")
            sessionStatusModel = getParcelable("sessionStatusModel")
            if (sessionStatusModel != null)
                isRecording = sessionStatusModel!!.isRecording
        }
        initUI(view)
        requestPermissions()

        handleDragDialog()
        mDetector = GestureDetectorCompat(
            requireContext(),
            MyGestureListener({ showControlPanelTemporarily() }, { miniCircleDoubleTap() })
        )

        return view
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return this.parentView
    }

    override fun onPause() {
        super.onPause()
        if (mSession == null) {
            return
        }
        mSession!!.onPause()
        if (requireActivity().isFinishing) {
            disconnectSession()
        }
    }

    override fun onResume() {
        super.onResume()
        if (mSession == null) {
            return
        }
        mSession!!.onResume()
    }

    override fun onDestroy() {
        disconnectSession()
        cmTimer.stop()
        super.onDestroy()
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun initUI(view: View) {
        videoCallContainer = view.findViewById(R.id.video_call_ll)

        layoutName = view.findViewById(R.id.layout_name)
        layoutMini = view.findViewById(R.id.layout_mini)
        icMini = view.findViewById(R.id.ic_mini)
        recordContainer = view.findViewById(R.id.record_container)
        activity_clingo_video_call = view.findViewById(R.id.activity_clingo_video_call)

        thumbnail_container = view.findViewById(R.id.thumbnail_container)
        mPublisherViewContainer = view.findViewById(R.id.local_video_view_container)
        mPublisherViewIcon = view.findViewById(R.id.local_video_view_icon)
        mSubscriberViewIcon = view.findViewById(R.id.remote_video_view_icon)
        mSubscriberViewContainer = view.findViewById(R.id.remote_video_view_container)

        patientName = view.findViewById<TextView>(R.id.patient_name)
        patientName.text = sessionStatusModel!!.patientName

        if (isRecording) {
            recordContainer.visibility = View.VISIBLE
        } else {
            recordContainer.visibility = View.GONE
        }

//        cmTimer = view.findViewById(R.id.cmTimer)
        cmTimer.format = "mm:ss"
        cmTimer.onChronometerTickListener =
            Chronometer.OnChronometerTickListener { arg0: Chronometer? ->
//            val f: NumberFormat = DecimalFormat("00")
//            f.format(minutes)
                val minutes: Long
                val seconds: Long
                if (!resume) {
                    minutes = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 / 60
                    seconds = (SystemClock.elapsedRealtime() - cmTimer.base) / 1000 % 60
                    elapsedTime = SystemClock.elapsedRealtime()
                } else {
                    minutes = (elapsedTime - cmTimer.base) / 1000 / 60
                    seconds = (elapsedTime - cmTimer.base) / 1000 % 60
                    elapsedTime += 1000
                }
                val format = "%1$02d:%2$02d" // two digits

                arg0?.text = String.format(format, minutes, seconds)
                Log.d(TAG, "onChronometerTick: $minutes : $seconds")
            }

        icMini.setOnClickListener {
            onMiniCircleClicked()
        }

        controlPanel = view.findViewById(R.id.control_panel)
        videoCallPresenter = VideoCallPresenterImpl(this, baseUrl)
        mCallBtn = view.findViewById<ImageView>(R.id.btn_call)
        mCallBtn.setOnClickListener {
            onCallClicked()
        }
        btnMinimize = view.findViewById<ImageView>(R.id.btn_minimize)
        btnMinimize.setOnClickListener {
            onMinimizedClicked(it)
        }
        mCameraBtn = view.findViewById<ImageView>(R.id.btn_camera)
        mCameraBtn.setOnClickListener {
            onCameraClicked(it)
        }
        mSwitchCameraBtn = view.findViewById<ImageView>(R.id.btn_switch_camera)
        mSwitchCameraBtn.setOnClickListener {
            onSwitchCameraClicked(it)
        }
        mspeckerBtn = view.findViewById<ImageView>(R.id.btn_specker)
        mspeckerBtn.setOnClickListener {
            onSpeckerClicked(it)
        }
        mMicBtn = view.findViewById<ImageView>(R.id.btn_mic)
        mMicBtn.setOnClickListener {
            onMicClicked(it)
        }
        //  progressBarLayout=findViewById(R.id.progressBar);
        //   progressBar=findViewById(R.id.progress_bar);
//        progressBarTextView=findViewById(R.id.progress_bar_text);
//        progressBar.setVisibility(View.GONE);
//        hiddenButtons()
        checkClientConnected()
        handleVideoViewHeight(true)



        if (appLang == "ar") {
            progressBarLayout!!.layoutDirection = View.LAYOUT_DIRECTION_RTL
        }
    }

    private fun checkClientConnected() {
        mConnectedHandler = Handler((Looper.getMainLooper()))
        mConnectedRunnable = Runnable {
            if (!isConnected) {
                videoCallPresenter.callClintConnected(sessionStatusModel)
            }
        }
        mConnectedHandler!!.postDelayed(mConnectedRunnable!!, (55 * 1000).toLong())
    }

    private fun hiddenButtons() {
        mVolHandler = Handler()
        mVolRunnable = Runnable { controlPanel.visibility = View.GONE }
        mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong())
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String?>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
//        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
    }

//    override fun onPermissionsGranted(requestCode: Int, perms: List<String?>) {
//        Log.d(TAG, "onPermissionsGranted:" + requestCode + ":" + perms.size)
//    }
//
//    override fun onPermissionsDenied(requestCode: Int, perms: List<String?>) {
//        Log.d(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size)
//        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
//            AppSettingsDialog.Builder(this)
//                .setTitle(getString(R.string.title_settings_dialog))
//                .setRationale(getString(R.string.rationale_ask_again))
//                .setPositiveButton(getString(R.string.setting))
//                .setNegativeButton(getString(R.string.cancel))
//                .setRequestCode(RC_SETTINGS_SCREEN_PERM)
//                .build()
//                .show()
//        }
//    }

//    @AfterPermissionGranted(RC_VIDEO_APP_PERM)
    private fun requestPermissions() {
//        val perms = arrayOf(
//            Manifest.permission.INTERNET,
//            Manifest.permission.CAMERA,
//            Manifest.permission.RECORD_AUDIO,
//            Manifest.permission.MODIFY_AUDIO_SETTINGS,
//            Manifest.permission.CALL_PHONE
//        )
//        if (EasyPermissions.hasPermissions(requireContext(), *perms)) {
//            try {
//                mSession = Session.Builder(context, apiKey, sessionId).build()
//                mSession!!.setSessionListener(this)
//                mSession!!.connect(token)
//
//                mSession!!.setReconnectionListener(object :Session.ReconnectionListener{
//                    override fun onReconnecting(p0: Session?) {
//
//                    }
//
//                    override fun onReconnected(session: Session?) {
//                        session?.connect(token)
//                    }
//
//
//                })
//
//
//            } catch (e: Exception) {
//                e.printStackTrace()
//            }
//        } else {
//            EasyPermissions.requestPermissions(
//                this,
//                getString(R.string.remaining_ar),
//                RC_VIDEO_APP_PERM,
//                *perms
//            )
//        }
    }

    override fun onConnected(session: Session?) {
        Log.i(TAG, "Session Connected")
        mPublisher = Publisher.Builder(requireContext())
//                .name("publisher")
//                .renderer(ThumbnailCircleVideoRenderer(requireContext()))
            .build()
        mPublisher!!.setPublisherListener(this)
        if (mPublisher!!.view is GLSurfaceView) {
            (mPublisher!!.view as GLSurfaceView).setZOrderOnTop(true)
        }

        mPublisherViewContainer.addView(mPublisher!!.view)

        mSession!!.publish(mPublisher)

        if (!resume) {
            cmTimer.base = SystemClock.elapsedRealtime()
        }
        cmTimer.start()
        videoCallResponseListener?.minimizeVideoEvent(true)
    }

    override fun onDisconnected(session: Session) {
        Log.d(TAG, "onDisconnected: disconnected from session " + session.sessionId)
//        mSession = null
//        cmTimer.stop()
//        disconnectSession()
//        videoCallResponseListener?.minimizeVideoEvent(false)
    }

    override fun onError(session: Session, opentokError: OpentokError) {
        Log.d(TAG, "onError: Error (" + opentokError.message + ") in session " + session.sessionId)

        // videoCallResponseListener?.errorHandle("Error (" + opentokError.message + ") in session ")
//        dialog?.dismiss()
    }

    override fun onStreamReceived(session: Session, stream: Stream) {
        Log.d(TAG, "onStreamReceived: New stream " + stream.streamId + " in session " + session.sessionId)
        if (mSubscriber != null) {
            isConnected = true
            return
        }
        isConnected = true
        subscribeToStream(stream)
        if (mConnectedHandler != null && mConnectedRunnable != null)
            mConnectedHandler!!.removeCallbacks(mConnectedRunnable!!)
        videoCallPresenter.callChangeCallStatus(
            ChangeCallStatusRequestModel(
                3,
                sessionStatusModel!!.doctorId,
                sessionStatusModel!!.generalid,
                token,
                sessionStatusModel!!.vcid
            )
        )
    }

    override fun onStreamDropped(session: Session, stream: Stream) {
        Log.d(
            TAG,
            "onStreamDropped: Stream " + stream.streamId + " dropped from session " + session.sessionId
        )
        if (mSubscriber == null) {
            return
        }
        if (mSubscriber!!.stream == stream) {
            mSubscriberViewContainer.removeView(mSubscriber!!.view)
            mSubscriber!!.destroy()
            mSubscriber = null
        }
        //disconnectSession()
    }

    override fun onStreamCreated(publisherKit: PublisherKit?, stream: Stream) {
        Log.d(TAG, "onStreamCreated: Own stream " + stream.streamId + " created")
    }

    override fun onStreamDestroyed(publisherKit: PublisherKit?, stream: Stream) {
        Log.d(TAG, "onStreamDestroyed: Own stream " + stream.streamId + " destroyed")
    }

    override fun onError(publisherKit: PublisherKit?, opentokError: OpentokError) {
        Log.d(VideoCallFragment.TAG, "onError: Error (" + opentokError.message + ") in publisher")
        // videoCallResponseListener?.errorHandle("Error (" + opentokError.message + ") in publisher")
//        dialog?.dismiss()
    }

    override fun onVideoDataReceived(subscriberKit: SubscriberKit?) {
        mSubscriber!!.setStyle(
            BaseVideoRenderer.STYLE_VIDEO_SCALE,
            BaseVideoRenderer.STYLE_VIDEO_FILL
        )
        (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(false)
        mSubscriberViewContainer.addView(mSubscriber!!.view)
//        switchToThumbnailCircle()
    }

    fun switchToThumbnailCircle() {
        thumbnail_container.postDelayed({
            val view = mSubscriber!!.view
            if (view.parent != null) {
                (view.parent as ViewGroup).removeView(view)
            }
            if (view is GLSurfaceView) {
                view.setZOrderOnTop(true)
                if (mSubscriber!!.renderer is DynamicVideoRenderer) {
                    (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(true)
                    thumbnail_container.addView(view)
                }
            }
            switchToFullScreenView()
        }, 4000)
    }

    fun switchToFullScreenView() {
        mSubscriberViewContainer.postDelayed({
            val view = mSubscriber!!.view
            if (view.parent != null) {
                (view.parent as ViewGroup).removeView(view)
            }
            if (view is GLSurfaceView) {
                view.setZOrderOnTop(false)
                if (mSubscriber!!.renderer is DynamicVideoRenderer) {
                    (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(false)
                    mSubscriberViewContainer.addView(view)
                }
            }
            switchToThumbnailCircle()
        }, 4000)
    }

    override fun onVideoDisabled(subscriberKit: SubscriberKit?, s: String?) {
        Log.d(VideoCallFragment.TAG, "onVideoDisabled: Error ($s)")

//        if (isCircle) {
//            videoCallContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
//            mSubscriberViewContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
//        } else {
//            videoCallContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_color))
//            mSubscriberViewContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.remoteBackground))
//        }
    }

    override fun onVideoEnabled(subscriberKit: SubscriberKit?, s: String?) {
        Log.d(VideoCallFragment.TAG, "onVideoEnabled: Error ($s)")

//        if (mSubscriber != null) {
//            (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(isCircle)
//        }
    }

    override fun onVideoDisableWarning(subscriberKit: SubscriberKit?) {}

    override fun onVideoDisableWarningLifted(subscriberKit: SubscriberKit?) {}

    private fun subscribeToStream(stream: Stream) {
        mSubscriber = Subscriber.Builder(requireContext(), stream)
            .renderer(DynamicVideoRenderer(requireContext()))
            .build()
        mSubscriber!!.setVideoListener(this)
        mSession!!.subscribe(mSubscriber)
    }

    private fun disconnectSession() {
        if (mSession == null) {
            videoCallResponseListener?.onCallFinished(Activity.RESULT_CANCELED)
//            requireActivity().setResult(Activity.RESULT_CANCELED)
            dialog?.dismiss()
            return
        }

        if (mSubscriber != null) {
            mSubscriberViewContainer.removeView(mSubscriber!!.view)
            mSession!!.unsubscribe(mSubscriber)
            mSubscriber!!.destroy()
            mSubscriber = null
        }
        if (mPublisher != null) {
            mPublisherViewContainer.removeView(mPublisher!!.view)
            mSession!!.unpublish(mPublisher)
            mPublisher!!.destroy()
            mPublisher = null
        }
        mSession!!.disconnect()
        countDownTimer?.cancel()

        videoCallPresenter.callChangeCallStatus(
            ChangeCallStatusRequestModel(
                16,
                sessionStatusModel!!.doctorId,
                sessionStatusModel!!.generalid,
                token,
                sessionStatusModel!!.vcid
            )
        )
//        if(isDismiss)
//        dialog?.dismiss()
//        else
            onCallChangeCallStatusSuccessful()
    }

     fun onCallChangeCallStatusSuccessful(){
        val returnIntent = Intent()
        returnIntent.putExtra("CallEnd", sessionStatusModel)
        videoCallResponseListener?.onCallFinished(Activity.RESULT_CANCELED, returnIntent)
        dialog?.dismiss()
    }

    override fun onCallSuccessful(sessionStatusModel: SessionStatusModel) {
        if (sessionStatusModel.sessionStatus == 2 || sessionStatusModel.sessionStatus == 3) {
            val returnIntent = Intent()
            returnIntent.putExtra("sessionStatusNotRespond", sessionStatusModel)
            videoCallResponseListener?.onCallFinished(Activity.RESULT_OK, returnIntent)
//            requireActivity().setResult(Activity.RESULT_OK, returnIntent)
            dialog?.dismiss()
        }
    }

    override fun onCallChangeCallStatusSuccessful(sessionStatusModel: SessionStatusModel?) {}

    override fun onFailure() {}

    private fun onSwitchCameraClicked(view: View?) {
        if (mPublisher != null) {
            isSwitchCameraClicked = !isSwitchCameraClicked
            mPublisher!!.cycleCamera()
            val res = if (isSwitchCameraClicked) R.drawable.camera_front else R.drawable.camera_back
            mSwitchCameraBtn.setImageResource(res)
        }
    }

    fun onCallClicked() {
        disconnectSession()
    }

    private fun miniCircleDoubleTap() {
        if (isCircle) {
            onMiniCircleClicked()
        }
    }

    private fun onMiniCircleClicked() {
        if (isCircle) {
            dialog?.window?.setLayout(
                400,
                600
            )

        } else {
            dialog?.window?.setLayout(
                300,
                300
            )
        }
        isCircle = !isCircle


        if (mSubscriber != null) {
            (mSubscriber!!.renderer as DynamicVideoRenderer).enableThumbnailCircle(isCircle)
        } else {
            if (isCircle) {
                videoCallContainer.background =
                    ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
                mSubscriberViewContainer.background =
                    ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
            } else {
                videoCallContainer.setBackgroundColor(
                    ContextCompat.getColor(
                        requireContext(),
                        R.color.text_color
                    )
                )
                mSubscriberViewContainer.setBackgroundColor(
                    ContextCompat.getColor(
                        requireContext(),
                        R.color.remoteBackground
                    )
                )
            }
        }

        if (isCircle) {
            controlPanel.visibility = View.GONE
            layoutMini.visibility = View.GONE
        } else {
            controlPanel.visibility = View.VISIBLE
            layoutMini.visibility = View.VISIBLE
        }

        handleVideoViewHeight(isFullScreen)
    }

    private fun onMinimizedClicked(view: View?) {
        if (isFullScreen) {
            dialog?.window?.setLayout(
                400,
                600
            )
            recordContainer.visibility = View.GONE
        } else {
            dialog?.window?.setLayout(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.MATCH_PARENT
            )
            if (isRecording) {
                recordContainer.visibility = View.VISIBLE
            } else {
                recordContainer.visibility = View.GONE
            }
        }
        isFullScreen = !isFullScreen

        val res = if (isFullScreen) R.drawable.reducing else R.drawable.expand
        btnMinimize.setImageResource(res)
        setViewsVisibility()

//        videoCallResponseListener?.minimizeVideoEvent(!isFullScreen)
    }

    private fun setViewsVisibility() {
        val btnMinimizeLayoutParam: ConstraintLayout.LayoutParams =
            btnMinimize.layoutParams as ConstraintLayout.LayoutParams
        val mCallBtnLayoutParam: ConstraintLayout.LayoutParams =
            mCallBtn.layoutParams as ConstraintLayout.LayoutParams

        val iconSize: Int = requireContext().resources.getDimension(R.dimen.video_icon_size).toInt()
        val iconSizeSmall: Int =
            requireContext().resources.getDimension(R.dimen.video_icon_size_small).toInt()

        val localPreviewMargin: Int =
            requireContext().resources.getDimension(R.dimen.local_preview_margin_top).toInt()
        val localPreviewWidth: Int =
            requireContext().resources.getDimension(R.dimen.local_preview_width).toInt()
        val localPreviewHeight: Int =
            requireContext().resources.getDimension(R.dimen.local_preview_height).toInt()
//        val localPreviewIconSize: Int = context!!.resources.getDimension(R.dimen.local_back_icon_size).toInt()
//        val localPreviewMarginSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_margin_small).toInt()
//        val localPreviewWidthSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_width_small).toInt()
//        val localPreviewHeightSmall : Int = context!!.resources.getDimension(R.dimen.local_preview_height_small).toInt()
//        val localPreviewIconSmall: Int = context!!.resources.getDimension(R.dimen.local_back_icon_size_small).toInt()
//        val localPreviewLayoutIconParam : FrameLayout.LayoutParams
        val localPreviewLayoutParam: RelativeLayout.LayoutParams =
            mPublisherViewContainer.layoutParams as RelativeLayout.LayoutParams

        val remotePreviewIconSize: Int =
            requireContext().resources.getDimension(R.dimen.remote_back_icon_size).toInt()
        val remotePreviewIconSizeSmall: Int =
            requireContext().resources.getDimension(R.dimen.remote_back_icon_size_small).toInt()
        val remotePreviewLayoutParam: FrameLayout.LayoutParams =
            mSubscriberViewIcon.layoutParams as FrameLayout.LayoutParams

        if (isFullScreen) {
            layoutName.visibility = View.VISIBLE
            layoutMini.visibility = View.GONE
            mCameraBtn.visibility = View.VISIBLE
            mSwitchCameraBtn.visibility = View.VISIBLE
//            mspeckerBtn.visibility = View.VISIBLE
            mMicBtn.visibility = View.VISIBLE

            btnMinimizeLayoutParam.width = iconSize
            btnMinimizeLayoutParam.height = iconSize
            mCallBtnLayoutParam.width = iconSize
            mCallBtnLayoutParam.height = iconSize
//            localPreviewLayoutIconParam = FrameLayout.LayoutParams(localPreviewIconSize, localPreviewIconSize)
////            localPreviewLayoutParam = RelativeLayout.LayoutParams(localPreviewWidth, localPreviewHeight)
            localPreviewLayoutParam.width = localPreviewWidth
            localPreviewLayoutParam.height = localPreviewHeight
            localPreviewLayoutParam.setMargins(0, localPreviewMargin, localPreviewMargin, 0)
            if (mPublisher != null && mPublisher!!.view.parent == null) {
                mPublisherViewContainer.addView(mPublisher!!.view)
            }
            mPublisherViewContainer.visibility = View.VISIBLE

//            remotePreviewLayoutParam = FrameLayout.LayoutParams(remotePreviewIconSize, remotePreviewIconSize)
            remotePreviewLayoutParam.width = remotePreviewIconSize
            remotePreviewLayoutParam.height = remotePreviewIconSize
        } else {
            layoutName.visibility = View.GONE
            layoutMini.visibility = View.VISIBLE
            mCameraBtn.visibility = View.GONE
            mSwitchCameraBtn.visibility = View.GONE
//            mspeckerBtn.visibility = View.GONE
            mMicBtn.visibility = View.GONE
//            mPublisherViewContainer.visibility = View.GONE
//            mPublisherViewIcon.visibility = View.GONE

//            layoutParam = ConstraintLayout.LayoutParams(iconSizeSmall, iconSizeSmall)
            btnMinimizeLayoutParam.width = iconSizeSmall
            btnMinimizeLayoutParam.height = iconSizeSmall
            mCallBtnLayoutParam.width = iconSizeSmall
            mCallBtnLayoutParam.height = iconSizeSmall

            localPreviewLayoutParam.width = 0
            localPreviewLayoutParam.height = 0
            localPreviewLayoutParam.setMargins(0, localPreviewMargin / 2, localPreviewMargin / 2, 0)

            if (mPublisher != null) {
                mPublisherViewContainer.removeView(mPublisher!!.view)
            }
            mPublisherViewContainer.visibility = View.GONE
//            localPreviewLayoutIconParam = FrameLayout.LayoutParams(localPreviewIconSmall, localPreviewIconSmall)
////            localPreviewLayoutParam = RelativeLayout.LayoutParams(localPreviewWidthSmall, localPreviewHeightSmall)
//            localPreviewLayoutParam.width = localPreviewWidthSmall
//            localPreviewLayoutParam.height = localPreviewWidthSmall
//            localPreviewLayoutParam.setMargins(0,localPreviewMarginSmall, localPreviewMarginSmall, 0)
//            remotePreviewLayoutParam = FrameLayout.LayoutParams(remotePreviewIconSizeSmall, remotePreviewIconSizeSmall)
            remotePreviewLayoutParam.width = remotePreviewIconSizeSmall
            remotePreviewLayoutParam.height = remotePreviewIconSizeSmall

            if (isCircle) {
                controlPanel.visibility = View.GONE
                layoutMini.visibility = View.GONE
            } else {
                controlPanel.visibility = View.VISIBLE
                layoutMini.visibility = View.VISIBLE
            }
        }

        mPublisherViewContainer.layoutParams = localPreviewLayoutParam
//        mPublisherViewIcon.layoutParams = localPreviewLayoutIconParam
        mSubscriberViewIcon.layoutParams = remotePreviewLayoutParam

        btnMinimize.layoutParams = btnMinimizeLayoutParam
        mCallBtn.layoutParams = mCallBtnLayoutParam

        handleVideoViewHeight(isFullScreen)
    }

    private fun handleVideoViewHeight(isFullScreen: Boolean) {
        val layoutNameParam: ConstraintLayout.LayoutParams =
            layoutName.layoutParams as ConstraintLayout.LayoutParams
        val layoutMiniParam: ConstraintLayout.LayoutParams =
            layoutMini.layoutParams as ConstraintLayout.LayoutParams
        val controlPanelParam: ConstraintLayout.LayoutParams =
            controlPanel.layoutParams as ConstraintLayout.LayoutParams

        val layoutNameHeight: Int =
            requireContext().resources.getDimension(R.dimen.layout_name_height).toInt()
        val layoutMiniHeight: Int =
            requireContext().resources.getDimension(R.dimen.layout_mini_height).toInt()
        val panelHeight: Int = requireContext().resources.getDimension(R.dimen.layout_panel_height).toInt()
        val panelHeightSmall: Int =
            requireContext().resources.getDimension(R.dimen.layout_panel_height_small).toInt()

        val panelPadding: Int =
            requireContext().resources.getDimension(R.dimen.padding_space_big).toInt()
        val panelPaddingMedium: Int =
            requireContext().resources.getDimension(R.dimen.padding_space_medium).toInt()

        val temp = getStatusBarHeight() / 2

        val screenWidth: Float
        val screenHeight: Float

        if (isFullScreen) {
            screenWidth = ViewsUtil.getWidthDp(requireContext())
            screenHeight = ViewsUtil.getHeightDp(requireContext())

            layoutNameParam.height = layoutNameHeight + temp
            layoutMiniParam.height = 0
            controlPanelParam.height = panelHeight + temp

            controlPanel.setPadding(panelPadding, panelPadding, panelPadding, panelPadding)
        } else {

            if (isCircle) {
                screenWidth = 300F
                screenHeight = 300F

                layoutNameParam.height = 0
                layoutMiniParam.height = 0
                controlPanelParam.height = 0
            } else {
                screenWidth = 400F
                screenHeight = 600F

                layoutNameParam.height = 0
                layoutMiniParam.height = layoutMiniHeight
                controlPanelParam.height = panelHeightSmall
            }

            controlPanel.setPadding(
                panelPaddingMedium,
                panelPaddingMedium,
                panelPaddingMedium,
                panelPaddingMedium
            )
        }

        layoutName.layoutParams = layoutNameParam
        layoutMini.layoutParams = layoutMiniParam
        controlPanel.layoutParams = controlPanelParam

        var videoStreamHeight =
            screenHeight - controlPanelParam.height - layoutNameParam.height - layoutMiniParam.height

        if (isFullScreen) {
//            videoStreamHeight -= getStatusBarHeight() / 2
        }

        val callLayoutParam: ConstraintLayout.LayoutParams =
            activity_clingo_video_call.layoutParams as ConstraintLayout.LayoutParams

        callLayoutParam.height = videoStreamHeight.toInt()
        callLayoutParam.width = screenWidth.toInt()
    }

    private fun onCameraClicked(view: View?) {
        if (mPublisher != null) {
            isCameraClicked = !isCameraClicked
            mPublisher!!.publishVideo = !isCameraClicked
            val res = if (isCameraClicked) R.drawable.video_disabled else R.drawable.video_enabled
            mCameraBtn.setImageResource(res)

//            if (!isCameraClicked) {
//                videoCallContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
//                mSubscriberViewContainer.background = ContextCompat.getDrawable(requireContext(), R.drawable.circle_shape)
//            } else {
//                videoCallContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.text_color))
//                mSubscriberViewContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.remoteBackground))
//            }
        }
    }

    private fun onMicClicked(view: View?) {
        if (mPublisher != null) {
            isMicClicked = !isMicClicked
            mPublisher!!.publishAudio = !isMicClicked
            val res = if (isMicClicked) R.drawable.mic_disabled else R.drawable.mic_enabled
            mMicBtn!!.setImageResource(res)
        }
    }

    private fun onSpeckerClicked(view: View?) {
        if (mSubscriber != null) {
            isSpeckerClicked = !isSpeckerClicked
            mSubscriber!!.subscribeToAudio = !isSpeckerClicked
            val res = if (isSpeckerClicked) R.drawable.audio_disabled else R.drawable.audio_enabled
            mspeckerBtn.setImageResource(res)
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun handleDragDialog() {
        mWindowManager = requireActivity().getSystemService(Context.WINDOW_SERVICE) as WindowManager
        getWindowManagerDefaultDisplay()

        videoCallContainer.setOnTouchListener(dragListener)
        mSubscriberViewContainer.setOnTouchListener(dragListener)
    }

    @SuppressLint("ClickableViewAccessibility")
    private val dragListener: View.OnTouchListener = View.OnTouchListener { _, event ->
        mDetector.onTouchEvent(event)

        //Get Floating widget view params
        val layoutParams: WindowManager.LayoutParams = dialog!!.window!!.attributes
        //get the touch location coordinates
        val x_cord = event.rawX.toInt()
        val y_cord = event.rawY.toInt()
        val x_cord_Destination: Int
        var y_cord_Destination: Int

        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                x_init_cord = x_cord
                y_init_cord = y_cord

                //remember the initial position.
                x_init_margin = layoutParams.x
                y_init_margin = layoutParams.y
            }
            MotionEvent.ACTION_UP -> {
                //Get the difference between initial coordinate and current coordinate
                val x_diff: Int = x_cord - x_init_cord
                val y_diff: Int = y_cord - y_init_cord

                y_cord_Destination = y_init_margin + y_diff
                val barHeight: Int = getStatusBarHeight()
                if (y_cord_Destination < 0) {
//                        y_cord_Destination = 0
//                    y_cord_Destination =
//                            -(szWindow.y - (videoCallContainer.height /*+ barHeight*/))
                    y_cord_Destination = -(szWindow.y / 2)
                } else if (y_cord_Destination + (videoCallContainer.height + barHeight) > szWindow.y) {
//                    y_cord_Destination = szWindow.y - (videoCallContainer.height + barHeight)
                    y_cord_Destination = (szWindow.y / 2)
                }
                layoutParams.y = y_cord_Destination

                //reset position if user drags the floating view
                resetPosition(x_cord)
            }
            MotionEvent.ACTION_MOVE -> {
                val x_diff_move: Int = x_cord - x_init_cord
                val y_diff_move: Int = y_cord - y_init_cord
                x_cord_Destination = x_init_margin + x_diff_move
                y_cord_Destination = y_init_margin + y_diff_move

                layoutParams.x = x_cord_Destination
                layoutParams.y = y_cord_Destination

                dialog!!.window!!.attributes = layoutParams
            }
        }
        true
    }

    private fun showControlPanelTemporarily() {
        if (!isCircle) {
            controlPanel.visibility = View.VISIBLE
            mVolHandler!!.removeCallbacks(mVolRunnable!!)
            mVolHandler!!.postDelayed(mVolRunnable!!, (5 * 1000).toLong())
        }
    }

    /*  Reset position of Floating Widget view on dragging  */
    private fun resetPosition(x_cord_now: Int) {
        if (x_cord_now <= szWindow.x / 2) {
            isLeft = true
            moveToLeft(x_cord_now)
        } else {
            isLeft = false
            moveToRight(x_cord_now)
        }
    }

    /*  Method to move the Floating widget view to Left  */
    private fun moveToLeft(current_x_cord: Int) {

        var mParams: WindowManager.LayoutParams = dialog!!.window!!.attributes

        mParams.x =
            (szWindow.x - current_x_cord * current_x_cord - videoCallContainer.width).toInt()

        dialog!!.window!!.attributes = mParams
        val x = szWindow.x - current_x_cord
        object : CountDownTimer(500, 5) {
            //get params of Floating Widget view
            var mParams: WindowManager.LayoutParams = dialog!!.window!!.attributes
            override fun onTick(t: Long) {
                val step = (500 - t) / 5
                //   mParams.x = 0 - (current_x_cord * current_x_cord * step).toInt()
                mParams.x =
                    (szWindow.x - current_x_cord * current_x_cord * step - videoCallContainer.width).toInt()

                dialog?.window?.attributes = mParams
            }

            override fun onFinish() {
                mParams.x = -(szWindow.x - videoCallContainer.width)

                dialog?.window!!.attributes = mParams
            }
        }.start()
    }

    /*  Method to move the Floating widget view to Right  */
    private fun moveToRight(current_x_cord: Int) {
//        var mParams : WindowManager.LayoutParams = dialog!!.window!!.attributes
//        mParams.x =
//            (szWindow.x + current_x_cord * current_x_cord  - videoCallContainer.width).toInt()
//
//        dialog!!.window!!.attributes = mParams
        object : CountDownTimer(500, 5) {
            //get params of Floating Widget view
            var mParams: WindowManager.LayoutParams = dialog!!.window!!.attributes
            override fun onTick(t: Long) {
                val step = (500 - t) / 5
                mParams.x =
                    (szWindow.x + current_x_cord * current_x_cord * step - videoCallContainer.width).toInt()

                dialog!!.window!!.attributes = mParams
            }

            override fun onFinish() {
                mParams.x = szWindow.x - videoCallContainer.width

                dialog?.window!!.attributes = mParams
            }
        }.start()
    }

    private fun getWindowManagerDefaultDisplay() {
        mWindowManager.getDefaultDisplay()
            .getSize(szWindow)
    }

    /*  return status bar height on basis of device display metrics  */
    private fun getStatusBarHeight(): Int {
        return ceil(
            (25 * requireActivity().applicationContext.resources.displayMetrics.density).toDouble()
        ).toInt()
    }

    private class MyGestureListener(
        val onTabCall: () -> Unit,
        val miniCircleDoubleTap: () -> Unit
    ) : GestureDetector.SimpleOnGestureListener() {

        override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
//            onTabCall()
            return true
        }

//        override fun onDoubleTap(e: MotionEvent?): Boolean {
//            miniCircleDoubleTap()
//            return super.onDoubleTap(e)
//        }

    }

    companion object {
        @JvmStatic
        fun newInstance(args: Bundle) =
            VideoCallFragment().apply {
                arguments = args
            }

        private val TAG = VideoCallFragment::class.java.simpleName

        private const val RC_SETTINGS_SCREEN_PERM = 123
        private const val RC_VIDEO_APP_PERM = 124

    }
}