package com.bokecc.livemodule.base;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;

import com.bokecc.livemodule.R;
import com.bokecc.livemodule.live.chat.util.DensityUtil;
import com.bokecc.livemodule.popup.SettingPopupWindow;
import com.bokecc.livemodule.popup.callback.SettingPopupInterface;
import com.bokecc.livemodule.popup.callback.SettingPopupWindowCallBack;
import com.bokecc.livemodule.replay.DWReplayCoreHandler;
import com.bokecc.livemodule.replay.room.ReplayRoomLayout;
import com.bokecc.livemodule.replay.room.rightview.ReplayRightView;
import com.bokecc.livemodule.utils.TimeUtil;
import com.bokecc.livemodule.view.BaseRelativeLayout;
import com.bokecc.livemodule.view.DotMsgPopupWindow;
import com.bokecc.livemodule.view.DotView;
import com.bokecc.livemodule.view.RePlaySeekBar;
import com.bokecc.livemodule.view.subtitle.SubtitleView;
import com.bokecc.sdk.mobile.live.OnMarqueeImgFailListener;
import com.bokecc.sdk.mobile.live.logging.ELog;
import com.bokecc.sdk.mobile.live.pojo.Marquee;
import com.bokecc.sdk.mobile.live.pojo.PlayUrlInfoBean;
import com.bokecc.sdk.mobile.live.replay.DWLiveReplay;
import com.bokecc.sdk.mobile.live.replay.DWReplayPlayer;
import com.bokecc.sdk.mobile.live.replay.pojo.ReplayDot;
import com.bokecc.sdk.mobile.live.replay.pojo.ReplayUrlInfo;
import com.bokecc.sdk.mobile.live.widget.MarqueeView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.google.gson.Gson;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 回放/离线回放
 * 播放控制界面封装
 */
public abstract class BaseReplayRoomLayout extends BaseRelativeLayout implements SettingPopupInterface {
    private static final String TAG = "BaseReplayRoomLayout";

    protected Activity activity;
    // ----------顶部布局---------
    protected RelativeLayout mTopLayout;
    protected TextView mTitle;             // 标题
    protected View mTopRightLayout;        // 顶部右侧布局
    protected ImageView mVideoDocSwitch;    // 切换文档/视频按钮
    protected ImageView mClose;            // 退出回放按钮
    protected ImageView mVideoDocMore;     // 横屏 配置按钮
//

    // ----------底部布局----------
    protected RelativeLayout mBottomLayout;
    protected View mPortBottomLayout;
    protected View mLandBottomLayout;
    protected RePlaySeekBar mPlaySeekBar;     // 竖屏进度条
    protected RePlaySeekBar mLandPlaySeekBar; // 横屏进度条
    protected TextView mDurationView;         // 播放时总时长
    protected TextView mLandDurationView;     // 播放时总时长
    protected TextView mCurrentTime;          // 当前播放时间
    protected TextView mLandCurrentTime;      // 当前播放时间
    protected ImageView mLiveFullScreen;      // 全屏按钮
    protected ImageView mPlayIcon;            // 播放/暂停 按钮
    protected TextView mLandSpeed;            // 横屏 倍速按钮
    protected TextView mLandQuality;          // 横屏 切换清晰度
    protected ImageView mLandPlayIcon;        // 横屏 播放/暂停 按钮
    protected ImageView mLandVideoDocSwitch;   // 横屏 切换大小屏按钮
    protected ReplayRightView rightView;      // 横屏右侧 进度 清晰度 线路布局
    // 底部弹出设置界面
    protected SettingPopupWindow settingPopupWindow;

    // ----------错误布局----------
    protected LinearLayout mTipsLayout;   // 错误界面
    protected TextView mTipsView;         // 错误提示
    protected TextView mTryBtn;           // 播放错误，重试按钮

    // ----------手势拖动布局----------
    protected RelativeLayout mSeekRoot;   // 手势拖动界面
    protected TextView mSeekTime;         // seek time
    protected TextView mSumTime;          // sum time

    protected MarqueeView mMarqueeView;   // 跑马灯控件
    protected TextView progress_record;   // 进度记忆展示

    protected boolean isTouch;            // 是否正在拖动进度
    protected boolean isVideoMain;        // 是否是视频大屏
    protected String recordId;        // recordId
    protected int start;                  // 拖动进度开始时间
    private boolean isFloatDismiss;       // 当前是否显示悬浮窗
    protected List<ReplayDot> dotBeans;   // 打点数据列表
    private DotMsgPopupWindow popupWindow;// 打点弹出界面

    private ArrayList<String> videoPreviews;

    private int currentSubtitleIndex = 0;
    private ReplayUrlInfo.SubtitleData subtitles;

    protected static final int HIDE_TIME = 5000;

    //针对隐藏标题栏和聊天布局的延迟
    protected Runnable hideRunnable = new Runnable() {
        @Override
        public void run() {
            hide();
        }
    };

    /**
     * 是否显示视频缩略图
     */
    private boolean isHasVideoPreviews = false;
    private ImageView ivCcVideoPreviews;//视频预览图
    protected RelativeLayout rlCcVideoPreviewsCon;//视频预览图容器
    private TextView tvCcVideoPreviewTime;
    private TextView tvCcVideoPreviewTime2;
    private ImageView ccReplayPicInPic;


    private PlayUrlInfoBean playUrlInfoBean;
    private ImageView ccReplayDlna;
    private SubtitleView subtitleView;

    public BaseReplayRoomLayout(Context context) {
        super(context);
    }

