package wang.yaojia.webterm.terminalview

import kotlin.math.floor

/**
 * The cols×rows grid a terminal viewport resolves to for a given pixel size and font metric — the
 * pure, JVM-unit-testable half of the resize path (plan §6.4, risk R5: "cols×rows drift — Android
 * font metrics ≠ SwiftTerm"). Extracted as a free function so the arithmetic is verified against known
 * metrics WITHOUT a device: the real `mFontWidth` / `mFontLineSpacing` come from Termux's
 * `TerminalRenderer` at runtime (they need a real `android.graphics.Paint`), but the formula that turns
 * them into a grid must never drift from the server/web/iOS contract.
 *
 * ```
 * cols = max(1, floor((viewW - 2*hPad) / mFontWidth))
 * rows = max(1, floor((viewH - 2*vPad) / mFontLineSpacing))
 * ```
 *
 * Non-positive pre-layout dimensions (a view measured at 0×0 before its first layout pass) yield
 * `null` — the caller drops them and never sends a bogus `resize` (plan §6.4: "drop non-positive
 * pre-layout dims").
 */
public data class TerminalGridSize(val cols: Int, val rows: Int)

public object TerminalGridMath {

    /** The smallest usable grid — the server hardcodes 80×24 on attach; we never send below 1×1. */
    public const val MIN_DIMENSION: Int = 1

    /**
     * Resolve [viewWidthPx]×[viewHeightPx] (minus symmetric padding) into a terminal grid using the
     * cell metrics [fontWidthPx] (`TerminalRenderer.mFontWidth`, a float) and [fontLineSpacingPx]
     * (`TerminalRenderer.mFontLineSpacing`, an int).
     *
     * Returns `null` when any input is non-positive OR the usable area after padding is non-positive —
     * i.e. the view has not been laid out yet, so there is no valid grid to send.
     */
    public fun computeGridSize(
        viewWidthPx: Int,
        viewHeightPx: Int,
        horizontalPaddingPx: Int,
        verticalPaddingPx: Int,
        fontWidthPx: Float,
        fontLineSpacingPx: Int,
    ): TerminalGridSize? {
        // Fail fast on any pre-layout / degenerate metric — never emit a bogus resize.
        if (viewWidthPx <= 0 || viewHeightPx <= 0) return null
        if (fontWidthPx <= 0f || fontLineSpacingPx <= 0) return null

        val usableWidth = viewWidthPx - 2 * horizontalPaddingPx
        val usableHeight = viewHeightPx - 2 * verticalPaddingPx
        if (usableWidth <= 0 || usableHeight <= 0) return null

        val cols = floor(usableWidth / fontWidthPx).toInt().coerceAtLeast(MIN_DIMENSION)
        val rows = (usableHeight / fontLineSpacingPx).coerceAtLeast(MIN_DIMENSION)
        return TerminalGridSize(cols, rows)
    }
}
