package com.yidianling.ydlcommon.custom.player.service

import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.media.AudioManager
import android.net.Uri
import android.os.Binder
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.support.v4.content.ContextCompat
import android.widget.RemoteViews
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.NotificationTarget
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.source.ExtractorMediaSource
import com.google.android.exoplayer2.source.TrackGroupArray
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util
import com.yidianling.common.tools.LogUtil
import com.yidianling.ydlcommon.R
import com.yidianling.ydlcommon.custom.player.MusicInfoBean
import com.yidianling.ydlcommon.custom.player.YDLMusicHelper
import com.yidianling.ydlcommon.custom.player.notifycation.NotificationHelper
import com.yidianling.ydlcommon.custom.player.player.PlayStatusListener
import com.yidianling.ydlcommon.custom.player.util.LogH
import com.yidianling.ydlcommon.custom.player.util.UtilH
import java.util.*
import kotlin.collections.ArrayList

/**
 * Created by hgw on 2018/4/6.
 */
class HMusicPlayService : Service() {

    private var timer: Timer = Timer()

    private var isPlayWhenLoss = false

    //    private var media: MediaPlayer? = null
    private var player: SimpleExoPlayer? = null
    private var musicList: ArrayList<MusicInfoBean> = ArrayList()
    private var binder: MusicController? = null

    //缓冲进度 百分数
    private var bufferProgress = 0

    private var currentIndex = 0
    //异步初始化完成是否自动播放
    private var autoPlay = false
    //自动播放下一曲
    private var autoPlayNext = false //
    //自动保存进度
    private var autoSaveProgress = false
    //是否加载中
    private var loading = false
    //是否开启通知栏
    private var isOpenNotifyCation = false

    //通知栏布局
    var remoteViews: RemoteViews? = null

    //当前播放URL
    var currentUrl: String? = null

    var handler = Handler(Looper.getMainLooper())

    companion object {
        val ONSTART = "harvie_ONSTART"
        val ONSTART_NEW = "harvie_ONSTART_NEW" //播放新的音频
        val INDEX = "harvie_INDEX" //需要播放的音频下标
        val ONDESTROY = "harvie_ONDESTROY"

        val ACTION = "harvie_ACTION" //

        //通知栏操作action
        val TAG = HMusicPlayService::class.java.simpleName!!
        val ACTION_PLAY = "harvie_play"
        val ACTION_PAUSE = "harvie_pause"
        val ACTION_STOP = "harvie_stop"
        val ACTION_DETAIL = "harvie_detail"
        val REQUEST_CODE = 104

        val NOTIFY_ID = 114

    }

    override fun onCreate() {
        super.onCreate()
        binder = MusicController()
        initPlayer()

        initListener()

        requestAudioFocus()

        handler.postDelayed({
            timer.schedule(timerTask, 0, 600)
        }, 500)

    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

        var bundle = intent?.getBundleExtra("bundle")
        var action = bundle?.getString(ACTION) ?: ""
        when (action) {
            ONSTART -> {
                startS()
            }
            ONSTART_NEW -> {
                var index = bundle?.getInt(INDEX, -1) ?: -1
                if (index > -1) {
                    playS(index)
                }
            }
            ACTION_PAUSE ->
                pauseS(true)
            ACTION_STOP -> {
                pauseS(false)
                //移除通知栏
                var myNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
                myNotificationManager.cancel(NOTIFY_ID)
            }
            ONDESTROY ->
                onDestroy()
        }

        return super.onStartCommand(intent, flags, startId)
    }


    private fun initPlayer() {
        //创建带宽对象
        val bandwidthMeter = DefaultBandwidthMeter()
        //根据当前宽带来创建选择磁道工厂对象
        val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory(bandwidthMeter)
        //传入工厂对象，以便创建选择磁道对象
        var trackSelector = DefaultTrackSelector(videoTrackSelectionFactory)
        //根据选择磁道创建播放器对象
        player = ExoPlayerFactory.newSimpleInstance(application, trackSelector)
        player!!.playWhenReady = false
    }

