<template>
    <view
        :style="{
            visibility: 'visible',
            'z-index': 921,
        }"
        class="image-viewer"
    >
        <view
            :style="{
                opacity: 1,
            }"
            class="inner"
        >
            <!-- 背景 -->
            <view
                :style="{
                    opacity: maskOpacity,
                }"
                class="mask"
            />
            <!-- 顶部区域 -->
            <view
                class="close-wrapper"
                :style="{
                    paddingTop: env === 'swan' ? (isFull && isIphoneX ? '110px' : '150px') : '10px'
                }"
            >
                <!-- nav切换 -->
                <c-navs
                    v-if="options && options.length > 1"
                    class="nav-wrapper"
                    :options="options"
                    :bottom-line="false"
                    background-color="transparent"
                    selected-color="#fff"
                    :selected-index="selectedIndex"
                    @itemtap="handleItemTap"
                />
                <!-- 关闭图标 -->
                <c-icon
                    name="close"
                    class="close"
                    @tap="handleCloseTap"
                />
            </view>
            <!-- 小程序自带轮播 -->
            <swiper
                :current="curIndex"
                :duration="swiperDuration"
                class="swiper"
                @change="handleSwiperChange"
            >
                <template v-if="videoList && videoList.length">
                    <swiper-item
                        v-for="(video, vdoIndex) in videoList"
                        :key="'video' + vdoIndex"
                    >
                        <view
                            class="vdo-wrapper"
                            :style="{'width': '100%', 'height': imageHeight + 'px'}"
                        >
                            <video
                                :id="'video' + vdoIndex"
                                style="width: 100%;"
                                :src="video.src"
                                :poster="video.imgUrl"
                                :autoplay="vdoIndex === 0 && videoAutoplay"
                                :direction="0"
                                :enable-progress-gesture="false"
                                object-fit="containe"
                                loop
                                @play="videoPlay"
                                @pause="videoPause"
                            >
                            </video>
                        </view>
                        <!-- 页码 -->
                        <view
                            v-if="videoList.length > 1"
                            class="page-num"
                        >
                            {{ curIndex }}/{{ videoList.length }}
                        </view>
                    </swiper-item>
                </template>
                <template v-if="imgList && imgList.length">
                    <swiper-item
                        v-for="(item, itemIndex) in imgList"
                        :key="itemIndex"
                        item-id="itemIndex"
                    >
                        <!-- eslint-disable max-len -->
                        <view
                            :style="{
                                'background-image': 'url(' + item + ')',
                                '-webkit-transform': curIndex === itemIndex ? 'translate3d(' + disXShow + 'px,' + disYShow + 'px,0) scale(' + imgScale + ')' : '',
                                'transform': curIndex === itemIndex ? 'translate3d(' + disXShow + 'px,' + disYShow + 'px,0 scale(' + imgScale + ')' : '',
                                'transform-origin': multiOrigin ? multiOrigin.x + 'px ' + multiOrigin.y + 'px' : 'center',
                            }"
                            :class="{
                                'img-transition': imgTransition,
                            }"
                            class="img"
                            @touchstart="handleImgTouchStart"
                            @touchmove="handleImgTouchMove"
                            @touchend="handleImgTouchEnd"
                        />
                        <!-- 页码 -->
                        <view
                            v-if="imgList.length > 1"
                            class="page-num"
                        >
                            {{ curIndex }}/{{ imgList.length }}
                        </view>
                    </swiper-item>
                </template>
            </swiper>

        </view>
    </view>
</template>

<script>
/* global getApp */
/**
 * @file 大图展示视频、图片
 * @author zhangqian51
 * @categories 大图展示视频、图片
 * @tags [component]
 */
import CIcon from '@baidu/med-ui/components/Icon/Icon';
import CNavs from '@baidu/med-ui/components/Navs/Navs';
import {getSystemInfo} from '@baidu/med-utils/lib/Mars/system';
import {isFullPhone} from '../../utils/core';

