<template>
    <view
        class="xt-video"
        :class="{
            'xt-video-fullscreen': isFullscreen,
        }"
        :style="{
            width: width,
            height: height,
        }"
    >
        <view
            class="xt-video-title"
            :class="{ 'xt-video-title-show': showControls }"
        >
            <text class="xt-video-title-text">{{ title }}</text>
        </view>
        <video
            class="xt-video-video"
            :id="videoId"
            :src="videoSrc"
            :autoplay="autoplay"
            :loop="loop"
            :muted="isMuted"
            :initial-time="initialTime"
            :duration="duration"
            :enable-danmu="false"
            :controls="false"
            :poster="poster"
            :show-center-play-btn="false"
            @play="xtVideoPlay"
            @click="xtVideoClick"
            @error="xtVideoError"
            @waiting="xtVideoWaiting"
            @loadedmetadata="xtVideoLoaded"
            @ended="xtVideoEnded"
            @timeupdate="xtVideoUpdate"
            @fullscreenchange="fullscreenchange"
        ></video>
        <!-- 控制条 -->
        <XtVideoControls
            :showControls="showControls"
            :playing="playing"
            :startTime="startTime"
            :totalTime="totalTime"
            :activeColor="activeColor"
            :isFullscreen="isFullscreen"
            :ratios="ratios"
            :ratioId="ratioId"
            :episodes="episodes"
            :showSpeed="showSpeed"
            @xtPlay="xtPlay"
            @xtPause="xtVideoPause"
            @xtVideoSlider="xtVideoSlider"
            @xtVideoSliding="xtVideoSliding"
            @xtVideoFullscreen="xtVideoFullscreen"
            @xtVideoExitFullscreen="xtVideoExitFullscreen"
            @xtRatioChange="xtShowRatioChange"
            @xtOpenEpi="xtOpenEpi"
            @xtOpenSpeed="xtOpenSpeed"
        />
        <!-- 中间播放按钮 -->
        <image
            v-if="!playing && showCenterPlay"
            class="xt-video-center-btn"
            src="../static/xt-video/xt-icon-play.png"
            @click="xtPlay"
        ></image>

        <!-- 静音控件 -->
        <view
            class="xt-controls-left"
            :class="{ 'xt-controls-left-show': showControls }"
        >
            <image
                v-if="!isMuted"
                class="xt-video-muted"
                src="../static/xt-video/xt-icon-muted-false.png"
                @click="xtVideoMuted"
            ></image>
            <image
                v-else
                class="xt-video-muted"
                src="../static/xt-video/xt-icon-muted.png"
                @click="xtVideoMuted"
            ></image>
        </view>

        <!-- 多分辨率切换 -->
        <view
            v-if="ratios && ratios.length > 0"
            class="xt-controls-ratios"
            :class="{ 'xt-ratio-show': isRatio }"
        >
            <block v-for="(item, index) in ratios" :key="item.id">
                <view
                    class="xt-controls-ratios-item"
                    :class="{ 'xt-ratio-active': ratioId === item.id }"
                    @click="xtRatioChange(item)"
                >
                    <text>{{ item.name }}</text>
                </view>
                <view
                    v-if="index !== ratios.length - 1"
                    class="xt-ratio-line"
                ></view>
            </block>
        </view>

        <!-- 倍速切换 -->
        <view
            v-if="showSpeed"
            class="xt-controls-ratios"
            :class="{ 'xt-ratio-show': isSpeed }"
        >
            <block v-for="(item, index) in speeds" :key="item.rate">
                <view
                    class="xt-controls-ratios-item"
                    :class="{ 'xt-ratio-active': speed === item.rate }"
                    @click="xtSpeedChange(item)"
                >
                    <text>{{ item.name }}</text>
                </view>
                <view
                    v-if="index !== speeds.length - 1"
                    class="xt-ratio-line"
                ></view>
            </block>
        </view>

        <!-- 选集弹框 -->
        <XtVideoEpisodes
            v-if="episodes && episodes.length > 0"
            ref="epiRef"
            :episodes="episodes"
            :isFullscreen="isFullscreen"
            :vipBgColor="vipBgColor"
            :vipFontColor="vipFontColor"
            :navHeight="navHeight"
            :epiDefaultId="epiDefaultId"
            @xtEpiChange="xtVideoEpiChange"
            @xtEpiHide="xtEpiHide"
        />

        <!-- 视频缓冲 -->
        <XtVideoLoading v-if="showLoading" />

        <!-- 视频播放失败 -->
        <XtVideoError v-if="showError" @onReload="xtVideoReload" />
    </view>
</template>

