package com.jishisongfu.duobibi.ui.worth

import java.time.LocalDate
import java.time.temporal.ChronoUnit
import kotlin.math.PI
import kotlin.math.sin

/**
 * "值不值得买"页用的前端 mock —— 60 天价格走势 + 历史统计 + 大促倒计时。
 *
 * 全部确定性算法,不调任何后端。同 (title, typical, current) 永远同曲线/同结果,
 * 占审重放稳定;数据是"看起来合理"的拟真,不是真实历史价。
 */

/** 60 天历史价 + 当前价快照,用于历史统计 / 水位分位 / 走势图渲染。 */
internal data class HistoryStats(
    val min: Double,
    val max: Double,
    val avg: Double,
    val current: Double,
    /** 当前价在 [min, max] 区间的分位 0..100;0 = 在最低,100 = 在最高 */
    val percentile: Int,
)

/**
 * 生成 60 天价格序列(index 0 = 60 天前,index 59 = 今天)。
 *
 * 算法:
 *  - base = typical * (1 + 0.07 * sin(2π i/30))   30 天波浪
 *  - 周末额外 -2%(模拟"周末活动")
 *  - 每月 17/18/19 号 -10%(模拟 618/双11/月度大促节奏)
 *  - +/- 5% 哈希微抖(让曲线"毛糙",不至于一眼像数学函数)
 *  - 最后一天(today)强制用 [currentPrice],让曲线最右端贴合用户实际看到的价
 */
internal fun generate60dPrices(title: String, typical: Double, currentPrice: Double): List<Double> {
    val seed = title.hashCode()
    val raw = (0 until 60).map { i ->
        val wave = sin(2 * PI * i / 30.0) * 0.07
        val weekend = if (i % 7 in setOf(5, 6)) -0.02 else 0.0
        val promo = if (i % 30 in setOf(17, 18, 19)) -0.10 else 0.0
        val jitterByte = ((seed xor (i * 131)) and 0x7F).toDouble() / 127.0    // 0..1
        val jitter = (jitterByte - 0.5) * 0.06                                 // ±3%
        (typical * (1.0 + wave + weekend + promo + jitter)).coerceAtLeast(typical * 0.6)
    }.toMutableList()
    raw[raw.lastIndex] = currentPrice
    return raw
}

internal fun computeHistoryStats(prices: List<Double>, currentPrice: Double): HistoryStats {
    val min = prices.min()
    val max = prices.max()
    val avg = prices.average()
    val percentile = if (max - min < 0.01) 50
    else (((currentPrice - min) / (max - min)) * 100).toInt().coerceIn(0, 100)
    return HistoryStats(min, max, avg, currentPrice, percentile)
}

// ============== 大促日历 ==============

internal data class Promo(val name: String, val month: Int, val day: Int)

/** 6 个全年标志性大促节点。日期与电商行业惯例对齐。 */
internal val PROMO_CALENDAR: List<Promo> = listOf(
    Promo("年货节", 1, 15),
    Promo("女王节", 3, 8),
    Promo("618 大促", 6, 18),
    Promo("88 会员节", 8, 8),
    Promo("双 11", 11, 11),
    Promo("双 12", 12, 12),
)

internal data class NextPromo(val name: String, val daysAway: Int)

/** 距今天最近的未来大促节点(跨年的话排到明年同日)。 */
internal fun nextPromo(today: LocalDate = LocalDate.now()): NextPromo {
    val candidates = PROMO_CALENDAR.flatMap { p ->
        listOf(today.year, today.year + 1).map { y -> p.name to LocalDate.of(y, p.month, p.day) }
    }
    val pick = candidates
        .filter { (_, d) -> !d.isBefore(today) }
        .minBy { (_, d) -> d }
    val days = ChronoUnit.DAYS.between(today, pick.second).toInt()
    return NextPromo(pick.first, days)
}
