package com.ydl.media.audio

import android.content.Context
import android.content.IntentFilter
import android.media.AudioManager
import android.os.Handler
import android.os.Looper
import com.tencent.bugly.Bugly.applicationContext
import com.ydl.media.audio.enums.PlayModeEnum
import com.ydl.media.audio.manager.AudioFocusManager
import com.ydl.media.audio.manager.MediaSessionManager
import com.ydl.media.audio.manager.NotifyManager
import com.ydl.media.audio.model.Music
import com.ydl.media.audio.receiver.NoisyAudioStreamReceiver
import com.ydl.media.audio.utils.PlayProgressUtil
import com.ydl.ydlcommon.event.MeditationFloatStopEvent
import com.ydl.ydlcommon.utils.LogUtil
import com.yidianling.common.tools.ToastUtil
import de.greenrobot.event.EventBus
import tv.danmaku.ijk.media.player.IMediaPlayer
import tv.danmaku.ijk.media.player.IjkMediaPlayer
import java.io.IOException
import java.util.*
import kotlin.collections.ArrayList


/**
 * Created by haorui on 2019-10-27 .
 * Des:
 */
class AudioPlayer private constructor() {

    private var context: Context? = null
    private var audioFocusManager: AudioFocusManager? = null
    var mediaPlayer: IMediaPlayer? = null
    private var handler: Handler? = null
    private var noisyReceiver: NoisyAudioStreamReceiver? = null
    private var noisyFilter: IntentFilter? = null
    private val musicList: MutableList<Music> = ArrayList()
    private val listeners = ArrayList<OnPlayerEventListener>()
    private var state = STATE_IDLE

    private val mPublishRunnable = object : Runnable {
        override fun run() {
            if (isPlaying) {
                val current = (mediaPlayer!!.currentPosition * 1.0).toFloat()
                val du = mediaPlayer!!.duration.toFloat()
                val percent = (current * 100 / du).toInt()
                //保存进度
                if (autoSaveProgress) {
                    PlayProgressUtil.saveProgress(
                        context,
                        playMusic!!.path,
                        (if (percent == 99 || percent == 100) 0 else current.toInt())
                    )
                }
                for (listener in listeners) {
                    listener.onPublish(percent, current.toLong())
                }
            }
            handler!!.postDelayed(this, TIME_UPDATE)
        }
    }

    val audioSessionId: Int
        get() = if (mediaPlayer != null) mediaPlayer!!.audioSessionId else 0

    val currentPosition: Long
        get() = if (isPlaying || isPausing) {
            mediaPlayer!!.currentPosition
        } else {
            0
        }

    val playMusic: Music?
        get() = if (musicList.isEmpty()) {
            null
        } else musicList[playPosition]

    val isPlaying: Boolean
        get() = state == STATE_PLAYING

    val isPausing: Boolean
        get() = state == STATE_PAUSE

    val isPreparing: Boolean
        get() = state == STATE_PREPARING

    val isIdle: Boolean
        get() = state == STATE_IDLE

    private var playPosition: Int = 0
        get() {
            if (field < 0 || field >= musicList.size) {
                field = 0
            }
            return field
        }

    /**
     * 设置播放模式
     * 默认为列表循环
     */
    var playMode = PlayModeEnum.LIST_LOOP

    /**
     * 是否自动保存播放进度
     */
    var autoSaveProgress = false

    /**
     * 是否显示通知栏
     */
    var isShowNotify = false

    private object SingletonHolder {
        val instance = AudioPlayer()
    }

