package me.khodak.claudeusage

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.util.AttributeSet
import android.view.View
import me.khodak.claudeusage.data.UsageSnapshot
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

/**
 * Lightweight line chart for usage history, hand-drawn on Canvas to stay dependency-free
 * and consistent with [BarRenderer]. Plots session (orange) and weekly (blue) utilization
 * 0-100% over time. Gaps longer than [GAP_MS] are not connected, so an offline stretch
 * shows as a break rather than a misleading straight line.
 */
class HistoryChartView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : View(context, attrs, defStyle) {

    private var points: List<UsageSnapshot> = emptyList()

    private val gridPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = 0xFF2A2A2A.toInt(); strokeWidth = dp(1f); style = Paint.Style.STROKE
    }
    private val labelPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = 0xFF666666.toInt(); textSize = sp(10f)
    }
    private val sessionPaint = linePaint(0xFFCC785C.toInt())
    private val weeklyPaint = linePaint(0xFF7B8FCC.toInt())
    private val emptyPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = 0xFF666666.toInt(); textSize = sp(13f); textAlign = Paint.Align.CENTER
    }

    private val padL = dp(28f)
    private val padR = dp(8f)
    private val padT = dp(10f)
    private val padB = dp(18f)

    fun setData(data: List<UsageSnapshot>) {
        points = data
        invalidate()
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val left = padL
        val top = padT
        val right = width - padR
        val bottom = height - padB
        if (right <= left || bottom <= top) return

        // Y gridlines + labels at 0 / 50 / 100%
        for (pct in intArrayOf(0, 50, 100)) {
            val y = bottom - (pct / 100f) * (bottom - top)
            canvas.drawLine(left, y, right, y, gridPaint)
            canvas.drawText("$pct", dp(4f), y + sp(3.5f), labelPaint)
        }

        val plottable = points.filter { it.sessionPct >= 0f || it.weeklyPct >= 0f }
        if (plottable.size < 2) {
            canvas.drawText(
                "Collecting history… check back later",
                (left + right) / 2f, (top + bottom) / 2f, emptyPaint
            )
            return
        }

        val tMin = plottable.first().epochMs
        val tMax = plottable.last().epochMs
        val tSpan = (tMax - tMin).coerceAtLeast(1L)

        fun x(ms: Long) = left + (ms - tMin).toFloat() / tSpan * (right - left)
        fun y(pct: Float) = bottom - (pct / 100f) * (bottom - top)

        drawSeries(canvas, plottable, sessionPaint, ::x, ::y) { it.sessionPct }
        drawSeries(canvas, plottable, weeklyPaint, ::x, ::y) { it.weeklyPct }

        // X axis time labels (start … end)
        val fmt = SimpleDateFormat("MMM d, h a", Locale.US)
        labelPaint.textAlign = Paint.Align.LEFT
        canvas.drawText(fmt.format(Date(tMin)), left, height - dp(4f), labelPaint)
        labelPaint.textAlign = Paint.Align.RIGHT
        canvas.drawText(fmt.format(Date(tMax)), right, height - dp(4f), labelPaint)
        labelPaint.textAlign = Paint.Align.LEFT
    }

    private inline fun drawSeries(
        canvas: Canvas,
        data: List<UsageSnapshot>,
        paint: Paint,
        x: (Long) -> Float,
        y: (Float) -> Float,
        value: (UsageSnapshot) -> Float
    ) {
        val path = Path()
        var penDown = false
        var prevMs = 0L
        for (p in data) {
            val v = value(p)
            if (v < 0f) { penDown = false; continue }
            val px = x(p.epochMs); val py = y(v)
            if (!penDown || p.epochMs - prevMs > GAP_MS) {
                path.moveTo(px, py)
            } else {
                path.lineTo(px, py)
            }
            penDown = true
            prevMs = p.epochMs
        }
        canvas.drawPath(path, paint)
    }

    private fun linePaint(c: Int) = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = c; strokeWidth = dp(2f); style = Paint.Style.STROKE
        strokeJoin = Paint.Join.ROUND; strokeCap = Paint.Cap.ROUND
    }

    private fun dp(v: Float) = v * resources.displayMetrics.density
    private fun sp(v: Float) = v * resources.displayMetrics.scaledDensity

    companion object {
        // Don't connect points separated by more than ~35 min (a missed refresh cycle or two).
        private const val GAP_MS = 35 * 60 * 1000L
    }
}
