"""DXF output generator — AC1015+ DXF from PostProcessResult using ezdxf."""

from __future__ import annotations

import io

import ezdxf

from pipeline.postprocess import PathInfo, PostProcessResult


def _add_path_to_msp(
    msp: ezdxf.layouts.BaseLayout,
    path: PathInfo,
    layer: str = "0",
) -> None:
    """Add a single PathInfo as an LWPOLYLINE entity to the modelspace.

    Closed paths get the LWPOLYLINE close flag set.
    Islands are placed on a separate "ISLANDS" layer for downstream CAM tools.
    """
    coords = path.simplified_coords
    if len(coords) < 2:
        return

    target_layer = "ISLANDS" if path.is_island else layer

    # LWPOLYLINE uses (x, y[, start_width, end_width, bulge]) tuples
    points = [(x, y) for x, y in coords]

    # Remove duplicate close point if the polyline close flag handles it
    if path.is_closed and len(points) > 1 and points[0] == points[-1]:
        points = points[:-1]

    msp.add_lwpolyline(
        points,
        dxfattribs={"layer": target_layer},
        close=path.is_closed,
    )


def generate_dxf(result: PostProcessResult) -> bytes:
    """Generate an AC1015 (AutoCAD R2000) DXF file from post-processed path data.

    Creates LWPOLYLINE entities from simplified coordinate data. Islands (holes)
    are placed on an "ISLANDS" layer; outer contours on the default "0" layer.

    Args:
        result: PostProcessResult from the post-processing pipeline.

    Returns:
        DXF file content as bytes.
    """
    doc = ezdxf.new(dxfversion="R2000")  # AC1015
    msp = doc.modelspace()

    # Create ISLANDS layer for hole/island paths
    doc.layers.add("ISLANDS", color=1)  # color 1 = red in AutoCAD

    for path in result.paths:
        _add_path_to_msp(msp, path)

    # Write to string buffer, then encode to bytes
    stream = io.StringIO()
    doc.write(stream)
    return stream.getvalue().encode("utf-8")