<script>
import XtVideoLoading from "./xt-video-loading.vue";
import XtVideoError from "./xt-video-error.vue";
import XtVideoControls from "./xt-video-controls.vue";
import XtVideoEpisodes from "./xt-video-episodes.vue";
import { formatSeconds, isArray } from "../utils/xt-uitls.js";
export default {
    components: {
        XtVideoLoading,
        XtVideoError,
        XtVideoControls,
        XtVideoEpisodes,
    },
    props: {
        // 视频唯一id
        videoId: {
            type: String,
            default: "",
            required: true,
        },
        // 视频宽度，默认100%
        width: {
            type: String,
            default: "100%",
        },
        // 视频高度，默认422rpx
        height: {
            type: String,
            default: "422rpx",
        },
        // 视频播放地址
        src: {
            type: String,
            default: "",
            required: true,
        },
        // 设置默认播放的分辨率
        ratioDefaultId: {
            type: [Number, String],
            default: null,
        },
        // 多分辨率播放
        ratios: {
            type: Array,
            default: () => {
                return [];
            },
        },
        // 视频封面
        poster: {
            type: String,
            default: "",
        },
        // 是否自动播放
        autoplay: {
            type: Boolean,
            default: false,
        },
        // 是否循环播放
        loop: {
            type: Boolean,
            default: false,
        },
        // 是否静音播放
        muted: {
            type: Boolean,
            default: false,
        },
        // 指定视频初始播放位置，单位（s）
        initialTime: {
            type: Number,
            default: 0,
        },
        // 指定视频总时长，单位（s）
        duration: {
            type: Number,
        },
        // 是否显示全屏按钮
        showFullscreenBtn: {
            type: Boolean,
            default: true,
        },
        // 进度条颜色
        activeColor: {
            type: String,
            default: "#03A3F8",
        },
        // 视频标题
        title: {
            type: String,
            default: "",
        },
        // 自定义全屏事件
        customFullscreen: {
            type: Boolean,
            default: false,
        },
        // 选集列表
        episodes: {
            type: Array,
            default: () => {
                return [];
            },
        },
        // vip背景色
        vipBgColor: {
            type: String,
            default: "#FF5345",
        },
        // vip文字颜色
        vipFontColor: {
            type: String,
            default: "#ffffff",
        },
        // 导航栏高度，用于视频全屏时，如果存在导航栏，导致选集弹框展示不全问题
        navHeight: {
            type: Number,
            default: 44,
        },
        // 默认播放第几集
        epiDefaultId: {
            type: [Number, String],
            default: null,
        },
        // 倍速数组
        speeds: {
            type: Array,
            default: () => {
                return [
                    { rate: 0.5, name: "0.5x" },
                    { rate: 0.8, name: "0.8x" },
                    { rate: 1.0, name: "1.0x" },
                    { rate: 1.25, name: "1.25x" },
                    { rate: 1.5, name: "1.5x" },
                    { rate: 2.0, name: "2.0x" },
                ];
            },
        },
        // 是否显示倍速播放
        showSpeed: {
            type: Boolean,
            default: false,
        },
    },
    data() {
        return {
            // video实例
            xtVideo: uni.createVideoContext(this.videoId, this),
            // 视频链接
            videoSrc: this.src,
            // 是否正在播放
            playing: false,
            // 是否显示控制条
            showControls: false,
            // 视频总时长
            totalTime: 0,
            // 视频开始时间
            startTime: 0,
            // 是否开启弹幕
            openDanmu: true,
            // 视频缓冲中
            showLoading: false,
            // 是否全屏
            isFullscreen: false,
            // 视频播放失败
            showError: false,
            // 是否显示中间播放按钮
            showCenterPlay: true,
            // 是否静音
            isMuted: this.muted,
            // 是否显示分辨率弹框
            isRatio: false,
            // 分辨率id
            ratioId: this.ratioDefaultId
                ? this.ratioDefaultId
                : this.ratios[0] && this.ratios[0].id,
            // 是否显示倍速弹框
            isSpeed: false,
            // 播放速度
            speed: 1.0,
        };
    },
    methods: {
        // 视频播放
        xtPlay() {
            this.xtVideo.play();
            this.playing = true;
            this.showCenterPlay = true;
            this.showControls = true;
        },

        // 监听视频播放
        xtVideoPlay() {
            this.showCenterPlay = false;
            this.playing = true;
        },

        // 视频暂停
        xtVideoPause() {
            this.xtVideo.pause();
            this.playing = false;
        },

        // 视频播放完成
        xtVideoEnded() {
            if (this.loop) {
                return;
            }
            this.showCenterPlay = true;
            this.playing = false;
            this.showControls = true;
        },

        // 视频播放出错了
        xtVideoError(err) {
            this.startTime = 0;
            this.totalTime = 1;
            this.showError = true;
            this.showCenterPlay = false;
        },

        // 视频出现缓冲
        xtVideoWaiting() {
            this.showLoading = true;
        },

        // 视频点击控制控制条和标题的展示与隐藏
        xtVideoClick() {
            this.showControls = !this.showControls;
            this.isRatio = false;
            this.isSpeed = false;
        },

        // 视频元数据加载完成
        xtVideoLoaded({ detail }) {
            this.totalTime = detail.duration;
            this.startTime = 0;
        },

        // 播放进度发生变化
        xtVideoUpdate({ detail }) {
            this.$emit("timeupdate", { detail: detail });
            this.startTime = detail.currentTime;
            this.showLoading = false;
        },

        // 进度条拖动过程中
        xtVideoSliding() {
            this.xtVideo.pause();
            this.playing = false;
        },

        // 进度条拖动结束
        xtVideoSlider(detail) {
            this.startTime = (this.totalTime * detail.value) / 100;
            this.xtVideo.seek(this.startTime);
            this.xtVideo.play();
            this.playing = true;
            this.showControls = true;
        },

        // 点击全屏
        xtVideoFullscreen() {
            this.isFullscreen = true;
            if (this.customFullscreen) {
                this.$emit("onFullscreen", this.isFullscreen);
            } else {
                switch (uni.getSystemInfoSync().platform) {
                    case "android":
                        document.documentElement.requestFullscreen();
                        break;
                    case "ios":
                        uni.createVideoContext(
                            this.videoId.toString(),
                            this
                        ).requestFullScreen();
                        break;
                }
            }
        },
        // 退出全屏
        xtVideoExitFullscreen() {
            this.isFullscreen = false;
            if (this.customFullscreen) {
                this.$emit("onExitFullscreen", this.isFullscreen);
            } else {
                switch (uni.getSystemInfoSync().platform) {
                    case "android":
                        document.exitFullscreen();
                        break;
                    case "ios":
                        uni.createVideoContext(
                            this.videoId.toString(),
                            this
                        ).stop();
                        break;
                }
            }
        },
        // h5-ios退出系统自带全屏播放器
        fullscreenchange() {
            this.isFullscreen = false;
            this.xtPlay();
        },
        // 视频重新加载
        xtVideoReload({ url = null, startTime = this.startTime } = {}) {
            if (url) {
                this.videoSrc = url;
            }
            this.playing = true;
            this.showCenterPlay = true;
            this.showControls = true;
            this.$nextTick(() => {
                this.xtVideo.seek(startTime);
                this.xtVideo.play();
            });
        },

        // 控制是否静音
        xtVideoMuted() {
            this.isMuted = !this.isMuted;
        },

        // 控制分辨率展示
        xtShowRatioChange() {
            this.showControls = false;
            this.isRatio = true;
        },

        // 点击改变分辨率
        xtRatioChange(item) {
            this.ratioId = item.id;
            this.isRatio = false;
            this.$emit("onChangeRatio", item);
        },

        // 展示选集弹框
        xtOpenEpi() {
            this.showControls = false;
            this.$refs.epiRef._show();
        },

        // 更改选集
        xtVideoEpiChange(item) {
            this.$emit("onChangeEpi", item);
        },

        // 隐藏选集
        xtEpiHide() {
            this.showControls = true;
        },

        // 点击打开倍速切换弹框
        xtOpenSpeed() {
            this.showControls = false;
            this.isSpeed = true;
        },

        // 切换播放速率
        xtSpeedChange(item) {
            this.speed = item.rate;
            this.xtVideo.playbackRate(item.rate);
            this.isSpeed = false;
            this.showControls = true;
        },
    },
};
</script>

