//
//  PQStuckPointCuttingView.swift
//  PQSpeed
//
//  Created by SanW on 2021/5/8.
//  Copyright © 2021 BytesFlow. All rights reserved.
//

import BFAnalyzeKit
import BFCommonKit
import BFUIKit
import UIKit

class PQStuckPointCuttingView: UIView {
    // 视频时长
    var videoDuration: CGFloat = 0
    var lastVideoDuration: CGFloat = 0
    // 卡点开始时间 默认 0
    var stuckPointStartTime: CGFloat = 0
    // 卡点结束时间
    var stuckPointEndTime: CGFloat = 0
    // 裁剪开始时间 默认 0
    private var cutStartTime: CGFloat = 0

//    /// 裁剪结束最终的开始时间
//    private var cutFinishedStartTime: CGFloat {
//        (scrollView.contentOffset.x / perSecondWidth) + (((scrollView.frame.width - videoCropView.frame.width) / 2 + 15) / perSecondWidth) + cutStartTime
//    }
//
//    /// 裁剪结束最终的结束时间
//    private var cutFinishedEndTime: CGFloat {
//        cutFinishedStartTime + (cutEndTime - cutStartTime)
//    }

    // 播放进度
    private var videoProgress: CGFloat = 0

    // 最小时长 默认 10s
    private var minCutTime: CGFloat = 10
    /// 时间间隔
    private var timeRange: CGFloat = cDefaultMargin
    /// 刻度高
    private var rateHeight: CGFloat = 23
    /// 时间线宽
    private var timeLineWidth: CGFloat = 35
    /// 时间线间隔
    private var timeLineMargin: CGFloat = 35
    /// 时间线高
    private var timeHeight: CGFloat = cDefaultMargin * 4
    /// 频率线宽
    private var frequencyWidth: CGFloat = adapterWidth(width: 1.5)
    /// 频率间隔
    private var frequencyMargin: CGFloat = adapterWidth(width: 3)
    /// 竖线和contentview 父视图的左右间隔
    private var margin: CGFloat = (cScreenWidth - adapterWidth(width: 250)) / 2

    /// 滑动区域大小
    private var contentWidth: CGFloat = 0

    // 竖线一个间隔代表多少 S 是动态的
    private var oneMarginTime: CGFloat = 0

    private var isDrawLine: Bool = false

    // 保存已经绘制的竖线用于变色使用
    var lineLayerArray: Array = Array<CAShapeLayer>.init()
    var lastDrawedLineIndex: Int = 0

    // 裁剪区的相素大小
    var cropViewWidth: CGFloat = adapterWidth(width: 250)
    /// 拖拽改变实时的回调
    var videoRangeDidChanged: ((_ startTime: CGFloat, _ endTime: CGFloat) -> Void)?
    /// 进度改变实时的回调
    var videoProgressDidChanged: ((_ progress: CGFloat) -> Void)?
    /// 拖缀结束的回调 type - 1-拖动左边裁剪结束 2--拖动右边裁剪结束 3-进度条拖动结束 4-滑动结束
    var videoDidEndDragging: ((_ type: Int, _ startTime: CGFloat, _ endTime: CGFloat, _ progress: CGFloat) -> Void)?
    // 开始划动
    var videoDidBeginDrag: (() -> Void)?

    // 选择区内的线个数
    var wavSelectCount: Int = 0
    // 整首歌的线的个数
    var wavTotalCount: Int = 0

    // 推荐虚线的位置
    var startLineX: CGFloat = 0.0

    // 如果是用户主动划动的 就不自动滚动到推荐位置了
    var isUserDrag: Bool = false
    // 推荐卡点起始时间
    var suggestRhythmStartTime: CGFloat = 0.0
    var suggestRhythmEndTime: CGFloat = 0.0

