#-----------------------------------------------------------------------------------------------------------------------
# Draw odometer from aligned 1:1 cells (right-to-left, lower-right anchor).
#-----------------------------------------------------------------------------------------------------------------------
from __future__ import annotations

from typing import List, Tuple

import pygame

from ohd_aligned_cells import (
    AlignedCellLibrary,
    TokenKind,
    aligned_anchor_from_layout,
    build_rtl_tokens,
    total_string_width,
)
from ohd_layout import COMMA_LEFT_POWER, OhdLayout
from odometer_engine import OdometerEngine, leftmost_significant_power


def draw_aligned_odometer(
    target: pygame.Surface,
    layout: OhdLayout,
    library: AlignedCellLibrary,
    engine: OdometerEngine,
    *,
    frame_x: int,
    frame_w: int,
) -> None:
    """Blit 1:1 odometer glyphs centered inside the frame, bottom-aligned to layout."""
    digits = engine.get_display_digits()
    leftmost = leftmost_significant_power(digits)
    tokens = build_rtl_tokens(
        digits, leftmost, show_comma=leftmost >= COMMA_LEFT_POWER
    )

    _, anchor_bottom = aligned_anchor_from_layout(layout)
    string_w = total_string_width(library, tokens)
    x_left = frame_x + max(0, (frame_w - string_w) // 2)
    x_right = x_left + string_w

    for rtl_i, (kind, digit) in enumerate(tokens):
        spec = library.spec_for(kind, digit)
        x = x_right - spec.w
        y = anchor_bottom - spec.h
        x_right = x

        if kind == "digit" and digit is not None:
            power = _digit_power_from_rtl_index(tokens, rtl_i)
            draw_digit, scroll = engine.get_column_draw(power)
            glyph = library.spec_for("digit", draw_digit)
            if scroll > 1e-6:
                _blit_scrolling_digit(
                    target,
                    x,
                    y,
                    glyph.w,
                    glyph.h,
                    library,
                    draw_digit,
                    scroll,
                )
                continue
            target.blit(glyph.surface, (x, y))
            continue

        target.blit(spec.surface, (x, y))


def _digit_power_from_rtl_index(
    tokens: List[Tuple[TokenKind, int | None]], rtl_index: int
) -> int:
    """RTL walk: first digit is power 0 (pennies), each digit to the left is +1 power."""
    power = 0
    for i in range(rtl_index):
        if tokens[i][0] == "digit":
            power += 1
    return power


def _blit_scrolling_digit(
    target: pygame.Surface,
    x: int,
    y: int,
    w: int,
    h: int,
    library: AlignedCellLibrary,
    digit: int,
    scroll: float,
) -> None:
    """Roll upward (value increasing): current digit rises, next digit enters from below."""
    g0 = library.digits[digit].surface
    g1 = library.digits[(digit + 1) % 10].surface
    step = max(g0.get_height(), g1.get_height(), h)
    offset_y = -int(round(scroll * step))

    clip = pygame.Rect(x, y, w, h)
    prev_clip = target.get_clip()
    target.set_clip(clip)
    try:
        target.blit(g0, (x, y + offset_y))
        target.blit(g1, (x, y + offset_y + step))
    finally:
        target.set_clip(prev_clip)