<style lang="scss" scoped>
.xt-video {
    position: relative;
    overflow: hidden;
    &-video {
        width: 100%;
        height: 100%;
    }
    &-center-btn {
        position: absolute;
        z-index: 5;
        left: 50%;
        margin-left: -48rpx;
        top: 50%;
        margin-top: -48rpx;
        width: 96rpx;
        height: 96rpx;
        border-radius: 50%;
    }
    .xt-controls-left {
        position: absolute;
        right: 16rpx;
        bottom: 100rpx;
        transform: translateX(80rpx);
        transition: all 0.3s ease;
        &-show {
            transform: translateX(0);
        }
    }
    &-muted {
        width: 64rpx;
        height: 64rpx;
    }
    .xt-video-title {
        position: absolute;
        top: 0;
        left: 0;
        z-index: 5;
        width: 100%;
        height: 64rpx;
        transform: translateY(-64rpx);
        box-sizing: border-box;
        padding: 0 24rpx;
        display: flex;
        align-items: center;
        background: linear-gradient(
            180deg,
            rgba(0, 0, 0, 0.5) 0%,
            rgba(0, 0, 0, 0) 100%
        );
        transition: all 0.3s ease;
        &-text {
            font-size: 30rpx;
            color: #fff;
            flex: 1;
            text-overflow: ellipsis;
            white-space: nowrap;
            overflow: hidden;
        }
        &-show {
            transform: translateY(0);
        }
    }
}
.xt-video-fullscreen {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100% !important;
    z-index: 9999;
}
.xt-controls-ratios {
    box-sizing: border-box;
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 100rpx;
    background-color: rgba(0, 0, 0, 0.3);
    display: none;
    justify-content: center;
    align-items: center;
    padding: 0 20rpx;
    &-item {
        display: block;
        padding: 0 20rpx;
        font-size: 28rpx;
        color: #fff;
    }
    .xt-ratio-line {
        width: 1px;
        height: 20rpx;
        margin: 0 10rpx;
        background-color: rgba(255, 255, 255, 0.3);
    }
    .xt-ratio-active {
        border-radius: 10rpx;
        background-color: rgba(255, 255, 255, 0.3);
    }
}
.xt-ratio-show {
    display: flex;
}
</style>