    public BaseReplayRoomLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public BaseReplayRoomLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void initViews() {
        LayoutInflater.from(mContext).inflate(R.layout.replay_room_layout, this, true);
        mTitle = findViewById(R.id.tv_portrait_live_title);
        mTopLayout = findViewById(R.id.rl_portrait_live_top_layout);
        mBottomLayout = findViewById(R.id.bottom_layout);
        mLiveFullScreen = findViewById(R.id.iv_portrait_live_full);
        mClose = findViewById(R.id.iv_portrait_live_close);
        mTipsLayout = findViewById(R.id.id_error_layout);
        mTryBtn = findViewById(R.id.id_try);
        mTipsView = findViewById(R.id.id_msg_tips);
        mSeekRoot = findViewById(R.id.seek_root);
        mSeekTime = findViewById(R.id.tv_seek_time);
        mSumTime = findViewById(R.id.tv_sum_time);
        progress_record = findViewById(R.id.progress_record);
        // 竖屏显示
        mPortBottomLayout = findViewById(R.id.replay_port_bottom_layout);
        mCurrentTime = findViewById(R.id.replay_current_time);
        mDurationView = findViewById(R.id.replay_duration);
        mTopRightLayout = findViewById(R.id.id_port_video_doc_switch);
        mVideoDocSwitch = findViewById(R.id.video_doc_switch);
        ccReplayPicInPic = findViewById(R.id.cc_replay_pic_in_pic);
        ccReplayDlna = findViewById(R.id.cc_replay_dlna);

        mPlayIcon = findViewById(R.id.replay_play_icon);
        // 横屏显示
        mLandBottomLayout = findViewById(R.id.replay_land_bottom_layout);
        mLandCurrentTime = findViewById(R.id.replay_land_current_time);
        mLandDurationView = findViewById(R.id.replay_land_duration);
        mLandSpeed = findViewById(R.id.replay_land_speed);
        mLandQuality = findViewById(R.id.replay_land_quality);
        mLandVideoDocSwitch = findViewById(R.id.video_doc_land_switch);
        mLandPlayIcon = findViewById(R.id.replay_land_play_icon);
        mVideoDocMore = findViewById(R.id.video_doc_more);
        rightView = findViewById(R.id.right_root);

        mPlaySeekBar = findViewById(R.id.replay_progressbar);
        mLandPlaySeekBar = findViewById(R.id.replay_land_progressbar);
        ivCcVideoPreviews = findViewById(R.id.iv_cc_video_previews);
        rlCcVideoPreviewsCon = findViewById(R.id.rl_cc_video_previews_con);
        tvCcVideoPreviewTime = findViewById(R.id.tv_cc_video_preview_time);
        tvCcVideoPreviewTime2 = findViewById(R.id.tv_cc_video_preview_time_2);
        subtitleView = findViewById(R.id.subtitle_view);

        caclVideoPreviewSize();

    }

    private void caclVideoPreviewSize() {
        post(new Runnable() {
            @Override
            public void run() {
               if(getContext().getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE){
                   int width = (int) (DensityUtil.getWidth(getContext())/100f*24);
                   int height = width*90/160;
                   RelativeLayout.LayoutParams layoutParams = (LayoutParams) ivCcVideoPreviews.getLayoutParams();
                   layoutParams.width = width;
                   layoutParams.height = height;
                   ivCcVideoPreviews.setLayoutParams(layoutParams);
               } else {
                   int width = (int) (DensityUtil.getWidth(getContext())/100f*30);
                   int height = width*90/160;
                   RelativeLayout.LayoutParams layoutParams = (LayoutParams) ivCcVideoPreviews.getLayoutParams();
                   layoutParams.width = width;
                   layoutParams.height = height;
                   ivCcVideoPreviews.setLayoutParams(layoutParams);
               }
            }
        });
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            //  横屏
            mLiveFullScreen.setVisibility(GONE);
            mLandBottomLayout.setVisibility(VISIBLE);
            mPortBottomLayout.setVisibility(GONE);
            mVideoDocSwitch.setVisibility(GONE);
            // 初始化打点View
            initDotView();
            //调整顶部更多按钮与右边边距
            mTopRightLayout.setPadding(0,0,DensityUtil.dp2px(getContext(),20f),0);
            ccReplayPicInPic.setPadding(0,0,DensityUtil.dp2px(getContext(),15f),0);

            if (subtitleView!=null){
                subtitleView.setLandScape(getContext(),true);
            }

        } else {
            // 竖屏
            mLiveFullScreen.setVisibility(VISIBLE);
            mLandBottomLayout.setVisibility(GONE);
            mPortBottomLayout.setVisibility(VISIBLE);
            if (isHasDoc()) {
                mVideoDocSwitch.setVisibility(VISIBLE);
            }

            //调整顶部更多按钮与右边边距
            mTopRightLayout.setPadding(0,0,DensityUtil.dp2px(getContext(),0f),0);
            ccReplayPicInPic.setPadding(0,0,DensityUtil.dp2px(getContext(),0f),0);

            if (subtitleView!=null){
                subtitleView.setLandScape(getContext(),true);
            }
        }
        caclVideoPreviewSize();

    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        initListener();
        // 延时隐藏上下bar
        removeCallbacks(hideRunnable);
        postDelayed(hideRunnable, HIDE_TIME);

        if (getPlayer() != null && getPlayer().isPlaying()) {
            startTimerTask();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        stopTimerTask();
    }


