package com.tencent.liteav.demo.superplayer.player;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.cast.dlna.dmc.DLNACastManager;
import com.android.cast.dlna.dmc.control.ICastInterface;
import com.tencent.liteav.base.util.TimeFormat;
import com.tencent.liteav.demo.superplayer.SuperPlayerCode;
import com.tencent.liteav.demo.superplayer.SuperPlayerDef;
import com.tencent.liteav.demo.superplayer.SuperPlayerGlobalConfig;
import com.tencent.liteav.demo.superplayer.SuperPlayerModel;
import com.tencent.liteav.demo.superplayer.util.CastorUtil;
import com.tencent.liteav.demo.superplayer.util.HistoryUtil;
import com.tencent.liteav.demo.superplayer.util.PlayerUtil;
import com.tencent.rtmp.ITXVodPlayListener;
import com.tencent.rtmp.TXLiveConstants;
import com.tencent.rtmp.TXVodPlayConfig;
import com.tencent.rtmp.TXVodPlayer;
import com.tencent.rtmp.ui.TXCloudVideoView;

import org.fourthline.cling.model.meta.Device;
import org.fourthline.cling.support.model.PositionInfo;
import org.fourthline.cling.support.model.TransportState;

import java.io.File;
import java.util.UUID;

public class SuperPlayerImpl implements SuperPlayer, ITXVodPlayListener {

    private static final String TAG = "SuperPlayerImpl";

    private TXCloudVideoView mVideoView;        // 腾讯云视频播放view
    private TXVodPlayer mVodPlayer;       // 点播播放器

    private SuperPlayerModel mCurrentModel;  // 当前播放的model
    private SuperPlayerObserver mObserver;
    private SuperPlayerDef.PlayerMode mCurrentPlayMode = SuperPlayerDef.PlayerMode.WINDOW;    // 当前播放模式
    private SuperPlayerDef.PlayerState mCurrentPlayState = SuperPlayerDef.PlayerState.INIT;

    private float mStartPos;                // 视频开始播放时间

    private boolean isPrepared = false;
    private boolean isNeedResume = false;
    private boolean mNeedToPause = false;
    private boolean mTimeout = false;
    private boolean isPauseByTimeout = false;
    private boolean isPauseByCasting = false;

    private long mCurrent = 0L;
    private long mStartPoint = 0L;
    private long mEndPoint = 0L;

    private boolean isCasting = false;
    private Device castDevice;

    private CircleMessageHandler positionHandler = new CircleMessageHandler(1000L, new Runnable() {
        @Override
        public void run() {
            if (castDevice == null) return;

            DLNACastManager.getInstance().getPositionInfo(castDevice, new ICastInterface.GetInfoListener<PositionInfo>() {
                @Override
                public void onGetInfoResult(@Nullable PositionInfo positionInfo, @Nullable String errMsg) {
                    if (positionInfo != null) {
                        long current = parseTime(positionInfo.getRelTime());
                        long duration = parseTime(positionInfo.getTrackDuration());

                        updatePlayProgress(current, duration);
                    }
                }
            });
        }
    });

    private ICastInterface.CastEventListener castEventListener = new ICastInterface.CastEventListener() {
        @Override
        public void onSuccess(String result) {
            positionHandler.start(0);
            updatePlayerState(SuperPlayerDef.PlayerState.INIT);
            updatePlayerState(SuperPlayerDef.PlayerState.PLAYING);

            DLNACastManager.getInstance().seekTo(mCurrent * 1000);
        }

        @Override
        public void onFailed(String errMsg) {

        }
    };

    private ICastInterface.PlayEventListener playEventListener = new ICastInterface.PlayEventListener() {
        @Override
        public void onSuccess(Void result) {
            updatePlayerState(SuperPlayerDef.PlayerState.PLAYING);
        }

        @Override
        public void onFailed(String errMsg) {

        }
    };

