/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
 */
package smartrefresh.toprefresh

internal import ohos.resource_manager.*
import ohos.state_macro_manage.*
import std.math.*
import std.time.*
import std.sync.*
import smartrefresh.utils.*
internal import ohos.hilog.*
import ohos.prompt_action.PromptAction

/**
 * Created on 2024/8/27
 */
@Component
public class Classics {
    @Link
    var model: SmartRefreshModel
    @State
    var classicsSimple: ClassicsSimpleModel = ClassicsSimpleModel().initData()
    @State
    var refresh: Bool = false
    @State
    var refreshState: Bool = false

    var information: String = ""
    var arrowDown: String = "M 0 0 L0 1"
    var arrowUp: String = "M 25 100  L25 -20 L0 15 L25 -20 L50 15 L25 -20"
    var pullRefreshImage: AppResource = @r(app.media.classicsRefreshing)

    @State
    var pullRefreshImageAngle: Float32 = 0.0

    var screenWidth: Int32 = getDefaultDisplaySync().width
    // 动画刷新速率,30ms刷新一次
    var timerRefreshRate: Duration = 30 * Duration.millisecond
    // 记录结束动画持续时长
    var endAnimationTime: Duration = 0 * Duration.millisecond
    // 是否可以刷新,已经在刷新中为false,可以刷新为true
    var refreshCanStart: Bool = true

    protected override func aboutToAppear() {
        this.model.setRefreshHeaderCallback({
            => draw()
        })
        if (model.initRefreshing) {
            model.refreshHeaderCallback()
            model.initRefreshing = false
        }
    }

    protected override func aboutToDisappear(): Unit {
        if (model.headerRefreshId.isSome()) {
            model.headerRefreshId.getOrThrow().cancel()
            model.headerRefreshId = Option<Timer>.None
        }
    }

    func calculationArrowSize(): Unit {
        let arrowDownHeight = 20 + model.drawableArrowSize
        let arrowDownBottomPointCoordinate = "L25 ${arrowDownHeight.toString()}"
        let arrowDownLeftPointCoordinate = "L0 ${(arrowDownHeight - 35).toString()}"
        let arrowDownRightPointCoordinate = "L50 ${(arrowDownHeight - 35).toString()}"
        arrowDown = "M 25 20 ${arrowDownBottomPointCoordinate} ${arrowDownLeftPointCoordinate} ${arrowDownBottomPointCoordinate} ${arrowDownRightPointCoordinate} ${arrowDownBottomPointCoordinate}"
        let arrowUpHeight = 20 + model.drawableArrowSize
        let arrowUpBottomPointCoordinate = "M25 ${arrowUpHeight.toString()}"
        arrowUp = "${arrowUpBottomPointCoordinate} L25 20 L0 55 L25 20 L50 55 L25 20"
    }

    func draw(): Unit { //刷新样式
        calculateTime()
        if (model.getDrawableArrow()) { // 计算箭头的长度
            calculationArrowSize()
        }
        endAnimationTime = 0 * Duration.millisecond
        if (model.getDrawableProgress()) {
            refreshingImage()
        } else {
//            model.headerRefreshId = Timer.repeatDuring(model.refreshDuration,  0 * Duration.millisecond, 20 * Duration.millisecond, {=> onDraw()
//            }, style: CatchupStyle.Burst)
            refreshingPath()
        }
    }

    func refreshingImage(): Unit {
        // 触发主界面数据刷新,控制只触发一次
        if (model.refreshState == 2 && refreshCanStart) {
            refreshCanStart = false
            model.refreshHeaderStart()
        }
        model.headerRefreshId = Timer.once(timerRefreshRate) {
            =>
                if (model.refreshState == 3) { // 刷新完成后
                    refreshCanStart = true
                    // 更新持续时间
                    endAnimationTime += timerRefreshRate
                    // 判断持续时间是否超过设置
                    if (endAnimationTime >= model.getRefreshFinishStopDuration()) {
                    	// 超过就通知主界面结束刷新
                        endAnimationTime = 0 * Duration.millisecond
                        model.refreshHeaderComplete()
                    } else {
                        refreshingImage() // 继续调用自己,保持刷新
                    }
                } else { // 刷新中,调用自己
                    if (model.refreshState == 2) {
                        if (pullRefreshImageAngle > 360.0) {
                            pullRefreshImageAngle = pullRefreshImageAngle - 360.0
                        }
                        pullRefreshImageAngle = pullRefreshImageAngle + 10.0
                    }
                    refreshingImage()
                }
        }
    }

