"""SVG asset resolver — resolves svgAsset token values to DrawingML shapes.

Handles multiple source schemes:
- ``undraw:<slug>`` — fetch from unDraw catalog via :mod:`tokenmoulds.media.undraw`
- ``https://...`` / ``http://...`` — fetch SVG from URL
- local file path — read SVG from disk

All SVGs are converted to native DrawingML vector shapes via svg2ooxml,
with optional theme color mapping.
"""

from __future__ import annotations

import logging
from pathlib import Path

from tokenmoulds._compat import HAS_HTTPX, HAS_SVG2OOXML, httpx
from tokenmoulds.dtcg.types import SvgAssetValue, Token

logger = logging.getLogger(__name__)


class SvgResolutionError(RuntimeError):
    """Raised when an SVG asset cannot be resolved."""


def is_available() -> bool:
    """Check if SVG resolution is possible (svg2ooxml installed)."""
    return HAS_SVG2OOXML


def svg_asset_from_token(token: Token) -> SvgAssetValue | None:
    """Construct an SvgAssetValue from a token with svgAsset extensions.

    Returns None if the token is not an SVG asset.
    """
    ext = token.extensions
    if ext is None or not ext.svg_asset:
        return None
    if not isinstance(token.value, str):
        return None
    return SvgAssetValue(src=token.value, color_map=ext.svg_color_map or {})


def resolve_svg_asset(asset: SvgAssetValue) -> str:
    """Resolve an svgAsset token value to DrawingML shape XML.

    Args:
        asset: The parsed ``SvgAssetValue`` with ``src`` and ``color_map``.

    Returns:
        DrawingML shape XML string (one or more ``<p:sp>`` elements).

    Raises:
        SvgResolutionError: If dependencies are missing, fetch fails, or conversion fails.
    """
    if not HAS_SVG2OOXML:
        msg = "svg2ooxml is required for SVG asset resolution"
        raise SvgResolutionError(msg)

    svg_text = _fetch_svg(asset.src)
    return _convert_to_drawingml(svg_text, asset.color_map)


def _fetch_svg(src: str) -> str:
    """Fetch SVG content from the given source URI."""
    if src.startswith("undraw:"):
        return _fetch_undraw(src.removeprefix("undraw:"))
    if src.startswith(("https://", "http://")):
        return _fetch_url(src)
    return _read_file(src)


def _fetch_undraw(slug: str) -> str:
    """Fetch SVG from unDraw by slug."""
    if not HAS_HTTPX:
        msg = "httpx is required for fetching remote SVG assets"
        raise SvgResolutionError(msg)

    url = f"https://undraw.co/api/illustrations/{slug}"
    try:
        resp = httpx.get(url, timeout=15.0, follow_redirects=True)
        resp.raise_for_status()
    except Exception as exc:
        msg = f"Failed to fetch unDraw illustration '{slug}': {exc}"
        raise SvgResolutionError(msg) from exc
    return resp.text


def _fetch_url(url: str) -> str:
    """Fetch SVG from a URL."""
    if not HAS_HTTPX:
        msg = "httpx is required for fetching remote SVG assets"
        raise SvgResolutionError(msg)

    try:
        resp = httpx.get(url, timeout=15.0, follow_redirects=True)
        resp.raise_for_status()
    except Exception as exc:
        msg = f"Failed to fetch SVG from '{url}': {exc}"
        raise SvgResolutionError(msg) from exc
    return resp.text


def _read_file(path: str) -> str:
    """Read SVG from a local file."""
    p = Path(path)
    if not p.exists():
        msg = f"SVG file not found: {path}"
        raise SvgResolutionError(msg)
    return p.read_text()


def _convert_to_drawingml(svg_text: str, color_map: dict[str, str]) -> str:
    """Parse SVG → IR → inject theme colors → render DrawingML shapes."""
    try:
        from svg2ooxml.public import (
            DrawingMLWriter,
            ParserConfig,
            SVGParser,
            convert_parser_output,
        )
    except ImportError as exc:
        msg = "svg2ooxml is required for SVG-to-DrawingML conversion"
        raise SvgResolutionError(msg) from exc

    try:
        parser = SVGParser(ParserConfig())
        scene = convert_parser_output(parser.parse(svg_text))

        if color_map:
            from tokenmoulds.media.undraw import _inject_theme_colors

            _inject_theme_colors(scene.elements, color_map)

        shapes = DrawingMLWriter().render_shapes_from_ir(scene)
    except Exception as exc:
        msg = f"SVG-to-DrawingML conversion failed: {exc}"
        raise SvgResolutionError(msg) from exc

    return "\n".join(shapes)