    /// 滚动视图
    lazy var scrollView: UIScrollView = {
        let scrollView = UIScrollView(frame: bounds)
        scrollView.showsVerticalScrollIndicator = false
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.bounces = false
        scrollView.delegate = self
        if #available(iOS 11.0, *) {
            scrollView.contentInsetAdjustmentBehavior = .never
        } else {
//            automaticallyAdjustsScrollViewInsets = false
        }
        scrollView.backgroundColor = .clear
        return scrollView
    }()

    //
    lazy var rateView: UIView = {
        let rateView = UIView(frame: CGRect(x: 0, y: 22, width: scrollView.contentSize.width, height: rateHeight))
        rateView.backgroundColor = .clear
        return rateView
    }()

    // 总时长
    lazy var tatalTimeLabel: UILabel = {
        let tatalTimeLabel = UILabel()
        tatalTimeLabel.font = UIFont.systemFont(ofSize: 11)
        tatalTimeLabel.textAlignment = .right
        tatalTimeLabel.tag = 66
        tatalTimeLabel.textColor = UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue)
        return tatalTimeLabel
    }()

    // 显示选择框
    lazy var videoCropView: UIView = {
        let videoCropView: UIView = UIView(frame: CGRect(x: (cScreenWidth - cropViewWidth) / 2, y: 0, width: cropViewWidth, height: 80))
        videoCropView.isUserInteractionEnabled = false
        videoCropView.layer.borderColor = UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue).cgColor
        videoCropView.layer.borderWidth = 2
        videoCropView.layer.cornerRadius = 8

        return videoCropView
    }()

    // 两边的mask 2 是裁剪区的边框
    lazy var leftMaskView: UIView = {
        let leftMaskView: UIView = UIView(frame: CGRect(x: 0, y: 0, width: (cScreenWidth - cropViewWidth) / 2 - 2, height: 80))
        leftMaskView.backgroundColor = BFConfig.shared.styleBackGroundColor
        leftMaskView.alpha = 0.7
        return leftMaskView
    }()

    // 右边的mask 2 是裁剪区的边框
    lazy var rightMaskView: UIView = {
        let rightMaskView: UIView = UIView(frame: CGRect(x: videoCropView.frame.maxX + 2, y: 0, width: (cScreenWidth - cropViewWidth) / 2, height: 80))
        rightMaskView.backgroundColor = BFConfig.shared.styleBackGroundColor
        rightMaskView.alpha = 0.7
        return rightMaskView
    }()

    override private init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder _: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    init(frame: CGRect, duration: CGFloat, suggestRhythmStartTime: CGFloat) {
        super.init(frame: frame)
        videoDuration = duration
        self.suggestRhythmStartTime = suggestRhythmStartTime
    }

    /// 更新卡点值
    /// - Parameter endTime: endTime description
    /// - Returns: <#description#>
    func updateEndTime(startTime: CGFloat, endTime: CGFloat,
                       suggestRhythmStartTime: CGFloat, suggestRhythmEndTime: CGFloat)
    {
//        videoDuration = duration
        self.suggestRhythmStartTime = suggestRhythmStartTime
        self.suggestRhythmEndTime = suggestRhythmEndTime
        startLineX = 0

        stuckPointStartTime = startTime
        stuckPointEndTime = endTime

        tatalTimeLabel.text = "\(Float64(stuckPointEndTime - stuckPointStartTime).formatDurationToHMS())"

        BFLog(1, message: "播放开始:\(stuckPointStartTime) 结束:\(stuckPointEndTime) 时长为:\(stuckPointEndTime - stuckPointStartTime); 音乐总时长为:\(videoDuration);推荐卡点开始:\(suggestRhythmStartTime) 结束:\(suggestRhythmEndTime)")
        backgroundColor = BFConfig.shared.styleBackGroundColor
        addSubview(scrollView)

        addSubview(videoCropView)
        addSubview(leftMaskView)
        addSubview(rightMaskView)
        videoCropView.addSubview(tatalTimeLabel)
        addData()
        videoCropView.frame = CGRect(x: (cScreenWidth - cropViewWidth) / 2, y: 0, width: cropViewWidth, height: 80)
        leftMaskView.frame = CGRect(x: 0, y: 0, width: (cScreenWidth - cropViewWidth) / 2 - 2, height: 80)
        rightMaskView.frame = CGRect(x: videoCropView.frame.maxX + 2, y: 0, width: (cScreenWidth - cropViewWidth) / 2 - 2, height: 80)

        tatalTimeLabel.snp.remakeConstraints { make in
            make.width.equalTo(40)
            make.height.equalTo(15)
            make.top.equalTo(videoCropView.snp.top).offset(6)
            make.right.equalTo(videoCropView.snp.right).offset(-6)
        }
    }

    func addData() {
        // 1,选择区内的线个数 ,划动区域后 个数会变？？？
        wavSelectCount = Int(ceil((adapterWidth(width: 250) - frequencyWidth) / (frequencyWidth + frequencyMargin)) + 1)

        cropViewWidth = CGFloat(wavSelectCount) * (frequencyWidth + frequencyMargin) + frequencyWidth
        margin = (cScreenWidth - cropViewWidth) / 2.0

        // 2竖线一个间隔代表多少 S 是动态的
        oneMarginTime = (stuckPointEndTime - stuckPointStartTime) / CGFloat(wavSelectCount)

        // 如果视频结束时间点大于歌曲有效结束点，则拼接推荐的时间段直到满足视频播放
        var videoDurationTemp = suggestRhythmEndTime
        while stuckPointEndTime > videoDurationTemp {
            videoDurationTemp += (suggestRhythmEndTime - suggestRhythmStartTime)
        }
        videoDuration = videoDurationTemp
        // 3,一共绘制的竖线个数
        wavTotalCount = Int(ceil(videoDuration / oneMarginTime) + 1)

        timeRange = oneMarginTime * 10
        // 显示时间 label 的个数 , -1 不够整倍数就不显示时间了
        let timeLabelCount = Int(wavTotalCount / 10)

        contentWidth = CGFloat(wavTotalCount - 1) * (frequencyWidth + frequencyMargin) + frequencyWidth + (cScreenWidth - cropViewWidth)
        if contentWidth < scrollView.frame.width {
            contentWidth = scrollView.frame.width
        }
        scrollView.contentSize = CGSize(width: contentWidth, height: scrollView.frame.height)

        BFLog(1, message: "框内个数：\(wavSelectCount), 总线条数：\(wavTotalCount), 框宽:\(cropViewWidth), 最终音乐时长:\(videoDuration)")
        scrollView.subviews.forEach { lable in
            if lable is UILabel, lable.tag != 66 {
                lable.removeFromSuperview()
            }
        }
        for index in 0...timeLabelCount {
//            scrollView.viewWithTag(100 + index)?.removeFromSuperview()
            let titleLab = UILabel(frame: CGRect(x: CGFloat(index) * (frequencyWidth + frequencyMargin) * 10 + margin - timeLineWidth / 2, y: rateView.frame.maxY, width: timeLineWidth, height: 30))
            titleLab.font = UIFont.systemFont(ofSize: 11)
            titleLab.textAlignment = .center
            titleLab.numberOfLines = 1
            titleLab.tag = 100 + index
            titleLab.backgroundColor = .clear
            titleLab.textColor = UIColor.hexColor(hexadecimal: "#999999")

            titleLab.text = "\(Float64(Int(CGFloat(index) * timeRange)).formatDurationToHMS())"
            scrollView.addSubview(titleLab)
        }
        if oneMarginTime > 0 {
            // 1,处理音频频率
            configVoiceFrequency()
            // 2，滚动到推荐位置
            if !isUserDrag {
                scrollView.contentOffset = CGPoint(x: startLineX - margin, y: 0)
            }

            scrollView.addSubview(rateView)
        }
    }

    /// 处理音频频率
    /// - Returns: <#description#>
    func configVoiceFrequency() {
        // 整倍数
        let waveTotalCount = Int(wavTotalCount) / cFrequency.count
        // 余多少个未画的
        var remainder = Int(wavTotalCount % cFrequency.count)
        var totalWave: [CGFloat] = Array<CGFloat>.init()
//         1，先画整倍数个竖线
        for _ in 0..<waveTotalCount {
            totalWave = totalWave + cFrequency
        }
        if remainder > cFrequency.count - 1 {
            remainder = cFrequency.count - 1
        }
        // 1,再画余数个竖线
        if remainder > 0 {
            totalWave = totalWave + cFrequency[0...(remainder - 1)]
        }

        createWave(waveArr: totalWave)
    }

    /// 更新进度绘制不同色值
    /// progress <#progress description#>
    func updateProgress(progress: CGFloat) {
        if progress <= 0 || lineLayerArray.count == 0 || progress.isNaN {
            BFLog(message: "progress is error \(progress) lineLayerArray \(lineLayerArray)")
            return
        }

        let startIndex = scrollView.contentOffset.x / (frequencyWidth + frequencyMargin)
        lastDrawedLineIndex = max(lastDrawedLineIndex, Int(ceil(startIndex)))
        let selectIndex = Int(ceil(startIndex + progress * CGFloat(wavSelectCount)))
        while selectIndex < lineLayerArray.count, selectIndex > lastDrawedLineIndex {
            let drawLayer: CAShapeLayer = lineLayerArray[lastDrawedLineIndex]
            if drawLayer.strokeColor != UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue).cgColor {
//                BFLog(1, message: "progress is \(progress) i \(lastDrawedLineIndex) 命中的位置：\(CGFloat(lastDrawedLineIndex) * oneMarginTime)")
                drawLayer.strokeColor = UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue).cgColor
                drawLayer.setNeedsDisplay()
                drawLayer.layoutIfNeeded()
            }
            lastDrawedLineIndex += 1
        }

        if progress >= 0.999 {
            BFLog(message: "播放完成 重新更新 UI ")
            resetDefaultsColor(clearData: false)
        }
    }

    // 竖线恢复到原有色值
    func resetDefaultsColor(clearData: Bool = true) {
        lastDrawedLineIndex = 0
        for layer in lineLayerArray {
            layer.strokeColor = UIColor.hexColor(hexadecimal: "#999999").cgColor
            layer.setNeedsDisplay()
        }
        if clearData == true {
            lineLayerArray.removeAll()
            if rateView.layer.sublayers != nil {
                for (_, layer) in rateView.layer.sublayers!.enumerated() {
                    layer.removeFromSuperlayer()
                }
            }

            isUserDrag = false
            isDrawLine = false
        }
    }

    /// 生成波纹
    /// - Parameter waveArr: <#waveArr description#> // warning 有崩溃 _buffer    _ArrayBuffer<CoreGraphics.CGFloat>    wavearr为CoreGraph.CGFloat数组
    /// - Returns: <#description#>
    func createWave(waveArr: [CGFloat]) {
        for (i, power) in waveArr.enumerated() {
            // 画布高度
            let hight: CGFloat = rateView.frame.height
            // 开始 Y 值
            var startY: CGFloat = (hight - power) / 2.0
            if startY < 0 { startY = 0 }
            // 结束 Y 值
            var endY: CGFloat = startY + power
            if endY > CGFloat(hight) { endY = hight }
            // 线的路径
            let linePath = UIBezierPath()
            // 起点 timeLineWidth / 2 处理显示时间的 label中心为时间点
            let originX: CGFloat = CGFloat(Float(i) * Float(frequencyWidth + frequencyMargin)) + margin

            linePath.move(to: CGPoint(x: originX, y: startY))
            // 终点
            linePath.addLine(to: CGPoint(x: originX, y: endY))
            let lineLayer = CAShapeLayer()

            lineLayer.lineWidth = frequencyWidth
            lineLayer.strokeColor = UIColor.hexColor(hexadecimal: "#999999").cgColor
            lineLayer.path = linePath.cgPath
            lineLayer.fillColor = UIColor.black.cgColor

            // 推荐的开始起点是虚线 减0.0001因为精度问题
//            BFLog(1, message: "suggestRhythmStartTime is \(suggestRhythmStartTime)")
            if oneMarginTime * CGFloat(i) >= (suggestRhythmStartTime - 0.0001), !isDrawLine {
                isDrawLine = true
                linePath.move(to: CGPoint(x: originX, y: -10))
                // 终点
                linePath.addLine(to: CGPoint(x: originX, y: 30))
                lineLayer.path = linePath.cgPath
                lineLayer.lineDashPhase = 0
                lineLayer.lineDashPattern = [3, 3]
            }
            if startLineX == 0, oneMarginTime * CGFloat(i) >= stuckPointStartTime {
                startLineX = originX
            }

            lineLayerArray.append(lineLayer)
            rateView.layer.insertSublayer(lineLayer, at: 0)
        }
    }

    deinit {
        BFLog(message: "卡点裁剪-裁剪视图销毁")
    }

    // 划动结速后处理
    func moveEnd() {
        // 最后一个竖线VIEW
        let lastLine: UIView = scrollView.viewWithTag(100 + Int(videoDuration / timeRange) - 1) ?? UIView()
        // 移动后的开始时间
        let startTime = videoDuration / lastLine.frame.maxX * scrollView.contentOffset.x
//        let startTime =  videoDuration * (margin + scrollView.contentOffset.x) / scrollView.contentSize.width
        // 选中的时长
        let selectDuration: CGFloat = CGFloat(stuckPointEndTime - stuckPointStartTime)
        BFLog(message: "拖拽结束 - 回调\(scrollView.contentOffset)  \(scrollView.contentSize) 开始时间为：\(startTime) 结束时间为:\(startTime + selectDuration)")
        stuckPointStartTime = startTime
        stuckPointEndTime = stuckPointStartTime + selectDuration
        if videoDidEndDragging != nil {
            videoDidEndDragging!(1, startTime, startTime + CGFloat(stuckPointEndTime - stuckPointStartTime), 0)
        }
        resetDefaultsColor(clearData: false)
        BFEventTrackAdaptor.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_musicPeriodSelect, pageSource: .sp_shanyinApp_main, commonParams: commonParams())
    }
}

// MARK: - scrollView滑动代理

/// scrollView滑动代理
extension PQStuckPointCuttingView: UIScrollViewDelegate {
    func scrollViewDidScroll(_: UIScrollView) {}

    func scrollViewWillBeginDragging(_: UIScrollView) {
        isUserDrag = true
        if videoDidBeginDrag != nil {
            videoDidBeginDrag!()
        }
    }

    func scrollViewDidEndDecelerating(_: UIScrollView) {
        if !scrollView.isDragging, !scrollView.isDecelerating {
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) { [weak self] in
                self?.moveEnd()
            }
        }
    }

    func scrollViewDidEndDragging(_: UIScrollView, willDecelerate decelerate: Bool) {
        if !decelerate, !scrollView.isDragging, !scrollView.isDecelerating {
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) { [weak self] in
                self?.moveEnd()
            }
        }
    }

    func scrollViewDidEndScrollingAnimation(_: UIScrollView) {
        BFLog(message: "scrollViewDidEndScrollingAnimation")
    }
}