export default {
    config: {
        component: true
    },
    components: {
        CIcon,
        CNavs
    },
    props: {

        /**
         * 视频数组
         */
        videoList: {
            type: Array,
            default: () => {
                return [];
            }
        },

        /**
         * 图片数组
         */
        imgList: {
            type: Array,
            default: () => {
                return [];
            }
        },

        /**
         * 是否显示
         */
        // show: {
        //     type: Boolean,
        //     default: false
        // },

        /**
         * 当前索引
         */
        index: {
            type: Number
        },

        /**
         * 滑动关闭距离；touchend 时滑动距离超过这个值会触发关闭
         */
        slideCloseDistance: {
            type: Number,
            default: 150
        },

        /**
         * 滑动关闭速度
         */
        slideCloseSpeed: {
            type: Number,
            default: 0.23
        }
    },
    data() {
        return {
            // 最外层隐藏或显示
            visibility: 'visible',
            // 预览框zIndex
            zIndex: 921,
            // swiper 滑动时长
            swiperDuration: 500,
            // 透明度
            opacity: 1,
            // 蒙层透明度
            maskOpacity: 1,
            // 当前索引
            curIndex: 1,
            // 屏幕宽高
            screenWidth: 0,
            screenHeight: 0,
            // 起始位置
            startX: 0,
            startY: 0,
            // 实时移动位置
            moveX: 0,
            moveY: 0,
            // 位置 diff
            disX: 0,
            disY: 0,
            // 视觉上要偏离的位置 diff
            disXShow: 0,
            disYShow: 0,
            // 触摸开始、结束时间戳
            touchStartTime: 0,
            touchEndTime: 0,
            // 触摸时长
            touchDuration: 0,
            // 滑动方向
            slideDirection: 0,
            // 滑动速度
            slideSpeed: 0,
            // 图片动效
            imgTransition: false,
            // 图片动效时间
            imgTransitionTime: 300,
            // 图片缩放
            imgScale: 1,
            // 多指触摸
            isMultiTouch: false,
            // 滑动保护
            slideProtect: false,
            // 滑动保护延时执行句柄
            slideProtectTimeout: null,
            // touchmove 执行次数
            touchMoveTime: 0,

            // 双指滑动缩放

            startPoint1: {
                x: 0,
                y: 0
            },
            startPoint2: {
                x: 0,
                y: 0
            },
            movePoint1: {
                x: 0,
                y: 0
            },
            movePoint2: {
                x: 0,
                y: 0
            },
            // 起始两个触摸点间的距离
            startDistance: 0,
            // 终止两个触摸点间的距离
            endDistance: 0,
            // 多指缩放倍数
            multiScale: 1,
            // 多指缩放中心点
            multiOrigin: {
                x: 0,
                y: 0
            },
            // navs数据
            options: [],
            // navs选中项
            selectedIndex: 0,
            videoAutoplay: false,
            imageHeight: 0,
            isIphoneX: false,
            env: 'h5',
            isFull: false,
            isInApp: getApp().globalData.isInApp
        };
    },
    onLoad() {
        this.getAutoplay();
    },
    created() {
        const systemInfo = getSystemInfo();
        if (systemInfo.model.search('iPhone X') !== -1
            || systemInfo.model.search('iPhone 11') !== -1
            || systemInfo.model.search('iPhone 12') !== -1
            || systemInfo.model.search('iPhone 13') !== -1
        ) {
            this.isIphoneX = true;
        }
        if (process.env.MARS_ENV === 'swan') {
            this.env = 'swan';
            this.isFull = isFullPhone(systemInfo);
        }
        // 计算宽高
        this.calculateWidthHeight();
        this.curIndex = this.index;
        this.handleOptions();
    },
    methods: {

        /**
         * 计算宽高
         */
        calculateWidthHeight() {
            let systemInfo = getSystemInfo();
            this.screenWidth = systemInfo.screenWidth;
            this.screenHeight = systemInfo.screenHeight;
            this.imageHeight = this.screenWidth * .85;
        },

        // 初始化 navs 数据
        handleOptions() {
            if (this.videoList && this.videoList.length && this.imgList && this.imgList.length) {
                this.options = [
                    {'text': '视频', 'key': 'video'},
                    {'text': '图片', 'key': 'img'}
                ];
                if (this.curIndex >= this.videoList.length) {
                    this.selectedIndex = 1;
                }
            }
        },

        // 切换navs-视频、图片
        handleItemTap(obj) {
            this.selectedIndex = obj.index;
            if (obj.item.key === 'img') {
                this.curIndex = this.videoList.length;
            }
            if (obj.item.key === 'video') {
                this.curIndex = 0;
            }
        },
        getAutoplay() {
            this.$api.getNetworkType({
                success: res => {
                    this.videoAutoplay = res && res.networkType === 'wifi';
                }
            });
        },
        videoPlay() {
            this.$emit('videoPlay');
        },
        videoPause() {
            this.$emit('videoPause');
        },
        // 关闭大图
        close() {
            /**
             * 关闭事件
             *
             * @event close
             */
            this.$emit('close');
        },

        // 关闭按钮点击
        handleCloseTap() {
            this.curIndex = 0;
            this.close();
        },

        // swiper change
        handleSwiperChange(obj) {
            const {current} = obj.detail;
            this.curIndex = current;
            this.selectedIndex = (this.videoList.length && (this.curIndex < this.videoList.length)) ? 0 : 1;
            // 恢复缩放
            this.imgScale = 1;
        },

        // 图片触摸开始
        handleImgTouchStart(e) {
            // 滑动保护
            if (this.slideProtect) {
                return;
            }
            // 单指滑动
            if (e.touches.length === 1) {
                // 记录开始位置
                this.startX = e.touches[0].clientX;
                this.startY = e.touches[0].clientY;
                // 记录起始时间
                this.touchStartTime = new Date().getTime();
            }
            // 双指滑动
            else if (e.touches.length === 2) {
                // 开启多指触摸
                this.isMultiTouch = true;
                // 记录触摸开始点
                this.startPoint1.x = e.touches[0].pageX;
                this.startPoint1.y = e.touches[0].pageY;
                this.startPoint2.x = e.touches[1].pageX;
                this.startPoint2.y = e.touches[1].pageY;
                // 记录开始时的距离
                this.startDistance = this.getDistance(this.startPoint1, this.startPoint2);
            }
        },

        handleImgTouchMovePre(e) {
            let f = this.throttle(this.handleImgTouchMove, 100);
            f(e);
        },

        // 图片触摸滑动
        handleImgTouchMove(e) {
            // 滑动保护
            if (this.slideProtect) {
                return;
            }
            // 统计 touchmove 事件的触发次数
            this.touchMoveTime++;
            // 小程序里的 e 没有 preventDefault 方法，需要先判断
            e.preventDefault && e.preventDefault();
            // 先关掉 img 的动效，让拖动跟手
            this.imgTransition = false;
            // 单指滑动 并且不是多指触摸
            // e.changedTouches 会实时变动，e.touches 不会
            if (e.touches.length === 1) {
                // 阻止默认事件，放置滚动事件透传
                this.moveX = e.touches[0].clientX;
                this.moveY = e.touches[0].clientY;
                this.disX = this.moveX - this.startX;
                this.disY = this.moveY - this.startY;
                // 计算方向
                this.slideDirection = this.getDirection(this.disX, this.disY);
                // 纵轴向上
                if (this.slideDirection === 1) {
                    // X 轴会卡
                    // this.disXShow = this.disX;
                    this.disYShow = this.disY;
                    this.maskOpacity = 1;
                    this.imgScale = 1;
                }
                // 纵轴向下
                else if (this.slideDirection === 2) {
                    // X 轴会卡
                    // this.disXShow = this.disX;
                    this.disYShow = this.disY;
                    // 计算出滑动高度和屏幕高度的百分比
                    let per = 1 - Math.abs(this.disY) / this.screenHeight;
                    // 通过百分比的变化设置透明度和缩放
                    this.maskOpacity = per;
                    // this.imgScale = per;
                }
            }
            // 双指滑动
            else if (e.touches.length === 2) {
                // 开启多指触摸
                this.isMultiTouch = true;
                // 计算滑动触摸点
                this.movePoint1.x = e.touches[0].pageX;
                this.movePoint1.y = e.touches[0].pageY;
                this.movePoint2.x = e.touches[1].pageX;
                this.movePoint2.y = e.touches[1].pageY;
                // 计算中心点
                this.multiOrigin = this.getOrigin(this.movePoint1, this.movePoint2);
                // 计算终止距离
                this.endDistance = this.getDistance(this.movePoint1, this.movePoint2);
                // this.imgTransition = true;
                // 计算放大倍数
                this.imgScale = this.endDistance / this.startDistance;
                this.disXShow = (this.multiOrigin.x - this.multiOrigin.x * this.imgScale) / 2;
                this.disYShow = (this.multiOrigin.y * this.imgScale - this.multiOrigin.y) / 2;
            }
        },

        // 图片滑动结束
        handleImgTouchEnd(e) {
            // 滑动保护
            if (this.slideProtect) {
                return;
            }
            // 记录结束时间
            this.touchEndTime = new Date().getTime();
            // 计算出持续时间
            this.touchDuration = this.touchEndTime - this.touchStartTime;
            // 计算出速度
            this.speed = this.disY / this.touchDuration;
            // 向下滑动
            if (this.slideDirection === 2 && !this.isMultiTouch) {
                // 速度达到阈值直接关闭
                if (this.speed >= this.slideCloseSpeed) {
                    this.close();
                }
                // 速度未达到阈值，再判断距离是否达到阈值
                else if (this.disY > this.slideCloseDistance) {
                    this.close();
                }
            }

            // 众神归位
            this.imgTransition = true;
            this.maskOpacity = 1;
            this.disX = 0;
            this.disXShow = 0;
            this.disY = 0;
            this.disYShow = 0;
            this.imgScale = 1;
            this.isMultiTouch = false;

            // 打开动画保护
            this.slideProtect = true;
            if (this.slideProtectTimeout) {
                clearTimeout(this.slideProtectTimeout);
                this.slideProtectTimeout = null;
            }
            // 延迟动画时间清除滑动保护
            this.slideProtectTimeout = setTimeout(() => {
                this.slideProtect = false;
            }, 300);
        },

        // 根据起点终点返回方向 1向上 2向下 3向左 4向右 0未滑动
        getDirection(angx, angy) {
            let result = 0;
            // 如果滑动距离太短
            if (Math.abs(angx) < 2 && Math.abs(angy) < 2) {
                return result;
            }
            let angle = this.getAngle(angx, angy);
            if (angle >= -135 && angle <= -45) {
                result = 1;
            }
            else if (angle > 45 && angle < 135) {
                result = 2;
            }
            else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
                result = 3;
            }
            else if (angle >= -45 && angle <= 45) {
                result = 4;
            }
            return result;
        },

        // 获得角度
        getAngle(angx, angy) {
            return Math.atan2(angy, angx) * 180 / Math.PI;
        },

        // throttle
        throttle(func, wait, options) {
            let timeout = null;
            // 保存函数调用时的上下文和参数，传递给 fn
            /* eslint-disable */
            let context = this;
            return function (t) {
                let args = t;
                clearTimeout(timeout);
                timeout = setTimeout(function () {
                    func.apply(context, args);
                }, wait);
            };
        },

        // TODO:多指放大参考：http://blog.codingplayboy.com/2017/04/16/mobile_gesture/

        /**
         * 计算缩放中心的坐标
         *
         * @param {Object} first 第一个触摸点
         * @param {Object} second 第二个触摸点
         * @return {Object} 触摸点对象
         */
        getOrigin(first, second) {
            return {
                x: (first.x + second.x) / 2,
                y: (first.y + second.y) / 2
            };
        },

        /**
         * 计算距离
         *
         * @param {Object} first 第一个触摸点
         * @param {Object} second 第二个触摸点
         * @return {number} 距离
         */
        getDistance(first, second) {
            return Math.sqrt(Math.pow((second.x - first.x), 2) + Math.pow((second.y - first.y), 2));
        },

        /**
         * 计算缩放比例
         *
         * @param {Array} start 起始坐标数组
         * @param {Array} end 结束坐标数组
         * @return {number} 缩放比例
         */
        getScale(start, end) {
            return this.getDistance(start[0], start[1]) / this.getDistance(end[0], end[1]);
        }
    },
    watch: {
        index(newVal, oldVal) {
            // 在设置图片索引之前，清零动效时长，避免设置的时候出现滑动到指定图片的动效
            this.swiperDuration = 0;
            // 设置图片索引
            this.curIndex = newVal;
            // 延时恢复滑动动效
            setTimeout(() => {
                this.swiperDuration = 500;
            }, 300);
        },
        show(newVal, oldVal) {
            // 打开时的透明度动效
            if (newVal) {
                this.visibility = 'visible';
                this.zIndex = 921;
                this.opacity = 1;
            }
            else {
                this.opacity = 0;
                this.zIndex = 0;
                setTimeout(() => {
                    this.visibility = 'hidden';
                }, 300);
            }
        }
    }
};
</script>

