"""Number line SVG generator for AGS Math instruments.

generate(start, end, interval, marked_points) -> str  (self-contained SVG)

  - Ink horizontal line with arrowheads at BOTH ends.
  - Gold tick markers at every `interval` with numeric labels below.
  - Crimson filled highlight dots at each value in `marked_points`.
  - Width auto-sizes to the number of ticks (range / interval).
"""

STYLE = (
    "<style>svg{--crimson:#960000;--gold:#BF9237;--lime:#88C808;"
    "--steel:#4A6488;--cream:#FAF5EE;--ink:#2A2A2A;--border:#D0ACAC;}</style>"
)


def _fmt(v):
    # integer-ish -> no decimal point
    if abs(v - round(v)) < 1e-9:
        return str(int(round(v)))
    return ('%g' % v)


def generate(start=0, end=10, interval=1, marked_points=None):
    if marked_points is None:
        marked_points = []
    start = float(start)
    end = float(end)
    interval = float(interval)

    n_ticks = int(round((end - start) / interval))
    span = n_ticks  # number of segments

    PAD = 50           # left/right padding for arrowheads + edge labels
    STEP_PX = 56       # pixels per interval
    line_w = span * STEP_PX
    width = line_w + 2 * PAD
    height = 120
    y = 55             # baseline y

    def xpos(value):
        return PAD + (value - start) / (end - start) * line_w

    parts = []
    parts.append(
        f'<svg xmlns="http://www.w3.org/2000/svg" width="{int(width)}" '
        f'height="{height}" viewBox="0 0 {int(width)} {height}">'
    )
    parts.append(STYLE)

    # Border frame
    parts.append(
        f'<rect x="3" y="3" width="{int(width)-6}" height="{height-6}" rx="14" '
        f'ry="14" fill="none" stroke="var(--border)" stroke-width="3"/>'
    )

    # Arrowhead marker defs (ink)
    parts.append(
        '<defs>'
        '<marker id="arrL" markerWidth="12" markerHeight="12" refX="6" refY="6" '
        'orient="auto"><path d="M11,1 L2,6 L11,11 Z" fill="var(--ink)"/></marker>'
        '<marker id="arrR" markerWidth="12" markerHeight="12" refX="6" refY="6" '
        'orient="auto"><path d="M1,1 L10,6 L1,11 Z" fill="var(--ink)"/></marker>'
        '</defs>'
    )

    # Main line with arrowheads both ends
    x_left = PAD - 20
    x_right = width - PAD + 20
    parts.append(
        f'<line x1="{x_left:.2f}" y1="{y}" x2="{x_right:.2f}" y2="{y}" '
        f'stroke="var(--ink)" stroke-width="3" '
        f'marker-start="url(#arrL)" marker-end="url(#arrR)"/>'
    )

    # Gold ticks + labels
    for i in range(n_ticks + 1):
        val = start + i * interval
        x = xpos(val)
        parts.append(
            f'<line x1="{x:.2f}" y1="{y-9}" x2="{x:.2f}" y2="{y+9}" '
            f'stroke="var(--gold)" stroke-width="3" stroke-linecap="round"/>'
        )
        parts.append(
            f'<text x="{x:.2f}" y="{y+28}" font-family="sans-serif" '
            f'font-size="14" fill="var(--ink)" text-anchor="middle">{_fmt(val)}</text>'
        )

    # Crimson highlight dots
    for mp in marked_points:
        mp = float(mp)
        x = xpos(mp)
        parts.append(
            f'<circle cx="{x:.2f}" cy="{y}" r="7" fill="var(--crimson)" '
            f'stroke="var(--cream)" stroke-width="1.5"/>'
        )

    parts.append('</svg>')
    return '\n'.join(parts)


if __name__ == '__main__':
    import os
    out = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'samples'))
    os.makedirs(out, exist_ok=True)
    samples = [
        dict(start=0, end=10, interval=1, marked_points=[3, 7]),
        dict(start=0, end=100, interval=10, marked_points=[40]),
        dict(start=-5, end=5, interval=1, marked_points=[0]),
    ]
    for i, kw in enumerate(samples, 1):
        p = os.path.join(out, f'number_line_{i}.svg')
        with open(p, 'w', encoding='utf-8') as f:
            f.write(generate(**kw))
        print('wrote', p)