    private ICastInterface.PauseEventListener pauseEventListener = new ICastInterface.PauseEventListener() {
        @Override
        public void onSuccess(Void result) {
            updatePlayerState(SuperPlayerDef.PlayerState.PAUSE);
        }

        @Override
        public void onFailed(String errMsg) {

        }
    };

    private ICastInterface.StopEventListener stopEventListener = new ICastInterface.StopEventListener() {
        @Override
        public void onSuccess(Void result) {
            updatePlayerState(SuperPlayerDef.PlayerState.END);
            positionHandler.stop();
        }

        @Override
        public void onFailed(String errMsg) {

        }
    };

    private ICastInterface.SeekToEventListener seekToEventListener = new ICastInterface.SeekToEventListener() {
        @Override
        public void onSuccess(Long result) {

        }

        @Override
        public void onFailed(String errMsg) {

        }
    };

    private ICastInterface.ISubscriptionListener subscriptionListener = new ICastInterface.ISubscriptionListener() {
        @Override
        public void onSubscriptionTransportStateChanged(TransportState event) {
            if (event == TransportState.STOPPED) {
                updatePlayerState(SuperPlayerDef.PlayerState.END);
            }
        }
    };

    public SuperPlayerImpl(Context context, TXCloudVideoView videoView) {
        mVideoView = videoView;

        initVodPlayer(context);
    }

    @Override
    public void setNeedToPause(boolean value) {
        mNeedToPause = value;
    }

    /**
     * 点播播放器事件回调
     *
     * @param player
     * @param event
     * @param param
     */
    @Override
    public void onPlayEvent(TXVodPlayer player, int event, Bundle param) {
        if (isCasting) return;

        if (event != TXLiveConstants.PLAY_EVT_PLAY_PROGRESS) {
            String playEventLog = "TXVodPlayer onPlayEvent event: " + event + ", " + param.getString(TXLiveConstants.EVT_DESCRIPTION);
            Log.d(TAG, playEventLog);
        }
        switch (event) {
            case TXLiveConstants.PLAY_EVT_VOD_PLAY_PREPARED://视频播放开始
                onVodPlayPrepared();
                break;
            case TXLiveConstants.PLAY_EVT_RCV_FIRST_I_FRAME:
                Log.i(TAG, "PLAY_EVT_RCV_FIRST_I_FRAME");
                if (mNeedToPause) {
                    return;
                }
                updatePlayerState(SuperPlayerDef.PlayerState.PLAYING);
                mObserver.onRcvFirstIframe();
                break;
            case TXLiveConstants.PLAY_EVT_PLAY_END:
                Log.i(TAG, "PLAY_EVT_PLAY_END");
                updatePlayerState(SuperPlayerDef.PlayerState.END);
                break;
            case TXLiveConstants.PLAY_EVT_PLAY_PROGRESS:
                int progress = param.getInt(TXLiveConstants.EVT_PLAY_PROGRESS_MS);
                int duration = param.getInt(TXLiveConstants.EVT_PLAY_DURATION_MS);

                if (duration != 0) {
                    updatePlayProgress(progress / 1000, duration / 1000);
                }
                break;
            case TXLiveConstants.PLAY_EVT_PLAY_LOADING:
                Log.i(TAG, "PLAY_EVT_PLAY_LOADING");
                updatePlayerState(SuperPlayerDef.PlayerState.LOADING);
                break;
            case TXLiveConstants.PLAY_EVT_PLAY_BEGIN:
                if (mNeedToPause) {
                    pause();
                    return;
                }
                updatePlayerState(SuperPlayerDef.PlayerState.PLAYING);
                break;
            default:
                break;
        }
        if (event < 0) {// 播放点播文件失败
            mVodPlayer.stopPlay(true);
            updatePlayerState(SuperPlayerDef.PlayerState.PAUSE);
            onError(SuperPlayerCode.VOD_PLAY_FAIL, param.getString(TXLiveConstants.EVT_DESCRIPTION));
        }
    }

