package com.lovense.sdkdemo

import android.annotation.SuppressLint
import android.media.AudioManager
import android.media.MediaPlayer
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import android.view.MenuItem
import android.view.inputmethod.EditorInfo
import android.widget.PopupMenu
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView.OnEditorActionListener
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.component.toymodule.bussiness.pattern.OnPrepareCallback
import com.lovense.sdkdemo.databinding.ActivityPlayPatternBinding
import com.lovense.sdklibrary.Lovense
import com.lovense.sdklibrary.LovenseToy
import com.lovense.sdklibrary.callBack.LovenseError
import com.lovense.sdklibrary.callBack.OnConnectListener
import java.io.IOException
import kotlin.math.roundToInt

/**
 * <pre>
 * author : liutangsheng
 * time   : 2023/05/31
 * desc   : pattern播放测试页面，对外SDK没有提供
</pre> *
 */
class PatternPlayActivity : AppCompatActivity(), OnConnectListener, OnPrepareCallback {

    companion object {
        const val UPDATE_PROGRESS = 0xa
        const val MSG_SHOW = 0xb
    }

    private var lovense: Lovense? = null
    private lateinit var toyId: String
    private var mediaPlayer: MediaPlayer? = null

    private var mediaId = "l121"//""V1000"
    private var isPrepared = false
    private var prepareRetryCount = 0 // prepare count
    private lateinit var binding: ActivityPlayPatternBinding

    private val handler: Handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            if (msg.what == UPDATE_PROGRESS) {
                val currentPosition = mediaPlayer?.currentPosition ?: 0
                val progress = currentPosition * 1000 / (mediaPlayer?.duration ?: 0)
                binding.seekbar.progress = progress
                binding.tvPosition.text = formatDuration((currentPosition / 1000).toLong())
                sendEmptyMessageDelayed(UPDATE_PROGRESS, 100)
            } else if (msg.what == MSG_SHOW && prepareRetryCount < 4) {
                val errorMsg = msg.obj as String
                mediaId = "l121"//""V1000"
                lovense?.stop()
                lovense?.prepareForPatternWithMediaID(mediaId, this@PatternPlayActivity)
                Toast.makeText(this@PatternPlayActivity, errorMsg, Toast.LENGTH_LONG).show()
                prepareRetryCount ++
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityPlayPatternBinding.inflate(layoutInflater)
        setContentView(binding.root)
        toyId = intent.getStringExtra("toyId") ?: ""

        setSupportActionBar(binding.toolbar)

        binding.tvMediaId.text = String.format("MediaId:%s", mediaId)
        binding.inputMediaId.setOnEditorActionListener(OnEditorActionListener { v, actionId, event ->
            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                val inputMediaId = binding.inputMediaId.text.toString().trim()
                if (inputMediaId.isNotEmpty()) {
                    mediaId = inputMediaId
                    binding.tvMediaId.text = String.format("MediaId:%s", mediaId)
                    lovense?.stop()
                    lovense?.prepareForPatternWithMediaID(mediaId, this@PatternPlayActivity)
                }
                return@OnEditorActionListener true
            }
            false
        })

