"""
Convert a Program to SVG for browser display.
No tkinter dependency; used by the web UI.
"""
from __future__ import division


# Plotter units to mm (HP-GL typical: 1 unit = 0.025 mm)
UNITS_PER_MM = 40.0

# Space for X and Y rulers (labels in plotter units)
RULER_LEFT = 52
RULER_BOTTOM = 36
MARGIN_TOP = 16
MARGIN_RIGHT = 16


def program_to_svg(program, width=800, height=600, margin=20, show_scale_bar=True):
    """
    Render Program to SVG string. Fits content into width x height.
    Always draws X and Y rulers showing bounds (xmin, xmax, ymin, ymax) in plotter units.
    HPGL Y is flipped so it displays top-down in SVG.
    """
    if not program.commands:
        return _empty_svg(width, height)

    w, h = program.winsize
    if w == 0 or h == 0:
        return _empty_svg(width, height)

    xmin, ymin = program.xmin, program.ymin
    xmax, ymax = program.xmax, program.ymax
    vw = width - RULER_LEFT - MARGIN_RIGHT
    vh = height - MARGIN_TOP - RULER_BOTTOM
    scale = min(vw / w, vh / h)
    cx, cy = program.center
    ox = RULER_LEFT + vw / 2 - cx * scale
    oy = MARGIN_TOP + vh / 2 + cy * scale  # flip Y: HPGL y up -> SVG y down

    def tx(x):
        return x * scale + ox

    def ty(y):
        return -y * scale + oy

    path_segments = []
    circles = []
    x, y = None, None

    for cmd in program.commands:
        if cmd.name == 'PU':
            x, y = cmd.x, cmd.y
        elif cmd.name == 'PD':
            if x is not None and y is not None:
                path_segments.append('M {:.2f} {:.2f} L {:.2f} {:.2f}'.format(
                    tx(x), ty(y), tx(cmd.x), ty(cmd.y)))
            x, y = cmd.x, cmd.y
        elif cmd.name == 'CI' and cmd.args:
            r = abs(cmd.args[0]) * scale
            cx_svg = tx(x) if x is not None else (RULER_LEFT + vw / 2)
            cy_svg = ty(y) if y is not None else (MARGIN_TOP + vh / 2)
            circles.append(
                '<circle cx="{:.2f}" cy="{:.2f}" r="{:.2f}" fill="none" stroke="currentColor" stroke-width="1"/>'
                .format(cx_svg, cy_svg, r))

    parts = []
    if path_segments:
        path_d = ' '.join(path_segments)
        parts.append('<path d="{}" fill="none" stroke="currentColor" stroke-width="1"/>'.format(path_d))
    parts.extend(circles)

    # X and Y rulers showing bounds (always)
    parts.append(_rulers_svg(width, height, xmin, ymin, xmax, ymax, tx, ty))

    return (
        '<?xml version="1.0" encoding="UTF-8"?>\n'
        '<svg xmlns="http://www.w3.org/2000/svg" '
        'width="{w}" height="{h}" viewBox="0 0 {w} {h}">\n'
        '<g>\n{body}\n</g>\n</svg>'
    ).format(w=width, h=height, body='\n'.join(parts))


def _rulers_svg(width, height, xmin, ymin, xmax, ymax, tx, ty):
    """Draw X and Y rulers with bounds labels (plotter units)."""
    # X ruler: bottom, from xmin to xmax
    y_xruler = height - RULER_BOTTOM + 8
    x0_x = tx(xmin)
    x1_x = tx(xmax)
    tick_y0 = y_xruler
    tick_y1 = y_xruler + 6
    # Y ruler: left, from ymin (bottom in SVG) to ymax (top in SVG)
    x_yruler = RULER_LEFT - 24
    y0_y = ty(ymin)  # bottom of drawing in SVG
    y1_y = ty(ymax)  # top of drawing in SVG
    tick_x0 = x_yruler + 18
    tick_x1 = x_yruler + 24
    font = 'font-size="11" font-family="system-ui,sans-serif" fill="#374151"'
    return (
        '<g stroke="#6b7280" fill="#374151" stroke-width="1">'
        # X axis line and ticks
        '<line x1="{x0_x:.1f}" y1="{y_xruler:.1f}" x2="{x1_x:.1f}" y2="{y_xruler:.1f}"/>'
        '<line x1="{x0_x:.1f}" y1="{tick_y0:.1f}" x2="{x0_x:.1f}" y2="{tick_y1:.1f}"/>'
        '<line x1="{x1_x:.1f}" y1="{tick_y0:.1f}" x2="{x1_x:.1f}" y2="{tick_y1:.1f}"/>'
        '<text x="{x0_x:.1f}" y="{label_y:.1f}" text-anchor="middle" {font}>{xmin:.0f}</text>'
        '<text x="{x1_x:.1f}" y="{label_y:.1f}" text-anchor="middle" {font}>{xmax:.0f}</text>'
        # Y axis line and ticks
        '<line x1="{x_yruler:.1f}" y1="{y0_y:.1f}" x2="{x_yruler:.1f}" y2="{y1_y:.1f}"/>'
        '<line x1="{tick_x0:.1f}" y1="{y0_y:.1f}" x2="{tick_x1:.1f}" y2="{y0_y:.1f}"/>'
        '<line x1="{tick_x0:.1f}" y1="{y1_y:.1f}" x2="{tick_x1:.1f}" y2="{y1_y:.1f}"/>'
        '<text x="{y_label_x:.1f}" y="{y0_y:.1f}" text-anchor="end" dominant-baseline="middle" {font}>{ymin:.0f}</text>'
        '<text x="{y_label_x:.1f}" y="{y1_y:.1f}" text-anchor="end" dominant-baseline="middle" {font}>{ymax:.0f}</text>'
        '</g>'
    ).format(
        x0_x=x0_x, x1_x=x1_x, y_xruler=y_xruler, tick_y0=tick_y0, tick_y1=tick_y1,
        label_y=y_xruler + 20, xmin=xmin, xmax=xmax,
        x_yruler=x_yruler, y0_y=y0_y, y1_y=y1_y, tick_x0=tick_x0, tick_x1=tick_x1,
        y_label_x=x_yruler + 14, ymin=ymin, ymax=ymax,
        font=font
    )


def _empty_svg(width, height):
    return (
        '<?xml version="1.0" encoding="UTF-8"?>\n'
        '<svg xmlns="http://www.w3.org/2000/svg" width="{w}" height="{h}" viewBox="0 0 {w} {h}">\n'
        '<text x="{x}" y="{y}" fill="#999">No content</text>\n</svg>'
    ).format(w=width, h=height, x=width // 2 - 30, y=height // 2)