    func refreshingPath(): Unit {
        // 触发主界面数据刷新,控制只触发一次
        if (model.refreshState == 2 && refreshCanStart) {
            refreshCanStart = false
            model.refreshHeaderStart()
        }
        model.headerRefreshId = Timer.once(timerRefreshRate) {
            =>
                if (model.refreshState == 3) { // 刷新完成后
                    refreshCanStart = true
                    // 更新持续时间
                    endAnimationTime += timerRefreshRate
                    // 判断持续时间是否超过设置
                    if (endAnimationTime >= model.getRefreshFinishStopDuration()) {
                    	// 超过就通知主界面结束刷新
                        endAnimationTime = 0 * Duration.millisecond
                        model.refreshHeaderComplete()
                    } else {
                        onDraw() // 继续调用自己,保持刷新
                    }
                } else { // 刷新中,调用自己
                    onDraw()
                }
        }
    }

    func calculateTime(): Unit {
        let index = 0
        information = ""
        let month = model.lastRefreshTime.month
        let day: Int64 = model.lastRefreshTime.dayOfMonth
        let hour: Int64 = model.lastRefreshTime.hour
        let minute: Int64 = model.lastRefreshTime.minute
        information = "${month}月${day}日 ${hour}:${minute}"
    }

    func onDraw(): Unit {
        if (classicsSimple.isSpinning) {
            if ((classicsSimple.barExtraLength + classicsSimple.minAngle) < 180.0) {
                classicsSimple.angleFlag = 0.0
            } else {
                classicsSimple.angleFlag = 1.0
            }
            // 增量时间
            let deltaTime = DateTime.now().toUnixTimeStamp().toNanoseconds() - classicsSimple.lastTimeAnimated
            let deltaNormalized = Float64(deltaTime) * classicsSimple.spinSpeed / 1000000000.0
            classicsSimple.mInitprogress += deltaNormalized
            if (classicsSimple.mInitprogress > 360.0) {
                classicsSimple.mInitprogress -= 360.0
            }
            let radian = classicsSimple.mInitprogress * Float64.PI / 180.0
            classicsSimple.startX = classicsSimple.circleRadius + (classicsSimple.radius * sin(radian))
            classicsSimple.startY = classicsSimple.circleRadius - (classicsSimple.radius * cos(radian))
            // 计算需要额外绘制的角度
            updateBarLength(deltaTime)
            classicsSimple.lastTimeAnimated = DateTime.now().toUnixTimeStamp().toNanoseconds()
            // 计算坐标
            calculation()
            classicsSimple.targetAngle = classicsSimple.mInitprogress + classicsSimple.barExtraLength + classicsSimple.
                minAngle
            if (classicsSimple.targetAngle > 360.0) {
                classicsSimple.targetAngle -= 360.0
            }
            classicsSimple.svgPath = "M ${classicsSimple.startX} ${classicsSimple.startY} A ${classicsSimple.radius} ${classicsSimple.radius}, 0, ${classicsSimple.angleFlag}, ${classicsSimple.directionFlag}, ${classicsSimple.endX} ${classicsSimple.endY}"
            classicsSimple.mProgress = "Progress:"
            refreshingPath()
        }
    }

    func updateBarLength(deltaTimeInMilliSeconds: Int64): Unit {
        // 到达最大小最小角的保持时间
        if (classicsSimple.pausedTimeWithoutGrowing >= classicsSimple.pauseGrowingTime) {
            classicsSimple.timeStartGrowing += deltaTimeInMilliSeconds
            // 计算递增递减
            if (classicsSimple.timeStartGrowing > classicsSimple.barSpinCycleTime) {
                classicsSimple.timeStartGrowing -= classicsSimple.barSpinCycleTime
                classicsSimple.pausedTimeWithoutGrowing = 0
                // 递增递减切换
                classicsSimple.barGrowingFromFront = !classicsSimple.barGrowingFromFront
            }
            let distance = cos(Float64(classicsSimple.timeStartGrowing / classicsSimple.barSpinCycleTime + 1) * Float64.PI) /
                2.0 + 0.5
            // 目标角度
            let destLength = (classicsSimple.maxAngle - classicsSimple.minAngle)
            if (classicsSimple.barGrowingFromFront) {
                // 递增
                classicsSimple.barExtraLength = distance * destLength
            } else {
                //递减
                let newLength = destLength * (1.0 - distance)
                classicsSimple.mInitprogress += (classicsSimple.barExtraLength - newLength)
                classicsSimple.barExtraLength = newLength
            }
        } else {
            classicsSimple.pausedTimeWithoutGrowing += deltaTimeInMilliSeconds
        }
    }