    private fun initListener() {
        player!!.addListener(object : ExoPlayer.EventListener {

            override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {
                LogUtil.e("onTracksChanged")
            }

            override fun onLoadingChanged(isLoading: Boolean) {
                LogUtil.e("onLoadingChanged=$isLoading")
            }

            override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
                when (playbackState) {
                    Player.STATE_ENDED -> {
                        LogUtil.e("Player.STATE_ENDED")
                        //播放完成后把当前的时间置为初始状态
                        if (autoSaveProgress) {
                            UtilH.saveProgress(applicationContext, musicList[currentIndex]?.url, 0)
                        }
                        //因多个状态会回调此方法，故做以下判断保证播放完成在回调
                        var duration = getDurationS()
                        var playProgress = getCurrentProgress()
                        if (duration > 0 && (playProgress / 1000) >= (duration / 1000)) {
//                            pauseS(true)
                            binder?.playStatusListener?.onCompletionListener()
                            if (autoPlayNext && (musicList.size - 1) > currentIndex) {
                                //播放下一曲
                                UtilH.saveProgress(applicationContext, musicList[currentIndex + 1]?.url, 0)
                                playS(currentIndex + 1)
                            } else {
                                seekToS(0, autoPlayNext)
                            }
                        }
                    }
                    Player.STATE_READY -> {
                        LogUtil.e("Player.STATE_READY")
                        //初始化完成
                        if (autoSaveProgress) {
                            var time = UtilH.getProgress(this@HMusicPlayService, currentUrl)
                            if (time > 0) {
                                player?.seekTo(time.toLong())
                            }
                        }

                        binder?.playStatusListener?.onPrepared()

                        if (autoPlay) {
                            startS()
                            autoPlay = false
                        }
                    }
                    Player.STATE_BUFFERING -> {
                        LogUtil.e("Player.STATE_BUFFERING")
                    }
                    Player.STATE_IDLE -> {
                        LogUtil.e("Player.STATE_IDLE")
                    }
                }
            }

            override fun onPlayerError(error: ExoPlaybackException) {
                binder?.playStatusListener?.OnErrorListener(error.type, error.cause?.message!!)
            }

            fun onPositionDiscontinuity() {
            }

            override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters) {
                LogUtil.e("onPlaybackParametersChanged")
            }
        })
    }

    private fun requestAudioFocus() {
        val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
        audioManager.requestAudioFocus({ focusChange ->
            when (focusChange) {
                AudioManager.AUDIOFOCUS_GAIN -> {
                    if (player?.playWhenReady != true && isPlayWhenLoss) {
                        player?.playWhenReady = true
                    }
                }
                AudioManager.AUDIOFOCUS_LOSS -> {
                    isPlayWhenLoss = player?.playWhenReady ?: false
                    if (player?.playWhenReady == true) {
                        player?.playWhenReady = false
                    }
                }
                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
                    isPlayWhenLoss = player?.playWhenReady ?: false
                    if (player?.playWhenReady == true) {
                        player?.playWhenReady = false
                    }
                }
                AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> {
                    isPlayWhenLoss = player?.playWhenReady ?: false
                    if (player?.playWhenReady == true) {
                        player?.playWhenReady = false
                    }
                }
                AudioManager.AUDIOFOCUS_REQUEST_FAILED -> {
                    isPlayWhenLoss = player?.playWhenReady ?: false
                    if (player?.playWhenReady == true) {
                        player?.playWhenReady = false
                    }
                }
            }
        }, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
    }

    fun isPlayingS(): Boolean {
        return try {
            player?.playWhenReady ?: false
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    fun getCurrentDataS(): MusicInfoBean? {
        if (musicList.size > currentIndex) {
            return musicList[currentIndex]
        }
        return null
    }

    private fun getCurrentUrlS(): String {
        if (musicList.size == 0 || musicList.size <= currentIndex) {
            return ""
        }
        return musicList[currentIndex].url ?: ""
    }

    fun seekToS(time: Int, autoPlay: Boolean = true) {
        this.autoPlay = autoPlay
        try {
            val seekPosition = (Math.min(
                    Math.max(0, time),
                    player!!.duration.toInt()
            )).toLong()
            player!!.seekTo(seekPosition)
            if (autoSaveProgress) {
                UtilH.saveProgress(this@HMusicPlayService, currentUrl, seekPosition.toInt())
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

    fun addDataS(urlLi: ArrayList<MusicInfoBean>) {
        musicList.addAll(urlLi)
    }

    fun setDataS(urlLi: ArrayList<MusicInfoBean>) {
        musicList.clear()
        musicList.addAll(urlLi)
    }

    fun playS(index: Int, autoSaveProgress: Boolean) {
        this.autoSaveProgress = autoSaveProgress
        playS(index)
    }

    fun playS(index: Int) {
        if (index >= musicList.size) return
        this.currentIndex = index
        this.currentUrl = getCurrentUrlS()
        YDLMusicHelper.title = musicList[currentIndex].title
        //初始化完成自动播放
        autoPlay = true
        try {
            binder?.playStatusListener?.beforeStart(index)
            //定义数据源工厂对象
            val mediaDataSourceFactory = DefaultDataSourceFactory(
                    this,
                    Util.getUserAgent(this, applicationContext.packageName)
            )
            //创建Extractor工厂对象，用于提取多媒体文件
            val extractorsFactory = DefaultExtractorsFactory()
            //创建数据源
            val mediaSource = ExtractorMediaSource(
                    Uri.parse(musicList[index].url),
                    mediaDataSourceFactory, extractorsFactory, Handler(), null
            )
            //添加数据源到播放器中
            if (player == null) {
                initPlayer()
            }
            player!!.prepare(mediaSource)
        } catch (e: Exception) {
            e.printStackTrace()
            LogH.e("设置资源，准备阶段出错：" + musicList[index].url)
        }
    }

    fun pauseS(isNotify: Boolean) {
        try {
            player?.playWhenReady = false
            if (isNotify) {
                updateNOtify()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        binder?.playStatusListener?.pause()
    }

    fun stopS() {
        player?.playWhenReady = false
        player?.stop()
        //移除通知栏
        val myNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        myNotificationManager.cancel(NOTIFY_ID)
    }

    fun startS() {
        try {
            player?.playWhenReady = true
            updateNOtify()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        binder?.playStatusListener?.start()
    }


    fun getDurationS(): Int {
        return try {
            player?.duration?.toInt() ?: 0
        } catch (e: Exception) {
            e.printStackTrace()
            0
        }
    }

    fun getCurrentProgress(): Int {
        return try {
            player?.currentPosition?.toInt() ?: 0
        } catch (e: Exception) {
            e.printStackTrace()
            0
        }
    }

    override fun onBind(p0: Intent?): IBinder? {
        return binder
    }

    override fun onUnbind(intent: Intent?): Boolean {
        binder?.playStatusListener = null
        return super.onUnbind(intent)
    }

    private var timerTask = object : TimerTask() {
        override fun run() {
            handler.post {
                //更新播放进度
                var pro = getCurrentProgress()
                var isp = isPlayingS()
                bufferProgress = player!!.bufferedPercentage
                binder?.playStatusListener?.OnBufferingUpdateListener(bufferProgress)
                if (isp) {
                    var buff = bufferProgress * getDurationS() / 100
                    if (pro >= buff) {
                        //播放进度已达到缓冲进度，表示网络加载中
                        binder?.playStatusListener?.loading()
                        loading = true
                    } else {
                        //缓冲大于播放进度，可以继续播放
                        if (loading) {
                            startS()
                        }
                        loading = false
                        binder?.playStatusListener?.onProgressUpdate(pro)
                        //保存进度
                        if (autoSaveProgress) {
                            UtilH.saveProgress(this@HMusicPlayService, currentUrl, pro)
                        }
                    }
                }
            }
        }
    }

    /**
     * 更新通知栏
     */
    private fun updateNOtify() {
        sendNotify()
    }

    /**
     * 发送通知
     */
    private fun sendNotify() {
        if (!isOpenNotifyCation) return
        remoteViews = createRemoteViews()
        val builder = Notification.Builder(applicationContext)
                .setContent(remoteViews)
                .setSmallIcon(R.mipmap.ic_music_not) // 设置状态栏内的小图标
                .setWhen(System.currentTimeMillis()) // 设置该通知发生的时间
                .setOngoing(true) //在运行的
        val notification = builder.build() // 获取构建好的Notification

//        notification.flags = Notification.FLAG_NO_CLEAR; // 点击清除按钮时就会清除消息通知,但是点击通知栏的通知时不会消失

        val target = NotificationTarget(applicationContext, R.id.iv_head, remoteViews, notification,
            NOTIFY_ID
        )
        Glide.with(this)
                .asBitmap()
                .load(getCurrentDataS()?.pic)
                .into(target)

        remoteViews?.setTextViewText(R.id.tv_title, getCurrentDataS()?.title)
        if (player?.playWhenReady == true) {
            val intentPause = Intent(ACTION_PAUSE)
            val pIntentPause = PendingIntent.getBroadcast(applicationContext,
                REQUEST_CODE, intentPause, PendingIntent.FLAG_UPDATE_CURRENT)

            remoteViews?.setOnClickPendingIntent(R.id.btn_pause_play, pIntentPause)
            remoteViews?.setImageViewResource(R.id.btn_pause_play, R.mipmap.ic_pause_24dp)
        } else {
            val intentPlay = Intent(ACTION_PLAY)
            val pIntentPlay = PendingIntent.getBroadcast(applicationContext,
                REQUEST_CODE, intentPlay, PendingIntent.FLAG_UPDATE_CURRENT)
            remoteViews?.setOnClickPendingIntent(R.id.btn_pause_play, pIntentPlay)
            remoteViews?.setImageViewResource(R.id.btn_pause_play, R.mipmap.ic_play_24dp)
        }
        var myNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        myNotificationManager.notify(NOTIFY_ID, notification)
    }

    private fun createRemoteViews(): RemoteViews {
        val remoteViews = RemoteViews(packageName, R.layout.ui_music_notification)

        val intentStop = Intent(ACTION_STOP)
        val pIntentStop = PendingIntent.getBroadcast(applicationContext,
            REQUEST_CODE, intentStop, PendingIntent.FLAG_UPDATE_CURRENT)
        remoteViews.setOnClickPendingIntent(R.id.btn_close, pIntentStop)

        val intentDetail = Intent(ACTION_DETAIL)
        val pIntentDetail = PendingIntent.getBroadcast(applicationContext,
            REQUEST_CODE, intentDetail, PendingIntent.FLAG_UPDATE_CURRENT)
        remoteViews.setOnClickPendingIntent(R.id.iv_head, pIntentDetail)
        remoteViews.setOnClickPendingIntent(R.id.tv_title, pIntentDetail)
        val color = getColor()
        remoteViews.setTextColor(R.id.tv_title, color)
        return remoteViews
    }

    private fun getColor(): Int {
        var color = ContextCompat.getColor(applicationContext, R.color.default_text_color)
        val tempColor = NotificationHelper.getNotificationColor(applicationContext)
        if (tempColor != NotificationHelper.INVALID_COLOR) {
            color = tempColor
        }
        return color
    }

    override fun onDestroy() {
        super.onDestroy()
        timerTask.cancel()
        timer.purge()
        timer.cancel()
        player?.playWhenReady = false
        player?.release()
        currentUrl = null
        player = null
        binder = null
        musicList.clear()
        var myNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        myNotificationManager.cancel(NOTIFY_ID)
    }

    inner class MusicController : Binder() {

        //状态回调
        var playStatusListener: PlayStatusListener? = null

        fun setData(urlLi: ArrayList<MusicInfoBean>) {
            setDataS(urlLi)
        }

        fun addData(urlLi: ArrayList<MusicInfoBean>) {
            addDataS(urlLi)
        }

        fun getData(): ArrayList<MusicInfoBean> {
            return musicList
        }

        fun getCurrentData(): MusicInfoBean? {
            return getCurrentDataS()
        }

        fun play(index: Int = 0, autoSaveProgress: Boolean = false) {
            playS(index, autoSaveProgress)
        }

        fun getDuration(): Int {
            return getDurationS()
        }

        fun getCurrentUrl(): String {
            return currentUrl ?: ""
        }

        fun getCurrentIndex(): Int {
            return currentIndex
        }

        fun seekTo(time: Int) {
            seekToS(time)
        }

        fun pause() {
            pauseS(true)
        }

        fun stop() {
            stopS()
        }

        fun start() {
            startS()
        }

        fun setAutoPlayNext(next: Boolean) {
            autoPlayNext = next
        }

        /**
         * 是否显示通知栏
         */
        fun setOpenNotifyCation(isShow: Boolean) {
            isOpenNotifyCation = isShow
        }

        fun isPlaying(): Boolean {
            return isPlayingS()
        }

        /**
         * 是否有下一曲
         */
        fun isHaveNext(): Boolean {
            var size = musicList.size
            return currentIndex < size - 1
        }

        /**
         * 是否有上一曲
         */
        fun isHavePre(): Boolean {
            return currentIndex > 0
        }

        /**
         * 上一曲
         */
        fun onPrePlaying() {
            if (isHavePre()) {
                if (autoSaveProgress) {
                    UtilH.saveProgress(applicationContext, getData()[currentIndex - 1]?.url, 0)
                }
                play(currentIndex - 1)
            }
        }

        /**
         * 下一曲
         */
        fun onNextPlaying() {
            if (isHaveNext()) {
                if (autoSaveProgress) {
                    UtilH.saveProgress(applicationContext, getData()[currentIndex + 1]?.url, 0)
                }
                play(currentIndex + 1)
            }
        }
    }
}