    private void onVodPlayPrepared() {
        isPrepared = true;

        if (mNeedToPause) {
            pause();
            return;
        }
        if (isNeedResume) {
            mVodPlayer.resume();
        }
    }

    /**
     * 点播播放器网络状态回调
     *
     * @param player
     * @param bundle
     */
    @Override
    public void onNetStatus(TXVodPlayer player, Bundle bundle) {
        // DO NOTHING
    }

    /**
     * 初始化点播播放器
     *
     * @param context
     */
    private void initVodPlayer(Context context) {
        mVodPlayer = new TXVodPlayer(context);
        SuperPlayerGlobalConfig config = SuperPlayerGlobalConfig.getInstance();
        // 点播播放器配置
        TXVodPlayConfig mVodPlayConfig = new TXVodPlayConfig();

        File sdcardDir = context.getExternalFilesDir(null);
        if (sdcardDir != null) {
            mVodPlayConfig.setCacheFolderPath(sdcardDir.getPath() + "/txcache");
        }
        mVodPlayConfig.setPreferredResolution(720 * 1280);
        mVodPlayConfig.setMaxCacheItems(config.maxCacheItem);
        mVodPlayConfig.setHeaders(config.headers);
        mVodPlayer.setConfig(mVodPlayConfig);
        mVodPlayer.setRenderMode(config.renderMode);
        mVodPlayer.setVodListener(this);
        mVodPlayer.enableHardwareDecode(config.enableHWAcceleration);
        mVodPlayer.setRate(config.playRate);
        mVodPlayer.setMute(config.mute);
        mVodPlayer.setMirror(config.mirror);
    }

    private void initCastPlayer() {
        DLNACastManager.getInstance().registerActionCallbacks(
                castEventListener,
                playEventListener,
                pauseEventListener,
                stopEventListener,
                seekToEventListener
        );

        DLNACastManager.getInstance().registerSubscriptionListener(subscriptionListener);
    }

    /**
     * 播放视频
     *
     * @param model
     */
    public void playWithModel(SuperPlayerModel model) {
        reset();

        String videoURL = model.url;

        if (TextUtils.isEmpty(videoURL)) {
            onError(SuperPlayerCode.PLAY_URL_EMPTY, "播放视频失败，播放链接为空");
            return;
        }

        if (!isCasting) {
            mVodPlayer.setPlayerView(mVideoView);

            if (mVodPlayer != null) {
                mVodPlayer.setStartTime(mStartPos);
                mVodPlayer.setAutoPlay(true);
                mVodPlayer.setVodListener(this);
                mVodPlayer.setToken(null);
                mVodPlayer.startPlay(videoURL);

                mStartPos = 0;
            }
        } else {
            if (castDevice != null) {
                DLNACastManager.getInstance().cast(
                        castDevice, CastObject.INSTANCE.newInstance(
                                videoURL, UUID.randomUUID().toString(), model.title
                        ));
            }
        }
        updatePlayProgress(0, model.duration);
    }

    /**
     * 更新播放进度
     *
     * @param current  当前播放进度(秒)
     * @param duration 总时长(秒)
     */
    private void updatePlayProgress(long current, long duration) {
        mCurrent = current;

        if (mObserver != null) {
            mObserver.onPlayProgress(current, duration);
        }
    }