    func calculation(): Unit {
        // 计算弧度
        let radian = classicsSimple.targetAngle * Float64.PI / 180.0
        classicsSimple.endX = classicsSimple.circleRadius + (classicsSimple.radius * sin(radian))
        classicsSimple.endY = classicsSimple.circleRadius - (classicsSimple.radius * cos(radian))
        // 控制起点终点无限接近时正常画圆
        if ((classicsSimple.circleRadius - 1.0) < classicsSimple.endX && classicsSimple.endX < classicsSimple.
            circleRadius && (classicsSimple.circleRadius - classicsSimple.endX) < 0.01) {
            classicsSimple.endX = classicsSimple.circleRadius - 0.01
        }
    }

    func calculateTopPosition(): Float64 {
        if (model.classicsSpinnerStyle == SpinnerStyleEnum.TRANSLATE) {
            return model.headerHeight - model.textTimeMarginTop
        }
        if (this.model.classicsSpinnerStyle == SpinnerStyleEnum.SCALE) {
            return (model.headerHeight - 150.0) / 2.0
        }
        if (this.model.classicsSpinnerStyle == SpinnerStyleEnum.FIXED_BEHIND) {
            return model.textTimeMarginTop
        }
        return (model.headerHeight - 150.0) / 2.0
    }

    func build() {
        Flex() {
            if (model.refreshState == 2) { //松开过后的刷新样式
                Stack(Alignment.Start) {
                    if (model.getDrawableProgress()) {
                        Row() {
                            Image(pullRefreshImage).width(testLog(model.drawableProgressSize, model)).height(
                                model.drawableProgressSize).rotate(
                                x: 0.0,
                                y: 0.0,
                                z: 1.0,
                                centerX: 50.percent,
                                centerY: 50.percent,
                                angle: pullRefreshImageAngle
                            )
                        }.margin(left: 100)
                    } else {
                        Path() //圆的轨道
                            .commands(classicsSimple.svgPath).strokeWidth(classicsSimple.barWidth).fillOpacity(0).
                            width(100).height(200).stroke(model.getAccentColor()).margin(left: 50.0,
                            top: 50.0 + calculateTopPosition())
                    }

                    Column() {
                        Row() {
                            Text(model.refreshHeaderRefreshing).fontSize(30).height(50).margin(
                                top: calculateTopPosition(), left: model.drawableMarginRight).fontColor(
                                model.getAccentColor()).maxLines(2).textOverflow(TextOverflow.Ellipsis)
                        }
                        if (model.getTimeShowState()) {
                            Row() {
                                Text("更新于${information}").fontSize(model.textSizeTime).align(Alignment.Center).height(
                                    50).margin(top: calculateTopPosition(), left: model.drawableMarginRight).fontColor(
                                    model.getAccentColor()).maxLines(2).textOverflow(TextOverflow.Ellipsis)
                            }.width(100.percent)
                        }
                    }.width(70.percent).alignItems(HorizontalAlign.Center).margin(left: 80.0,
                        top: (this.model.headerHeight - 150.0) / 2.0)
                }.width(100.percent).height(100.percent)
            } else if (model.refreshState == 1) { //拖住过程中的样式
                if (model.headerHeight > (model.initHeaderHeight / 2.0)) {
                    Stack(Alignment.Start) {
                        Path().commands(if (model.headerHeight < model.initHeaderHeight) {
                            arrowDown
                        } else {
                            arrowUp
                        }).strokeWidth(classicsSimple.barWidth).fillOpacity(0).stroke(model.getAccentColor()).margin(
                            left: 80.0, top: calculateTopPosition()).visibility(
                                if (model.getDrawableArrow()) {
                                    Visibility.Visible
                                } else {
                                    Visibility.None
                                })
                        Column() {
                            Row() {
                                Text(
                                    if (model.headerHeight < model.initHeaderHeight) {
                                    model.refreshHeaderPullDown
                                } else {
                                    model.refreshHeaderRelease
                                }).fontSize(model.textSizeTitle).height(50).fontColor(model.getAccentColor()).margin(
                                    top: calculateTopPosition(), left: model.drawableMarginRight).maxLines(2).
                                    textOverflow(TextOverflow.Ellipsis)
                            }
                            if (model.getTimeShowState()) {
                                Row() {
                                    Text("更新于${information}").fontSize(model.textSizeTime).fontColor(
                                        model.getAccentColor()).height(50).margin(top: calculateTopPosition(),
                                        left: model.drawableMarginRight).maxLines(2).textOverflow(TextOverflow.Ellipsis)
                                }
                            }
                        }.width(70.percent).alignItems(HorizontalAlign.Center).margin(left: 80.0,
                            top: (model.headerHeight - 150.0) / 2.0)
                    }.width(100.percent).height(100.percent)
                }
            } else if (model.refreshState == 3) {
                Row() {
                    Text(model.refreshHeaderRefreshFinish).fontSize(40).fontColor(model.getAccentColor()).margin(
                        top: 60.0, left: px2vp(Int64(screenWidth / 3).px).getOrThrow().value).maxLines(2).textOverflow(
                        TextOverflow.Ellipsis)
                }.alignItems(VerticalAlign.Center)
            }
        }.backgroundColor(model.getBackgroundShadowColor()).width(100.percent)
    }
}