        binding.seekbar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {}
            override fun onStartTrackingTouch(seekBar: SeekBar) {
                if (isPrepared && mediaPlayer?.isPlaying == true) {
                    dispatchPlayAction()
                }
            }
            override fun onStopTrackingTouch(seekBar: SeekBar) {
                val scale = seekBar.progress / 1000f
                val position = ((mediaPlayer?.duration ?: 0) * scale).roundToInt()
                lovense?.syncCurrentTime(position.toLong())
                mediaPlayer?.seekTo(position)
                handler.removeMessages(UPDATE_PROGRESS)
                if (isPrepared && mediaPlayer?.isPlaying == false) {
                    dispatchPlayAction()
                }
            }
        })

        binding.ivPlay.setOnClickListener { dispatchPlayAction() }
        binding.tvSpeed.setOnClickListener { showSpeedMenu() }
        lovense = Lovense.getInstance(application)
        lovense?.connectToy(toyId, this)

        //V1000&pf=t0
        mediaPlayer = MediaPlayer()
        mediaPlayer?.setOnPreparedListener { mp ->
            isPrepared = true
            binding.ivPlay.isEnabled = true
            mp.start()
            lovense?.playPattern(
                mediaPlayer?.currentPosition?.toLong()?:0,
                mediaPlayer?.duration?.toLong()?:0
            )
            binding.tvDuration.text = formatDuration((mp.duration / 1000).toLong())
            handler.sendEmptyMessage(UPDATE_PROGRESS)
        }
        mediaPlayer?.setOnSeekCompleteListener { handler.sendEmptyMessage(UPDATE_PROGRESS) }
        mediaPlayer?.setOnCompletionListener { mp ->
            handler.removeMessages(UPDATE_PROGRESS)
            mp.reset()
            isPrepared = false
            binding.tvSpeed.text = "1.0X"
            binding.ivPlay.setImageResource(R.mipmap.music_minibar_play)
        }
        mediaPlayer?.setAudioStreamType(AudioManager.STREAM_MUSIC)
    }

    private fun showSpeedMenu() {
        val popupMenu = PopupMenu(this, binding.tvSpeed)
        popupMenu.menuInflater.inflate(R.menu.speed_menu, popupMenu.menu)
        popupMenu.setOnMenuItemClickListener { item -> setRate(item) }
        popupMenu.show()
    }

    @SuppressLint("SetTextI18n")
    private fun setRate(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.speed_0_5 -> {
                setMediaPlayerRate(0.5f)
                binding.tvSpeed.text = "0.5X"
                return true
            }

            R.id.speed_1_0 -> {
                setMediaPlayerRate(1.0f)
                binding.tvSpeed.text = "1.0X"
                return true
            }

            R.id.speed_1_5 -> {
                setMediaPlayerRate(1.5f)
                binding.tvSpeed.text = "1.5X"
                return true
            }

            R.id.speed_2_0 -> {
                setMediaPlayerRate(2.0f)
                binding.tvSpeed.text = "2.0X"
                return true
            }
        }
        return false
    }

    private fun setMediaPlayerRate(speed: Float) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && isPrepared) {
            mediaPlayer?.playbackParams?.setSpeed(speed)
            lovense?.setRate(speed)
        }
    }

    private fun dispatchPlayAction() {
        if (isPrepared) {
            if (mediaPlayer?.isPlaying == true) {
                mediaPlayer?.pause()
                binding.ivPlay.setImageResource(R.mipmap.music_minibar_play)
                handler.removeMessages(UPDATE_PROGRESS)
                lovense?.stop()
            } else {
                mediaPlayer?.start()
                lovense?.playPattern(
                    mediaPlayer?.currentPosition?.toLong()?:0,
                    mediaPlayer?.duration?.toLong()?:0
                )
                handler.sendEmptyMessage(UPDATE_PROGRESS)
                binding.ivPlay.setImageResource(R.mipmap.music_minibar_pause)
            }
        } else {
            try {
                //https://cdn.lovense.com/oss/mediaPattern/audio/20230525/2db2f37968e245feb54460f140b69e27.mp3
                //https://test1.lovense.com/oss/media/m3u8/20230407/e1ea5b44007b43ccb080da0c5e813ca5/index.m3u8
                mediaPlayer?.apply {
                    setDataSource("https://test1.lovense.com/oss/media/m3u8/20230407/e1ea5b44007b43ccb080da0c5e813ca5/index.m3u8")
                    prepareAsync()
                }
                binding.ivPlay.apply {
                    isEnabled = false
                    setImageResource(R.mipmap.music_minibar_pause)
                }
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (item.itemId == android.R.id.home) {
            finish()
            return true
        }
        return super.onOptionsItemSelected(item)
    }

    override fun onConnect(toyId: String, status: String) {
        when (status) {
            LovenseToy.STATE_CONNECTED -> {
                Toast.makeText(this, "Connect Toy Success", Toast.LENGTH_SHORT).show()
                lovense?.setupPatternPlayerWithToyIds(
                    arrayListOf(toyId),
                    "lovense" //if (BuildConfig.DEBUG) "t0" else "Audiodesires"
                )

                // init pattern data
                lovense?.stop()
                lovense?.prepareForPatternWithMediaID(mediaId, this)
            }
        }
    }

    override fun onError(error: LovenseError) {}
    private fun formatDuration(duration: Long): String {
        val builder = StringBuilder()
        if (duration / 60 >= 10) {
            builder.append(duration / 60)
        } else {
            builder.append("0")
            builder.append(duration / 60)
        }
        builder.append(":")

        if (duration % 60 >= 10) {
            builder.append(duration % 60)
        } else {
            builder.append("0")
            builder.append(duration % 60)
        }
        return builder.toString()
    }

    override fun onDestroy() {
        super.onDestroy()
        mediaPlayer?.reset()
        mediaPlayer?.release()
        lovense?.stop()
        handler.removeMessages(UPDATE_PROGRESS)
        Lovense.getInstance(application).disconnect(toyId)
    }

    override fun onComplete() {
        prepareRetryCount = 0
    }
    override fun onError(errorMsg: String?) {
        val message = Message.obtain()
        message.what = MSG_SHOW
        message.obj = errorMsg ?: ""
        handler.sendMessage(message)
        Log.e("Pattern Activity", "prepare pattern error = $errorMsg prepareRetryCount = $prepareRetryCount")
    }

}
