from django.core.exceptions import ValidationError
from lxml import etree

ALLOWED_SVG_TAGS: set[str] = {
    "svg",
    "g",
    "path",
    "rect",
    "circle",
    "ellipse",
    "line",
    "polyline",
    "polygon",
    "text",
    "tspan",
    "defs",
    "linearGradient",
    "radialGradient",
    "stop",
    "clipPath",
    "use",
    "title",
    "desc",
}

ALLOWED_SVG_ATTRIBUTES: set[str] = {
    "id",
    "class",
    "style",
    "d",
    "fill",
    "fill-rule",
    "stroke",
    "stroke-width",
    "stroke-linecap",
    "stroke-linejoin",
    "stroke-miterlimit",
    "stroke-dasharray",
    "stroke-dashoffset",
    "stroke-opacity",
    "transform",
    "x",
    "y",
    "cx",
    "cy",
    "r",
    "rx",
    "ry",
    "width",
    "height",
    "x1",
    "y1",
    "x2",
    "y2",
    "gradientTransform",
    "gradientUnits",
    "offset",
    "stop-color",
    "stop-opacity",
    "clip-path",
    "viewBox",
    "preserveAspectRatio",
    "href",
    "xlink:href",
    "font-family",
    "font-size",
    "font-weight",
    "text-anchor",
    "xmlns",
    "xmlns:xlink",
}


def reject_dangerous_svg(file):
    """
    Rejects SVG files that contain dangerous tags or attributes.
    Raises ValidationError if unsafe content is found.
    See GHSA-6p53-hqqw-8j62
    """
    try:
        parser = etree.XMLParser(resolve_entities=False)
        file.seek(0)
        tree = etree.parse(file, parser)
        root = tree.getroot()
    except etree.XMLSyntaxError:
        raise ValidationError("Invalid SVG file.")

    for element in root.iter():
        tag = etree.QName(element.tag).localname.lower()
        if tag not in ALLOWED_SVG_TAGS:
            raise ValidationError(f"Disallowed SVG tag: <{tag}>")

        for attr_name, attr_value in element.attrib.items():
            attr_name_lower = attr_name.lower()
            if attr_name_lower not in ALLOWED_SVG_ATTRIBUTES:
                raise ValidationError(f"Disallowed SVG attribute: {attr_name}")

            if attr_name_lower in {
                "href",
                "xlink:href",
            } and attr_value.strip().lower().startswith("javascript:"):
                raise ValidationError(f"Disallowed javascript: URI in {attr_name}")