func testLog(msg: String): String {
    Hilog.info(0x0000, "classicsTag", "msg:${msg}")
    return msg
}

func testLog(msg: Int64, mode: SmartRefreshModel): Int64 {
    Hilog.info(0x0000, "classicsTag", "msg:${msg}")

    //Hilog.info(0x0000, "classicsTag", "SmartRefreshModel:${mode.refreshState}")
    return msg
}

@Observed
public class ClassicsSimpleModel {
    //画笔宽度
    @Publish
    var barWidth: Float64 = 5.0
    //轮圈宽度
    @Publish
    var rimWidth: Float64 = 5.0
    //画笔颜色
    @Publish
    var barColor: Color = Color(0X5588FF)
    // 大/小角度弧标志  0为小角度
    @Publish
    var angleFlag: Float64 = 0.0
    // 圆弧最小角度
    @Publish
    var minAngle: Float64 = 16.0
    // 圆弧最大角度
    @Publish
    var maxAngle: Float64 = 270.0
    //半径
    @Publish
    var circleRadius: Float64 = 60.0
    //真实半径
    @Publish
    var radius: Float64 = 55.0
    // 在 minAngle 基础上,额外需要绘制的角度
    @Publish
    var barExtraLength: Float64 = 0.0
    // 需要绘制到的角度
    @Publish
    var targetAngle: Float64 = 0.0
    // 圆弧递增或递减的标记  true表示递增
    @Publish
    var barGrowingFromFront: Bool = true
    // 逆时针顺时针标志 1表示顺时针
    @Publish
    var directionFlag: UInt8 = 1
    // svg路径
    @Publish
    var svgPath: String = ""
    // 绘制终点的X轴坐标
    @Publish
    var endX: Float64 = 0.0
    //绘制终点的Y轴坐标
    @Publish
    var endY: Float64 = 0.0
    //起始位置
    @Publish
    var startX: Float64 = 60.0
    @Publish
    var startY: Float64 = 5.0
    // 目标进度值
    @Publish
    var mTargetProgress: Float64 = 1.0
    // 进度值
    @Publish
    var mProgress: String = "0"
    // 起始角度
    @Publish
    var mInitprogress: Float64 = 0.0
    //轮圈颜色
    @Publish
    var rimColor: Color = Color.WHITE
    // 近似闭合的坐标
    @Publish
    var closureY: Float64 = 0.0
    // 每1ms的旋转角度,例:230 每1s旋转 230 度    (270-16)/0.46 = 230
    @Publish
    var spinSpeed: Float64 = 230.0
    //轮圈的svg路径
    @Publish
    var rimSvgPath: String = ""
    // 是否是动态进度轮
    @Publish
    var isSpinning: Bool = true
    // 是否是线性进度轮
    @Publish
    var linearProgress: Bool = false
    //圆弧处在最大或者最小角度时,保持当时状态的时间,简而言之,当圆弧为的角度为 barLength
    //圆弧处在最大或者最小角度时,保持当时状态的时间,简而言之,当圆弧为的角度为 barLength
    // 或者 barMaxLength 时,都会在 pauseGrowingTime 这个时间后才会继续变化,最大向最小变化,最小向最大变化,可以理解为 delayTime
    @Publish
    var pauseGrowingTime: Int64 = 200
    // 圆弧 递增/递减 已经经历时间
    @Publish
    var timeStartGrowing: Int64 = 0
    //圆弧 从最小到最大/从最大到最小 的总时间
    @Publish
    var barSpinCycleTime: Int64 = 460
    // 圆弧在 最大/最小 角度保持的时间
    @Publish
    var pausedTimeWithoutGrowing: Int64 = 0
    //上一次绘制的时间
    @Publish
    var lastTimeAnimated: Int64 = DateTime.now().toUnixTimeStamp().toNanoseconds()
    // 定时器
    var interval: ?Timer = Option<Timer>.None