    /**
     * 更新播放状态
     *
     * @param playState
     */
    private void updatePlayerState(SuperPlayerDef.PlayerState playState) {
        mCurrentPlayState = playState;
        if (mObserver == null) {
            return;
        }
        switch (playState) {
            case INIT:
                mObserver.onPlayPrepare();
                break;
            case PLAYING:
                PlayerUtil.INSTANCE.sendNewTimer(PlayerUtil.getSTATE_PLAY());
                mObserver.onPlayBegin(getPlayName());
                break;
            case PAUSE:
                PlayerUtil.INSTANCE.sendNewTimer(PlayerUtil.getSTATE_PAUSE());
                mObserver.onPlayPause();
                break;
            case LOADING:
                PlayerUtil.INSTANCE.sendNewTimer(PlayerUtil.getSTATE_LOADING());
                mObserver.onPlayLoading();
                break;
            case END:
                PlayerUtil.INSTANCE.sendNewTimer(PlayerUtil.getSTATE_STOP());
                mObserver.onPlayStop();
                break;
        }

        switch (playState) {
            case PLAYING:
                if (!isCasting) {
                    mStartPoint = (int) mVodPlayer.getCurrentPlaybackTime();
                } else {
                    DLNACastManager.getInstance().getPositionInfo(castDevice, new ICastInterface.GetInfoListener<PositionInfo>() {
                        @Override
                        public void onGetInfoResult(@Nullable PositionInfo positionInfo, @Nullable String errMsg) {
                            if (positionInfo != null) {
                                mStartPoint = parseTime(positionInfo.getRelTime());
                            }
                        }
                    });
                }
                break;
            case PAUSE:
            case END:
                if (!isCasting) {
                    mEndPoint = (int) mVodPlayer.getCurrentPlaybackTime();
                } else {
                    DLNACastManager.getInstance().getPositionInfo(castDevice, new ICastInterface.GetInfoListener<PositionInfo>() {
                        @Override
                        public void onGetInfoResult(@Nullable PositionInfo positionInfo, @Nullable String errMsg) {
                            if (positionInfo != null) {
                                mEndPoint = parseTime(positionInfo.getRelTime());
                            }
                        }
                    });
                }
                saveHistory();
                break;
        }
    }

    private void onError(int code, String message) {
        if (mObserver != null) {
            mObserver.onError(code, message);
        }
    }

    private String getPlayName() {
        String title = "";
        if (mCurrentModel != null && !TextUtils.isEmpty(mCurrentModel.title)) {
            title = mCurrentModel.title;
        }
        return title;
    }

    @Override
    public void play(SuperPlayerModel model) {
        if (mTimeout) return;

        mCurrentModel = model;
        playWithModel(model);
    }

    @Override
    public void restart() {
        if (mTimeout) return;

        playWithModel(mCurrentModel);
    }

    @Override
    public void pause() {
        if (!isCasting) {
            mVodPlayer.pause();
            updatePlayerState(SuperPlayerDef.PlayerState.PAUSE);
        } else {
            DLNACastManager.getInstance().pause();
        }
    }

    @Override
    public void resume() {
        if (mTimeout) return;

        if (isCasting) {
            DLNACastManager.getInstance().play();
            return;
        }
        isNeedResume = true;
        if (isPrepared) {
            mVodPlayer.resume();
        }

        updatePlayerState(SuperPlayerDef.PlayerState.PLAYING);
    }

    @Override
    public void stop() {
        if (!isCasting) {
            resetPlayer();
            updatePlayerState(SuperPlayerDef.PlayerState.END);
        } else {
            DLNACastManager.getInstance().stop();
            DLNACastManager.getInstance().unregisterActionCallbacks();
        }
    }

    @Override
    public void reset() {
        resetPlayer();
        updatePlayerState(SuperPlayerDef.PlayerState.INIT);
    }

    @Override
    public void onTimeout(boolean timeout) {
        this.mTimeout = timeout;

        if (timeout) {
            if (!isCasting) {
                if (mCurrentPlayState == SuperPlayerDef.PlayerState.PLAYING || mCurrentPlayState == SuperPlayerDef.PlayerState.LOADING) {
                    isPauseByTimeout = true;
                    pause();
                }
            } else {
                stopCast();
            }
        } else {
            mStartPoint = mEndPoint;

            saveHistory();

            if (isPauseByTimeout) {
                resume();
            }

        }
    }

    private void resetPlayer() {
        isPrepared = false;
        isNeedResume = false;
        if (mVodPlayer != null) {
            mVodPlayer.setVodListener(null);
            mVodPlayer.stopPlay(false);
        }
    }