    /**
     * 初始化播放器
     */
    fun init(context: Context) {
        this.context = context.applicationContext
        audioFocusManager = AudioFocusManager(context)
        try {
            mediaPlayer = IjkMediaPlayer().also {
                it.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1)
                it.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1)
            }
        } catch (e: Exception) {
            LogUtil.e(e.message)
        }
        mediaPlayer!!.setOnPreparedListener {
            // TODO: 2022/8/4 startPlayer 和 onPrepared 调用顺序不对
            if (isPreparing) {
                if (autoSaveProgress) {
                    //自动播放
                    val time = PlayProgressUtil.getProgress(context, playMusic!!.path)
                    if (time > 0) {
                        startPlayer()
                        seekTo(position = time.toLong())
                    } else {
                        startPlayer()
                    }
                } else {
                    startPlayer()
                }
            }
            for (listener in listeners) {
                listener.onPrepared(mediaPlayer!!.duration)
            }
        }
        mediaPlayer!!.setOnBufferingUpdateListener { _, percent ->
            for (listener in listeners) {
                listener.onBufferingUpdate(percent)
            }
        }
        mediaPlayer!!.setOnCompletionListener {
            if (autoSaveProgress) {
                PlayProgressUtil.saveProgress(applicationContext, playMusic!!.path, 0)
            }

            for (listener in listeners) {
                listener.onComplete()
            }

            when (playMode) {
                PlayModeEnum.SINGLE -> {
                    resetPlayer()
                    playMode = PlayModeEnum.LIST_LOOP
                }
                PlayModeEnum.LIST -> {
                    if (playPosition >= musicList.lastIndex) pausePlayer()
                    else {
                        next()
                    }
                }
                else -> next()
            }
        }
        handler = Handler(Looper.getMainLooper())
        noisyReceiver = NoisyAudioStreamReceiver()
        noisyFilter = IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)

    }

    /**
     * 添加播放监听
     */
    fun addOnPlayEventListener(listener: OnPlayerEventListener) {
        if (!listeners.contains(listener)) {
            listeners.add(listener)
        }
    }

    /**
     * 移除播放监听
     */
    fun removeOnPlayEventListener(listener: OnPlayerEventListener) {
        listeners.remove(listener)
    }

    /**
     * 添加播放列表
     */
    fun addPlayList(music: ArrayList<Music>) {
        if (music.isEmpty()) {
            return
        }
        musicList.clear()
        musicList.addAll(music)
        autoSaveProgress = false
    }

    /**
     * 单曲模式播放音乐
     */
    fun singlePlay(music: Music, isAutoSaveProgress: Boolean = false) {
        musicList.clear()
        musicList.add(music)
        playMode = PlayModeEnum.SINGLE
        autoSaveProgress = isAutoSaveProgress
        load(0)
    }

    /**
     * 单曲循环模式播放音乐
     */
    fun singleCirclePlay(music: Music) {
        musicList.clear()
        musicList.add(music)
        playMode = PlayModeEnum.SINGLE_LOOP
        autoSaveProgress = false
        load(0)
    }

    /**
     * 添加后自动播放
     */
    fun addAndPlay(music: Music) {
        var position = musicList.indexOf(music)
        if (position < 0) {
            musicList.add(music)
            position = musicList.size - 1
        }
        load(position)
    }

    /**
     * 播放第一首
     */
    fun play() {
        load(0)
    }

    /**
     * 加载指定索引的音乐
     */
    fun load(index: Int) {
        if (musicList.isEmpty()) return
        var position = index
        if (position < 0) {
            position = musicList.size - 1
        } else if (position >= musicList.size) {
            position = 0
        }
        listeners.forEach {
            if (!it.onPreLoad(position)) return
        }
        playPosition = position
        val music = playMusic

        try {
            mediaPlayer!!.reset()
            mediaPlayer!!.dataSource = music!!.path
            mediaPlayer!!.prepareAsync()
            state = STATE_PREPARING
            for (listener in listeners) {
                listener.onLoad(music)
            }
            if (isShowNotify) {
                NotifyManager.get().showPlay(music)
                MediaSessionManager.get().updateMetaData(music)
                MediaSessionManager.get().updatePlaybackState()
            }
        } catch (e: IOException) {
            e.printStackTrace()
            ToastUtil.toastShort("当前歌曲无法播放")
        }

    }

    /**
     * 从列表里移除播放音乐
     */
    fun delete(position: Int) {
        musicList.removeAt(position)
        if (playPosition > position) {
            playPosition -= 1
        } else if (playPosition == position) {
            if (isPlaying || isPreparing) {
                playPosition -= 1
                next()
            } else {
                resetPlayer()
                for (listener in listeners) {
                    listener.onLoad(playMusic!!)
                }
            }
        }
    }

    /**
     * 暂停或者播放音乐
     */
    fun playOrPause() {
        when {
            isPreparing -> {
                resetPlayer()
            }
            isPlaying -> {
                pausePlayer()
            }
            isPausing -> {
                startPlayer()
            }
            else -> {
                load(playPosition)
            }
        }
    }

    /**
     *开始播放
     */
    fun startPlayer() {
        if (!isPreparing && !isPausing) {
            return
        }
        if (audioFocusManager!!.requestAudioFocus()) {
            mediaPlayer!!.start()
            state = STATE_PLAYING
            handler!!.post(mPublishRunnable)
            if (isShowNotify) {
                NotifyManager.get().showPlay(playMusic)
                MediaSessionManager.get().updatePlaybackState()
            }
            context!!.registerReceiver(noisyReceiver, noisyFilter)
            for (listener in listeners) {
                listener.onStartPlay()
            }
        }

        val event = MeditationFloatStopEvent(show = false, stop = true, time = null)
        EventBus.getDefault().post(event)

    }

    /**
     * 暂停播放器
     */
    @JvmOverloads
    fun pausePlayer(abandonAudioFocus: Boolean = true) {
        if (!isPlaying) {
            return
        }

        mediaPlayer!!.pause()
        state = STATE_PAUSE
        handler!!.removeCallbacks(mPublishRunnable)
        if (isShowNotify) {
            NotifyManager.get().showPause(playMusic)
            MediaSessionManager.get().updatePlaybackState()
        }
        context!!.unregisterReceiver(noisyReceiver)
        if (abandonAudioFocus) {
            audioFocusManager!!.abandonAudioFocus()
        }

        for (listener in listeners) {
            listener.onPausePlay()
        }
    }

    /**
     * 停止播放器
     */
    fun resetPlayer() {
        if (isIdle) {
            return
        }

        pausePlayer()
        musicList.clear()
        mediaPlayer!!.reset()
        state = STATE_IDLE
    }

    fun getNextPosition(position: Int): Int {
        return when (playMode) {
            PlayModeEnum.SHUFFLE -> Random().nextInt(musicList.size)
            PlayModeEnum.SINGLE_LOOP -> position
            PlayModeEnum.LIST_LOOP -> if (position >= musicList.lastIndex) 0 else position + 1
            PlayModeEnum.LIST -> if (position >= musicList.lastIndex) -1 else position + 1
            else -> position + 1
        }
    }

    /**
     * 下一首
     */
    fun next() {
        if (musicList.isEmpty()) {
            return
        }
        val position = getNextPosition(playPosition)
        if (-1 == position) {
            ToastUtil.toastShort("暂无内容")
            return
        }
        load(position)
    }

    /**
     * 上一首
     */
    fun prev() {
        if (musicList.isEmpty()) {
            return
        }
        val position = when (playMode) {
            PlayModeEnum.SHUFFLE -> Random().nextInt(musicList.size)
            PlayModeEnum.SINGLE_LOOP -> playPosition
            PlayModeEnum.LIST_LOOP -> if (playPosition <= 0) musicList.lastIndex else playPosition - 1
            PlayModeEnum.LIST -> if (playPosition <= 0) -1 else playPosition - 1
            else -> playPosition - 1
        }
        if (-1 == position) {
            ToastUtil.toastShort("暂无内容")
            return
        }
        load(position)
    }

    /**
     * 跳转到指定的时间位置
     * @param percent 百分比
     * @param position 时间点
     */
    fun seekTo(percent: Int = -1, position: Long = -1) {
        if (isPlaying || isPausing) {
            val duration = getDuration()
            val currentPercent: Int
            val currentPosition = if (position != -1L) {
                val pos = when {
                    position > duration -> duration
                    position < 0 -> 0L
                    else -> position
                }
                currentPercent = (pos / duration).toInt()
                pos
            } else {
                currentPercent = when {
                    percent > 100 -> 100
                    percent < 0 -> 0
                    else -> percent
                }
                currentPercent * duration / 100
            }
            mediaPlayer!!.seekTo(currentPosition)
            MediaSessionManager.get().updatePlaybackState()
            if (autoSaveProgress) {
                PlayProgressUtil.saveProgress(
                    context,
                    musicList[playPosition].coverPath,
                    currentPosition.toInt()
                )
            }
            for (listener in listeners) {
                listener.onPublish(currentPercent, currentPosition)
            }
        }
    }

    /**
     * 获取播放列表
     */
    fun getMusicList(): List<Music> {
        return musicList
    }

    /**
     * 获取音乐时长
     */
    fun getDuration(): Long {
        return mediaPlayer?.duration ?: 0
    }

    companion object {
        // TODO: 2022/8/4 缺少完成状态和出错状态,目前看代码逻辑是
        // TODO: 2022/8/4 正常播放完,到下一首加载前都是 STATE_PLAYING 状态,如果播放链接出错,则到下一首加载前是 STATE_PREPARING 状态
        private val STATE_IDLE = 0
        private val STATE_PREPARING = 1
        private val STATE_PLAYING = 2
        private val STATE_PAUSE = 3

        private val TIME_UPDATE = 300L

        fun get(): AudioPlayer {
            return SingletonHolder.instance
        }
    }

    /**
     * 设置倍速播放
     */
    fun setSpeed(speed: Float) {
        (mediaPlayer as? IjkMediaPlayer)?.setSpeed(speed)
    }

    /**
     * 获取播放倍速
     */
    fun getSpeed(): Float = (mediaPlayer as? IjkMediaPlayer)?.getSpeed(0f) ?: 1f
}