    func initData(): ClassicsSimpleModel {
        radius = circleRadius - barWidth
        startX = circleRadius
        startY = barWidth
        // 近似一个完整的回环(轮圈)
        let closureRadian = 359.99 * Float64.PI / 180.0
        // 近似闭合的坐标
        let closureX = circleRadius + (radius * sin(closureRadian))
        closureY = circleRadius - (radius * cos(closureRadian))
        rimSvgPath = "M${startX} ${startY} A ${radius} ${radius}, 0, 1, ${directionFlag}, ${closureX} ${closureY}Z"
        // 计算弧度
        if (isSpinning) {
            let radian = minAngle * Float64.PI / 180.0
            endX = circleRadius + (radius * sin(radian))
            endY = circleRadius - (radius * cos(radian))
            svgPath = "M${startX} ${startY} A ${radius} ${radius}, 0, ${angleFlag}, ${directionFlag}, ${endX} ${endY}"
        } else {
            if (mTargetProgress == 1.0) {
                maxAngle = 359.99
            } else {
                maxAngle = mTargetProgress * 360.0
            }
        }
        if (!interval.isNone()) {
            interval.getOrThrow().cancel()
        }
        return this
    }

    func setCircleRadius(circleRadius: Float64): ClassicsSimpleModel {
        this.circleRadius = circleRadius
        return this
    }

    func getCircleRadius(): Float64 {
        return circleRadius
    }

    func setBarColor(barColor: Color): ClassicsSimpleModel {
        this.barColor = barColor
        return this
    }

    func getBarColor(): Color {
        return barColor
    }

    func setRimColor(rimColor: Color): ClassicsSimpleModel {
        this.rimColor = rimColor
        return this
    }

    func getRimColor(): Color {
        return rimColor
    }

    func setRimWidth(rimWidth: Float64): ClassicsSimpleModel {
        this.rimWidth = rimWidth
        return this
    }

    func getRimWidth(): Float64 {
        return this.rimWidth
    }

    func setBarWidth(barWidth: Float64): ClassicsSimpleModel {
        this.barWidth = barWidth
        return this
    }

    func getBarWidth(): Float64 {
        return barWidth
    }

    func setProgress(targetProgress: Float64): ClassicsSimpleModel {
        if (isSpinning) {
            mInitprogress = 0.0
            isSpinning = false
        }
        if (targetProgress > 1.0) {
            mTargetProgress = 1.0
        } else if (targetProgress < 0.0) {
            mTargetProgress = 0.0
        }
        this.mTargetProgress = targetProgress
        return this
    }
    // 获取当前的进度值
    func getProgress(): String {
        return mProgress
    }

    func setSpinning(isSpinning: Bool): ClassicsSimpleModel {
        this.isSpinning = isSpinning
        return this
    }

    func setLinearProgress(linearProgress: Bool): ClassicsSimpleModel {
        this.linearProgress = linearProgress
        return this
    }

    func setSpinSpeed(spinSpeed: Float64): ClassicsSimpleModel {
        this.spinSpeed = spinSpeed
        return this
    }

    func getSpinSpeed(): Float64 {
        return spinSpeed
    }

    // Reset the count (in increment mode)
    func resetCount(): Unit {
        mInitprogress = 0.0
        mTargetProgress = 0.0
    }

    func stopSpinning(): Unit {
        isSpinning = false
        mInitprogress = 0.0
        mTargetProgress = 0.0
    }

    // Puts the view on spin mode
    func spin(): Unit {
        lastTimeAnimated = DateTime.now().toUnixTimeStamp().toNanoseconds()
        isSpinning = true
    }

    // 将进度设置为特定值,栏将立即设置为该值 @param progress 0 和 1 之间的进度
    func setInstantProgress(progress: Float64): Unit {
        if (isSpinning) {
            mInitprogress = 0.0
            isSpinning = false
        }
        var temp = progress
        if (progress > 1.0) {
            temp = progress - 1.0
        } else if (progress < 0.0) {
            temp = 0.0
        }
        if (temp == mTargetProgress) {
            return
        }
        mTargetProgress = min(temp * 360.0, 360.0)
        mInitprogress = mTargetProgress
        lastTimeAnimated = DateTime.now().toUnixTimeStamp().toNanoseconds()
    }

    func spinning(): Bool {
        return isSpinning
    }
}