    @Override
    public void switchPlayMode(SuperPlayerDef.PlayerMode playerMode) {
        if (mCurrentPlayMode == playerMode) {
            return;
        }

        mCurrentPlayMode = playerMode;

        if (mCurrentPlayMode == SuperPlayerDef.PlayerMode.FULLSCREEN) {
            if (getPlayerState() == SuperPlayerDef.PlayerState.PAUSE) {
                resume();
            }
        }
    }

    @Override
    public void seek(int position) {
        if (!isCasting) {
            mEndPoint = (int) mVodPlayer.getCurrentPlaybackTime();
            saveHistory();
        } else {
            final long start = mStartPoint;

            DLNACastManager.getInstance().getPositionInfo(castDevice, (positionInfo, errMsg) -> {
                if (positionInfo != null) {
                    mEndPoint = parseTime(positionInfo.getRelTime());

                    if (mCurrentModel != null) {
                        HistoryUtil.INSTANCE.sendHistory(start, mEndPoint, mCurrentModel.sectionId);
                    }
                }
            });
        }

        mStartPoint = position;

        if (!isCasting) {
            mVodPlayer.seek(position);
            mVodPlayer.resume();
        } else {
            DLNACastManager.getInstance().seekTo(position * 1000L);
        }

        if (mObserver != null) {
            mObserver.onSeek(position);
        }
    }

    @Override
    public void startCast(Device device) {
        if (isCasting) {
            stopCast();
        }

        if (mVodPlayer.isPlaying()) {
            isPauseByCasting = true;
            mVodPlayer.pause();
        }

        if (castDevice != null) {
            positionHandler.stop();
        }

        castDevice = device;
        isCasting = true;
        initCastPlayer();
        DLNACastManager.getInstance().cast(device,
                CastObject.INSTANCE.newInstance(mCurrentModel.url, UUID.randomUUID().toString(), mCurrentModel.title));
    }

    @Override
    public void stopCast() {
        if (!isCasting) return;

        mStartPos = mCurrent;

        DLNACastManager.getInstance().unregisterActionCallbacks();
        DLNACastManager.getInstance().stop();
        castDevice = null;
        isCasting = false;

        playWithModel(mCurrentModel);
    }

    @Override
    public SuperPlayerDef.PlayerMode getPlayerMode() {
        return mCurrentPlayMode;
    }

    @Override
    public SuperPlayerDef.PlayerState getPlayerState() {
        return mCurrentPlayState;
    }

    @Override
    public void setObserver(SuperPlayerObserver observer) {
        mObserver = observer;
    }

    @Override
    public void setLoop(boolean isLoop) {
        mVodPlayer.setLoop(isLoop);
    }

    @Override
    public void setStartTime(float startPos) {
        this.mStartPos = startPos;
        mVodPlayer.setStartTime(startPos);
    }

    private void saveHistory() {
        Log.d(TAG, "saveHistory: " + mStartPoint + " - " + mEndPoint);
        if (mCurrentModel != null) {
            HistoryUtil.INSTANCE.sendHistory(mStartPoint, mEndPoint, mCurrentModel.sectionId);
        }
    }

    private static long parseTime(String time) {
        String[] split = time.split(":");
        long parsedTime = 0, radix = 1;
        for (int i = split.length - 1; i >= 0; i--) {
            parsedTime += Long.parseLong(split[i]) * radix;
            radix *= 60;
        }

        return parsedTime;
    }

    private static class CircleMessageHandler extends Handler {
        private static final int MSG = 101;

        private final long duration;
        private final Runnable runnable;

        public CircleMessageHandler(long duration, Runnable runnable) {
            super(Looper.getMainLooper());
            this.duration = duration;
            this.runnable = runnable;
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            runnable.run();
            sendEmptyMessageDelayed(MSG, duration);
        }

        public void start(long delay) {
            stop();
            sendEmptyMessageDelayed(MSG, delay);
        }

        public void stop() {
            removeMessages(MSG);
        }
    }
}