    private void initListener() {
        // 点击整个控件，隐藏上下bar
        setOnClickListener(mRoomAnimatorListener);
        // 进度条设置监听
        // mPlaySeekBar2 = getPlaySeekBar(null);
        // 点击播放暂停
        mPlayIcon.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                changePlayerStatus();
            }
        });
        mLandPlayIcon.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                changePlayerStatus();
            }
        });


        // 切换文档/视频大小屏
        mVideoDocSwitch.setOnClickListener(onSwitchClickListener);
        mLandVideoDocSwitch.setOnClickListener(onSwitchClickListener);

        // 全屏
        mLiveFullScreen.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // 回调给activity修改ui
                if (replayRoomStatusListener != null) {
                    replayRoomStatusListener.fullScreen();
                }
            }
        });

        // 点击关闭
        mClose.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (replayRoomStatusListener != null) {
                    replayRoomStatusListener.closeRoom();
                }
            }
        });


        // 重试按钮
        mTryBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mTipsLayout.setVisibility(GONE);
                doRetry(false);
            }
        });

        // 倍速切换
        mLandSpeed.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                rightView.showRight(ReplayRightView.RIGHT_SHOW_SPEED);
            }
        });

        // 进度条监听
        mPlaySeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener);
        mLandPlaySeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener);

        ccReplayPicInPic.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (onPicInPicListener!=null){
                    onPicInPicListener.onPicInPicClick();
                }
            }
        });
        ccReplayDlna.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (playUrlInfoBean!=null&&onDlnaListener!=null){
                    onDlnaListener.onDlnaClick(playUrlInfoBean);
                }
            }
        });
    }


    // region ---------------------------------内部方法---------------------------------------------

    // 拖拽进度条监听
    private final SeekBar.OnSeekBarChangeListener onSeekBarChangeListener =
            new SeekBar.OnSeekBarChangeListener() {

                @Override
                public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                    String formatTime = TimeUtil.getFormatTime(seekBar.getProgress());
                    mCurrentTime.setText(formatTime);
                    mLandCurrentTime.setText(formatTime);

                    if (isTouch){
                        //显示视频缩略图
                        if (isHasVideoPreviews) {
                            updateVideoPreviews(seekBar);
                        }else {
                            String currentTime = TimeUtil.getFormatTime(seekBar.getProgress());
                            String maxTime = TimeUtil.getFormatTime(seekBar.getMax());
                            mSeekTime.setText(currentTime);
                            mSumTime.setText(maxTime);
                        }
                    }

                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                    isTouch = true;
                    start = seekBar.getProgress();
                    removeCallbacks(hideRunnable);
                    if (isHasVideoPreviews){
                        rlCcVideoPreviewsCon.setVisibility(View.VISIBLE);
                    }else {
                        mSeekRoot.setVisibility(VISIBLE);
                    }
                }

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                    isTouch = false;
                    DWReplayPlayer player = getPlayer();
                    if (player != null) {
                        if (player.isPlaying()) {
                            setPlaySeekBarCanSeek(false);
                        }
                        player.seekTo(seekBar.getProgress());
                    }
                    if (mSeekListener != null && seekBar.getProgress() - start < 0) {
                        mSeekListener.onBackSeek(seekBar.getProgress());
                    }
                    removeCallbacks(hideRunnable);
                    postDelayed(hideRunnable, HIDE_TIME);
                    rlCcVideoPreviewsCon.setVisibility(View.GONE);
                    mSeekRoot.setVisibility(GONE);

                }
            };


    private long lastMills = 0;

    private void updateVideoPreviews(SeekBar seekBar) {
        if (!isHasVideoPreviews || videoPreviews == null) {
            return;
        }
        long mills = seekBar.getProgress();
        //更新时间戳
        String currentTime = TimeUtil.getFormatTime(seekBar.getProgress());
        String maxTime = TimeUtil.getFormatTime(seekBar.getMax());

        tvCcVideoPreviewTime.setText(currentTime);
        tvCcVideoPreviewTime2.setText("/"+maxTime);

        if (mills /1000/ 6 == lastMills/1000 / 6) {
            return;
        }

        lastMills = mills;
        //videoPreviews集合中存储的是雪碧图（10*10）固定像素：1600x900，6秒截一张图，需要根据mills和max计算当前需要展示的图片，并使用Glide加载到imageview上

        //计算当前mills位于第几张图
        int index = (int) (mills/1000/6);


        String path  = getContext().getCacheDir()+"/replay_video_preview/"+recordId+"/sprite_"+index+".png";

        File file = new File(path);
        if (file.exists()){
            // 使用Glide加载
            Glide.with(getContext()).load(file).placeholder(R.drawable.shape_bg_video_previews).dontAnimate().fitCenter().into(ivCcVideoPreviews);
        }




    }


    // 切换文档和视频监听
    private final OnClickListener onSwitchClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            if (replayRoomStatusListener != null) {
                if (isFloatDismiss) {
                    replayRoomStatusListener.openVideoDoc();
                    setSwitchText(false);
                } else {
                    isVideoMain = !isVideoMain;
                    replayRoomStatusListener.switchVideoDoc(isVideoMain);
                    setSwitchText(false);
                }

            }
        }
    };


    // endregion

    // region ---------------------------------对外方法---------------------------------------------

    /**
     * 初始化房间状态
     * <p>
     * ** 需要登录之后调用,包含文档和视频的内部监听
     *
     * @param isVideoMain 是否是视频大窗
     */
    public void init(boolean isVideoMain, String recordId) {
        this.isVideoMain = isVideoMain;
        this.recordId = recordId;
        //竖屏设置弹框
        settingPopupWindow = new SettingPopupWindow(mContext);
        settingPopupWindow.setSettingPopupInterface(this);
        settingPopupWindow.addSpeed(new float[]{0.5f, 1.0f, 1.25f, 1.5f,3.0f});
        playInit();
    }

    /**
     * 重试播放
     *
     * @param updateStream 是否更新流
     */
    public void doRetry(boolean updateStream) {
        playRetry(updateStream);
    }

    /**
     * 播放/暂停
     */
    public void changePlayerStatus() {
        playChangeState(getPlaySeekBar().getProgress());
    }

    /**
     * 切换倍速
     */
    public void changePlaySpeed() {
        playChangeSpeed();
    }

    /**
     * 设置文档/视频切换的按钮的文案
     *
     * @param isFloatDismiss 小窗是否关闭
     */
    public void setSwitchText(boolean isFloatDismiss) {
        this.isFloatDismiss = isFloatDismiss;
        if (isFloatDismiss) {
            mVideoDocSwitch.setImageResource(isVideoMain ? R.drawable.open_doc : R.drawable.open_video);
            mLandVideoDocSwitch.setImageResource(isVideoMain ? R.drawable.open_doc : R.drawable.open_video);
        } else {
            mVideoDocSwitch.setImageResource(R.drawable.video_doc_switch);
            mLandVideoDocSwitch.setImageResource(R.drawable.video_doc_switch);
        }
    }

    /**
     * 设置跑马灯数据
     *
     * @param marquee Marquee
     */
    public void setMarquee(final Marquee marquee) {
        final ViewGroup parent = (ViewGroup) mMarqueeView.getParent();
        if (parent.getWidth() != 0 && parent.getHeight() != 0) {
            if (marquee != null && marquee.getAction() != null) {
                if (marquee.getType().equals("text")) {
                    mMarqueeView.setTextContent(marquee.getText().getContent());
                    mMarqueeView.setTextColor(marquee.getText().getColor().replace("0x", "#"));
                    mMarqueeView.setTextFontSize((int) DensityUtil.sp2px(mContext, marquee.getText().getFont_size()));
                    mMarqueeView.setType(1);
                } else {
                    mMarqueeView.setMarqueeImage(mContext, marquee.getImage().getImage_url(), marquee.getImage().getWidth(), marquee.getImage().getHeight());
                    mMarqueeView.setType(2);
                }
                mMarqueeView.setMarquee(marquee, parent.getHeight(), parent.getWidth());
                mMarqueeView.setOnMarqueeImgFailListener(new OnMarqueeImgFailListener() {
                    @Override
                    public void onLoadMarqueeImgFail() {
                        //跑马灯加载失败
                    }
                });
                mMarqueeView.start();
            }
        } else {
            parent.getViewTreeObserver().addOnGlobalLayoutListener(
                    new ViewTreeObserver.OnGlobalLayoutListener() {
                        @Override
                        public void onGlobalLayout() {
                            parent.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                            int width = parent.getWidth();// 获取宽度
                            int height = parent.getHeight();// 获取高度
                            if (marquee != null && marquee.getAction() != null) {
                                if (marquee.getType().equals("text")) {
                                    mMarqueeView.setTextContent(marquee.getText().getContent());
                                    mMarqueeView.setTextColor(marquee.getText().getColor().replace("0x", "#"));
                                    mMarqueeView.setTextFontSize((int) DensityUtil.sp2px(mContext, marquee.getText().getFont_size()));
                                    mMarqueeView.setType(1);
                                } else {
                                    mMarqueeView.setMarqueeImage(mContext, marquee.getImage().getImage_url(), marquee.getImage().getWidth(), marquee.getImage().getHeight());
                                    mMarqueeView.setType(2);
                                }
                                mMarqueeView.setMarquee(marquee, height, width);
                                mMarqueeView.setOnMarqueeImgFailListener(new OnMarqueeImgFailListener() {
                                    @Override
                                    public void onLoadMarqueeImgFail() {
                                        //跑马灯加载失败
                                    }
                                });
                                mMarqueeView.start();
                            }
                        }
                    });
        }

    }

    /**
     * 是否是視頻大窗/
     */
    public boolean isVideoMain() {
        return isVideoMain;
    }

    /**
     * 设置进度条是否可seek
     */
    protected void setPlaySeekBarCanSeek(boolean isCan) {
        RePlaySeekBar landPlaySeekBar = findViewById(R.id.replay_land_progressbar);
        landPlaySeekBar.setCanSeek(isCan);
        RePlaySeekBar playSeekBar = findViewById(R.id.replay_progressbar);
        playSeekBar.setCanSeek(isCan);
    }

    /**
     * 设置进度条
     *
     * @param max max
     */
    protected void setSeekBarMax(int max) {
        RePlaySeekBar landPlaySeekBar = findViewById(R.id.replay_land_progressbar);
        landPlaySeekBar.setMax(max);
        RePlaySeekBar playSeekBar = findViewById(R.id.replay_progressbar);
        playSeekBar.setMax(max);
    }

    /**
     * seek 相应时间
     *
     * @param progress progress
     */
    public void seekTo(int progress) {
        DWReplayPlayer player = getPlayer();
        if (player != null) {
            if (!player.isPlaying()) {
                playChangeState(progress);
            } else {
                player.seekTo(progress);
                if (mSeekListener != null && progress - getPlaySeekBar().getProgress() < 0) {
                    mSeekListener.onBackSeek(getPlaySeekBar().getProgress());
                }
            }
            setPlayBarProgress(progress);
            removeCallbacks(hideRunnable);
            postDelayed(hideRunnable, HIDE_TIME);
        }


    }

    public void onVideoPrepared() {
        mTipsLayout.setVisibility(GONE);
        mPlayIcon.setSelected(true);
        mLandPlayIcon.setSelected(true);
    }

    /**
     * 设置横屏倍速按钮文本
     *
     * @param speed
     */
    protected void setSpeedText(float speed) {
        String s = "";
        if (speed == 0.5f) {
            s = "0.5x";
        } else if (speed == 1.0f) {
            s = "倍速";
        } else if (speed == 1.25f) {
            s = "1.25x";
        } else if (speed == 1.5f) {
            s = "1.5x";
        } else if (speed == 3f) {
            s = "3x";
        }
        mLandSpeed.setText(s);
    }

    // endregion


    //******************************* 定时任务 用于更新进度条等 UI ********************************/

    /**
     * 开启定时器
     */
    protected void startTimerTask() {
        removeCallbacks(runnable);
        post(runnable);
    }

    /**
     * 停止计时器（播放状态、播放时间）
     */
    protected void stopTimerTask() {
        removeCallbacks(runnable);
    }

    private OnPlayerTimerListener playerTimerListener;

    public void hideMemoryPlayTip() {
        if (progress_record!=null){
            progress_record.setVisibility(View.GONE);
        }
    }

    public void hideController() {
        hide();
    }

    protected void setPlayUrl(PlayUrlInfoBean playUrlInfoBean) {
        this.playUrlInfoBean = playUrlInfoBean;
    }

    protected void setSubtitles(ReplayUrlInfo.SubtitleData subtitles) {
        subtitleView.setVisibility(View.GONE);

        if (subtitles!=null){
            this.subtitles = subtitles;
            currentSubtitleIndex = subtitles.getDefaultSubtitle();
            if (settingPopupWindow!=null){
                settingPopupWindow.addSubtitles(subtitles);
            }
            //加载字幕
            reloadSubtitle();
        }
    }

    private void reloadSubtitle() {
        if (subtitles!=null){
            subtitleView.setVisibility(View.VISIBLE);
            subtitleView.initStyle(subtitles);
            if (currentSubtitleIndex==1){
                //加载字幕2
                if (subtitles.getSubtitle2()!=null&&!TextUtils.isEmpty(subtitles.getSubtitle2().getUrl())){
                    subtitleView.loadSubtitle2(subtitles.getSubtitle2().getUrl(),isDownloadSecondSubtitle);
                }
            }else {
                //加载字幕1
                if (subtitles.getSubtitle()!=null&&!TextUtils.isEmpty(subtitles.getSubtitle().getUrl())){
                    subtitleView.loadSubtitle(subtitles.getSubtitle().getUrl(),isDownloadFirstSubtitle);
                }
            }
            subtitleView.setSubtitle(currentSubtitleIndex);
        }
    }

    /**
     * 加载本地字幕
     */
    protected void reloadLocalSubtitle(String accountId, String replayId) {
        if(accountId != null && !accountId.isEmpty() && replayId != null && !replayId.isEmpty()){
            //加载本地字幕
            // 从 SharedPreferences 读取 JSON 字符串
            SharedPreferences prefs = getContext().getSharedPreferences("SubtitleData", Context.MODE_PRIVATE);
            String json = prefs.getString(accountId+"-"+replayId, null);
            if (json != null) {
                // 使用 Gson 将 JSON 字符串转换回对象
                Gson gson = new Gson();
                ReplayUrlInfo.SubtitleData subtitles = gson.fromJson(json, ReplayUrlInfo.SubtitleData.class);
                this.subtitles = subtitles;
                reloadLocalSubtitle(subtitles);
            }
        }
    }

    protected void saveLocalSubtitle(String accountId, String replayId,ReplayUrlInfo.SubtitleData subtitles){
        //保存字幕
        if(accountId != null && !accountId.isEmpty() && replayId != null && !replayId.isEmpty()){
            //
            Gson gson = new Gson();
            String json = gson.toJson(subtitles);
            SharedPreferences prefs = getContext().getSharedPreferences("SubtitleData", Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putString(accountId+"-"+replayId, json); // 存储 JSON 字符串
            editor.apply();
        }
    }

    boolean isDownloadFirstSubtitle = false;
    boolean isDownloadSecondSubtitle = false;

    /**
     * 加载
     */
    protected void reloadLocalSubtitle(ReplayUrlInfo.SubtitleData subtitles){
        //根据
        if (subtitles!=null){
            //判断字幕是否需要下载,并下载
            if(this.subtitles == null){
                isDownloadFirstSubtitle = true;
                isDownloadSecondSubtitle = true;
            }else{
                //挡字幕1不一致
                if(this.subtitles.getSubtitle() != null && !this.subtitles.getSubtitle().getUrl().equals(subtitles.getSubtitle().getUrl())){
                    isDownloadFirstSubtitle = true;
                }
                //当字幕2不一致
                if(this.subtitles.getSubtitle2() != null && !this.subtitles.getSubtitle2().getUrl().equals(subtitles.getSubtitle2().getUrl())){
                    isDownloadSecondSubtitle = true;
                }
            }

            //下载完成，加载字幕
            this.subtitles = subtitles;
            if (settingPopupWindow!=null){
                settingPopupWindow.addSubtitles(subtitles);
            }
            reloadSubtitle();
        }
    }

    protected void onSubtitleChange(int number) {
        currentSubtitleIndex = number;
        reloadSubtitle();
//        if (subtitleView!=null){
//            subtitleView.setSubtitle(number);
//        }
    }

    public interface OnPlayerTimerListener{
        void onPlayerTimer(long time);
    }

    public void setPlayerTimerListener(OnPlayerTimerListener playerTimerListener) {
        this.playerTimerListener = playerTimerListener;
    }

    public void setTimeText() {
        DWReplayPlayer player = getPlayer();
        if (player == null) {
            return;
        }
        //更新播放器的播放时间
        long pos = 0L;
        if (!player.isPlaying() && (player.getDuration() - player.getCurrentPosition() < 500)) {
            pos = player.getDuration();
        } else {
            pos = player.getCurrentPosition();
        }
        setCurrentTime(pos);
        if (playerTimerListener != null) {
            playerTimerListener.onPlayerTimer(pos);
        }
        mPlayIcon.setSelected(player.isPlaying());
        mLandPlayIcon.setSelected(player.isPlaying());
    }

    // 设置进度时间显示
    private void setCurrentTime(final long time) {
        long playSecond = Math.round((double) time / 1000) * 1000;
        if (!isTouch && !isSeek) {
            String formatTime = TimeUtil.getFormatTime(getPlaySeekBar().getProgress());
            mCurrentTime.setText(formatTime);
            mLandCurrentTime.setText(formatTime);
            setPlayBarProgress((int) playSecond);
        }
        if (subtitleView!=null){
            subtitleView.refreshSubTitle(time);
        }
    }

    private final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            if (getPlayer() != null && getPlayer().isInPlaybackState()) {
                setTimeText();
            }
            postDelayed(runnable, 1000);
        }
    };


    //********************************* 动画相关方法 ****************************************

    protected OnClickListener mRoomAnimatorListener = new OnClickListener() {

        @Override
        public void onClick(View v) {
            removeCallbacks(hideRunnable);
            postDelayed(hideRunnable, HIDE_TIME);
            toggleTopAndButtom();
        }
    };

    protected void hide() {
        mTopLayout.clearAnimation();
        mBottomLayout.clearAnimation();
        ObjectAnimator bottom_y = ObjectAnimator.ofFloat(mBottomLayout, "translationY", mBottomLayout.getHeight());
        ObjectAnimator top_y = ObjectAnimator.ofFloat(mTopLayout, "translationY", -1 * mTopLayout.getHeight());
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(top_y).with(bottom_y);
        //播放动画的持续时间
        animatorSet.setDuration(500);
        animatorSet.start();
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                mBottomLayout.setVisibility(GONE);
                mTopLayout.setVisibility(GONE);
            }

            @Override
            public void onAnimationCancel(Animator animator) {
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
            }
        });
    }

    protected void show() {
        mTopLayout.clearAnimation();
        mBottomLayout.clearAnimation();
        mTopLayout.setVisibility(VISIBLE);
        mBottomLayout.setVisibility(VISIBLE);
        ObjectAnimator bottom_y = ObjectAnimator.ofFloat(mBottomLayout, "translationY", 0);
        ObjectAnimator top_y = ObjectAnimator.ofFloat(mTopLayout, "translationY", 0);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(top_y).with(bottom_y);
        //播放动画的持续时间
        animatorSet.setDuration(500);
        animatorSet.start();
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {

            }

            @Override
            public void onAnimationCancel(Animator animator) {


            }

            @Override
            public void onAnimationRepeat(Animator animator) {


            }
        });
        postDelayed(hideRunnable, HIDE_TIME);
    }

    protected void toggleTopAndButtom() {
        if (mTopLayout.isShown()) {
            hide();
        } else {
            show();
        }
    }

    //********************************* 进度条seek相关 ****************************************

    // 获取当前界面显示的seekbar
    protected RePlaySeekBar getPlaySeekBar() {
        int orientation = getResources().getConfiguration().orientation;
        if (orientation == Configuration.ORIENTATION_PORTRAIT) {
            // 竖屏
            return mPlaySeekBar;
        } else {
            return mLandPlaySeekBar;
        }
    }

    /**
     * @param videoPreviews
     */
    protected void setVideoPreviews(ArrayList<String> videoPreviews) {
        if (videoPreviews.size() > 0) {
            isHasVideoPreviews = true;
        }
        this.videoPreviews = videoPreviews;
        String regex = "_thumbnail_([0-9]+)\\.([a-zA-Z]+)$";
        final Pattern pattern = Pattern.compile(regex);

        //文件命名：
        //http://img-test212.play.bokecc.com/comimage/FAA3DD658CB47E29/2023-11-24/F978EAA4B676690D9C33DC5901307461_thumbnail_001.jpg
        //http://img-test212.play.bokecc.com/comimage/FAA3DD658CB47E29/2023-11-24/F978EAA4B676690D9C33DC5901307461_thumbnail_002.jpg
        //http://img-test212.play.bokecc.com/comimage/FAA3DD658CB47E29/2023-11-24/F978EAA4B676690D9C33DC5901307461_thumbnail_000.jpg

        //根据文件命名进行排序
        Collections.sort(this.videoPreviews, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                Matcher matcher1 = pattern.matcher(o1);
                if (matcher1.find()) {
                    String result1 = matcher1.group(1);
                    Matcher matcher2 = pattern.matcher(o2);
                    if (matcher2.find()) {
                        String result2 = matcher2.group(1);
                        if (result1!=null&&result2!=null){
                            try{
                                return Integer.parseInt(result1)-Integer.parseInt(result2);
                            }catch (Exception e){
                                e.printStackTrace();
                            }
                        }
                    }
                }
                return 0;
            }
        });



        //处理videoPreviews
        for (int i = 0; i < videoPreviews.size(); i++) {
            String url = videoPreviews.get(i);
            final int index = i;
            if (!TextUtils.isEmpty(url)) {
                Glide.with(getContext()).load(url).asBitmap().into(new SimpleTarget<Bitmap>() {

                    @Override
                    public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                        // 裁剪并保存
                        cropAndSaveSprites(resource, index);
                    }
                });
            }
        }
    }

    // 裁剪并保存雪碧图小图
    private void cropAndSaveSprites(Bitmap spriteSheet, int index) {
        // 定义小图的宽高
        int spriteWidth = 160;
        int spriteHeight = 90;

        // 创建目标文件夹
        File targetDir = new File(getContext().getCacheDir(), "replay_video_preview/"+recordId);
        if (!targetDir.exists()) {
            targetDir.mkdirs();
        }

        // 循环裁剪并保存小图
        for (int row = 0; row < 10; row++) {
            for (int col = 0; col < 10; col++) {
                int x = col * spriteWidth;
                int y = row * spriteHeight;

                // 裁剪小图
                Bitmap sprite = Bitmap.createBitmap(spriteSheet, x, y, spriteWidth, spriteHeight);

                // 保存小图到文件
                File spriteFile = new File(targetDir, "sprite_" + (100 * index + (row * 10 + col)) + ".png");
                //文件不存在，保存
                if (!spriteFile.exists()){
                    try {
                        FileOutputStream fos = new FileOutputStream(spriteFile);
                        sprite.compress(Bitmap.CompressFormat.PNG, 100, fos);
                        fos.flush();
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 设置进度条位置
     *
     * @param progress progress
     */
    protected void setPlayBarProgress(int progress) {
        mPlaySeekBar.setProgress(progress);
        mLandPlaySeekBar.setProgress(progress);
    }

    /**
     * 设置二级进度条位置
     *
     * @param progress progress
     */
    protected void setPlayBarSecondaryProgress(int progress) {
        mPlaySeekBar.setSecondaryProgress(progress);
        mLandPlaySeekBar.setSecondaryProgress(progress);
    }

    protected float downX;
    protected float downY;
    protected float moveX;
    protected VelocityTracker mVelocityTracker = null;
    protected boolean isSeek = false;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if ((getDocumentDisplayMode() == 1 || getDocumentDisplayMode() == 0) && mTipsLayout.getVisibility() != VISIBLE && getPlaySeekBar().isCanSeek()) {
            if (mVelocityTracker == null) {
                mVelocityTracker = VelocityTracker.obtain();
            }
            mVelocityTracker.addMovement(event);
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    downX = event.getX();
                    moveX = event.getX();
                    downY = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    float moveX = event.getX();
                    float moveY = event.getY();
                    if (Math.abs(downY - moveY) + 10 < Math.abs(moveX - this.downX)) {
                        if (getPlayer() == null) {
                            break;
                        }
                        if (Math.abs(moveX - this.downX) > 10 && getPlayer().isInPlaybackState()) {
                            stopTimerTask();
                            mVelocityTracker.computeCurrentVelocity(1000);
                            seek((moveX - this.moveX) * 1000, false, mVelocityTracker.getXVelocity(0));

                            //显示新的视频预览
                            if (isHasVideoPreviews){
                                rlCcVideoPreviewsCon.setVisibility(View.VISIBLE);
                                updateVideoPreviews(getPlaySeekBar());
                            }else {
                                String currentTime = TimeUtil.getFormatTime(getPlaySeekBar().getProgress());
                                String maxTime = TimeUtil.getFormatTime(getPlaySeekBar().getMax());
                                mSeekTime.setText(currentTime);
                                mSumTime.setText(maxTime);
                                mSeekRoot.setVisibility(VISIBLE);
                            }

                            this.moveX = moveX;
                            //手势拖拽显示进度条
                            if (mTopLayout.getVisibility() != VISIBLE) {
                                show();
                            }
                            removeCallbacks(hideRunnable);
                            isSeek = true;
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    float upX = event.getX();
                    if (isSeek) {
                        if (Math.abs(upX - downX) > 10) {
                            seek((upX - downX), true, mVelocityTracker.getXVelocity(0));
                            startTimerTask();
                        }
                        postDelayed(hideRunnable, HIDE_TIME);
                        isSeek = false;
                        rlCcVideoPreviewsCon.setVisibility(GONE);
                        mSeekRoot.setVisibility(GONE);
                        return true;
                    }
                    break;
                case MotionEvent.ACTION_CANCEL:

                    rlCcVideoPreviewsCon.setVisibility(GONE);
                    mSeekRoot.setVisibility(GONE);
                    break;
            }
        } else {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_UP:
                    performClick();
                    return false;

            }
        }
        return super.onTouchEvent(event);
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }


    protected void seek(float move, boolean isSeek, float xVelocity) {
        int max = getPlaySeekBar().getMax();
        int progress = getPlaySeekBar().getProgress();
        DWReplayPlayer player = getPlayer();
        if (progress + move < 0) {
            setPlayBarProgress(0);
        } else if (progress + move >= max) {
            setPlayBarProgress(max);
        } else if (progress + move < max) {
            setPlayBarProgress((int) (progress + ((xVelocity * 10))));
        }
        if (isSeek && player != null) {
            player.seekTo(getPlaySeekBar().getProgress());
        }
    }

    //********************************* 设置进度回调方法 ****************************************

    protected ReplayRoomLayout.SeekListener mSeekListener;

    /**
     * 设置进度监听
     *
     * @param listener listener
     */
    public void setSeekListener(ReplayRoomLayout.SeekListener listener) {
        mSeekListener = listener;
    }

    public interface SeekListener {
        void onBackSeek(long progress);
    }

    private OnPicInPicListener onPicInPicListener;

    public void setOnPicInPicListener(OnPicInPicListener onPicInPicListener) {
        this.onPicInPicListener = onPicInPicListener;
    }

    public interface OnPicInPicListener{
        void onPicInPicClick();
    }


    private OnDlnaListener onDlnaListener;

    public void setOnDlnaListener(OnDlnaListener onDlnaListener) {
        this.onDlnaListener = onDlnaListener;
    }

    public interface OnDlnaListener{
        void onDlnaClick(PlayUrlInfoBean infoBean);
    }




    //****************************** 回放直播间状态监听 用于Activity更新UI *************************

    public abstract static class ReplayRoomStatusListener {

        /**
         * 视频/文档 切换
         */
        public abstract void switchVideoDoc(boolean isVideoMain);

        /**
         * 打开小窗
         */
        public abstract void openVideoDoc();

        /**
         * 退出直播间
         */
        public abstract void closeRoom();

        /**
         * 进入全屏
         */
        public abstract void fullScreen();

        /**
         * 点击文档类型
         */
        public void onClickDocScaleType(int scaleType) {
        }

        /**
         * 切换音视频模式
         *
         * @param playMode playMode
         */
        public void onChangePlayMode(DWLiveReplay.PlayMode playMode) {

        }


    }

    // 回放直播间状态监听
    protected ReplayRoomLayout.ReplayRoomStatusListener replayRoomStatusListener;

    /**
     * 设置回放直播间状态监听
     *
     * @param listener 回放直播间状态监听
     */
    public void setReplayRoomStatusListener(ReplayRoomStatusListener listener) {
        this.replayRoomStatusListener = listener;
    }


    // ****************************** 视频打点功能 ********************************************
    public void initDotView() {
        if (dotBeans == null) {
            // ELog.i(TAG, "dotBeans is null");
            return;
        }
        if (!getPlaySeekBar().isCanSeek()) {
            // ELog.i(TAG, "mLandPlaySeekBar is not CanSeek");
            return;
        }
        post(new Runnable() {
            @Override
            public void run() {
                if (DWReplayCoreHandler.getInstance().getPlayer() == null) {
                    return;
                }
                final long duration = DWReplayCoreHandler.getInstance().getPlayer().getDuration();
                if (duration == 0) {
                    ELog.i(TAG, "player duration = 0");
                    return;
                }
                int measuredWidth = mLandPlaySeekBar.getMeasuredWidth();
                if (measuredWidth == 0) {
                    ELog.i(TAG, "measuredWidth=" + measuredWidth + ",mLandPlaySeekBar.isShown:" + mLandPlaySeekBar.isShown());
                    return;
                }
                FrameLayout seekBarGrandParent = (FrameLayout) mLandPlaySeekBar.getParent();
                List<DotView> dotViewList = new ArrayList<>();
                for (ReplayDot dotBean : dotBeans) {
                    if (dotBean.getTime() * 1000 > duration) {
                        continue;
                    }
                    DotView mDotView = new DotView(getContext());
                    mDotView.setDotTime(dotBean.getTime());
                    mDotView.setDotMsg(dotBean.getDesc());
                    dotViewList.add(mDotView);
                    seekBarGrandParent.removeView(mDotView);
                    seekBarGrandParent.addView(mDotView);
                }
                for (final DotView dotView : dotViewList) {
                    reLayoutDotView(duration, dotView);
                }
            }

        });

    }

    private void reLayoutDotView(long mDuration, final DotView dotView) {
        int measuredWidth = mLandPlaySeekBar.getWidth();
        if (mDuration <= 0 || measuredWidth <= 0) {
            return;
        }
        int currentPosition = dotView.getDotTime();
        int seekBarWidth = mLandPlaySeekBar.getProgressDrawable().getBounds().width();
        int thumbWidth = mLandPlaySeekBar.getThumb().getBounds().width();
        final double x_position = (seekBarWidth * 1.00) / mDuration * currentPosition * 1000;
        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) dotView.getLayoutParams();
        layoutParams.leftMargin = (int) Math.round(mLandPlaySeekBar.getPaddingLeft() + (thumbWidth >> 1) + x_position - (dotView.getRootWidth() >> 1));
        layoutParams.height = mLandPlaySeekBar.getHeight();
        dotView.setLayoutParams(layoutParams);
        dotView.setOnDotViewClickListener(new DotView.OnDotViewClickListener() {
            @Override
            public void onDotViewClick() {
                int[] position = new int[2];
                dotView.getLocationInWindow(position);
                removeCallbacks(hideRunnable);
                // 打点弹出框
                popupWindow = new DotMsgPopupWindow(getContext(), dotView, position[0], position[1]);
                popupWindow.show(mLandPlaySeekBar);
                popupWindow.setOnDotViewMsgClickListener(new DotMsgPopupWindow.OnDotViewMsgClickListener() {
                    @Override
                    public void onDotViewMsgClick() {
                        seekTo(dotView.getDotTime() * 1000);

                    }
                });

            }
        });
    }


    //********************************* 需要实现的方法 ****************************************

    /**
     * 初始化
     */
    protected abstract void playInit();

    /**
     * 重试播放
     *
     * @param updateStream 是否更新流
     */
    protected abstract void playRetry(boolean updateStream);

    /**
     * 修改播放状态
     */
    protected abstract void playChangeState(long progress);

    /**
     * 修改播放倍速
     */
    protected abstract void playChangeSpeed();

    /**
     * 获取播放器对象
     */
    protected abstract DWReplayPlayer getPlayer();

    /**
     * 获取文档展示模式
     *
     * @return 文档窗口状态：1——适合窗口，2——适合宽度
     */
    protected abstract int getDocumentDisplayMode();

    protected abstract boolean isHasDoc();

    @Override
    public void onSpeed(float speed) {

    }

    @Override
    public void onPlayMode(boolean isAudio, SettingPopupWindowCallBack callBack) {

    }

    @Override
    public void onQuality(int quality, String desc, SettingPopupWindowCallBack callBack) {

    }

    @Override
    public void onLine(int line, SettingPopupWindowCallBack callBack) {

    }

    @Override
    public void onSubtitle(int number) {
        onSubtitleChange(number);
    }

    public void setActivity(Activity activity) {
        this.activity = activity;
        settingPopupWindow.setActivity(activity);
    }

    public void showPicInPicButton(boolean show){
        ccReplayPicInPic.setVisibility(show?VISIBLE:GONE);
    }
}