<style lang="less" scoped>
.image-viewer {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}

.inner {
    position: relative;
    width: 100%;
    height: 100%;
    transition: opacity .3s cubic-bezier(0, 0, .3, 1);
}

.mask {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    transition: opacity .3s cubic-bezier(0, 0, .3, 1);
    background-color: #000;
}

.close-wrapper {
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding: 0 10px;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 70px;
    background: -webkit-gradient(linear, center top, center bottom, color-stop(0%, rgba(0, 0, 0, 0.25)), color-stop(100%, rgba(0, 0, 0, 0)));
    box-sizing: border-box;
    z-index: 1;
}

.close {
    padding: 5px 8px;
    color: #656565;
    font-size: 20px;
    z-index: 1;
    background-color: rgba(162, 162, 162, 0.22);
    border-radius: 16px;
}

.swiper {
    width: 100%;
    height: 100%;

    .vdo-wrapper {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
    }

    .img {
        background-size: contain;
        background-position: center;
        background-repeat: no-repeat;
        width: 100%;
        height: 100%;
    }

    .img-transition {
        transition: all .3s cubic-bezier(.2, 0, .2, 1);
    }
}

.page-num {
    position: absolute;
    bottom: 20%;
    left: 50%;
    transform: translateX(-50%);
    color: #fff;
    font-size: 12px;
    display: flex;
    align-items: center;
    padding: 3px 13px;
    box-sizing: border-box;
    border-radius: 14px;
    background-color: rgba(162, 162, 162, 0.22);
}

.nav-wrapper {
    width: 100px;
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
}
</style>
