import base64
import pathlib
import subprocess
import tempfile
import os
import shutil
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import uvicorn


app = FastAPI()

@app.get("/health")
def health():
    return {"status": "ok"}


# Template for multiline solution (text + formulas)
TEX_TEMPLATE = r"""
\documentclass[preview,border=6pt]{standalone}
\usepackage{amsmath,amssymb,mathtools}
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\begin{document}
\begin{minipage}{0.92\linewidth}
%s
\end{minipage}
\end{document}
"""


class RenderReq(BaseModel):
    body_latex: str
    fmt: str = "svg"      # svg | png
    density: int = 300    # for png


def run(cmd: list[str], cwd: str, timeout: int) -> None:
    try:
        subprocess.run(
            cmd,
            cwd=cwd,
            check=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            timeout=timeout,
        )
    except subprocess.TimeoutExpired:
        raise HTTPException(408, "Render timeout")
    except subprocess.CalledProcessError as e:
        stderr = e.stderr.decode(errors="ignore") if e.stderr else ""
        raise HTTPException(400, f"LaTeX error: {stderr[:1200]}")


def _imagemagick_convert_cmd() -> list[str]:
    """Choose ImageMagick convert command cross-platform."""
    # Comments in English by request
    # Prefer "magick convert" on Windows (ImageMagick 7), fallback to "convert" elsewhere.
    magick = shutil.which("magick")
    convert = shutil.which("convert")
    if os.name == "nt":
        if magick:
            return [magick, "convert"]
        if convert:
            # Warning: might resolve to Windows system32 convert.exe (not ImageMagick)
            return [convert]
        raise HTTPException(500, "ImageMagick not found. Install ImageMagick 7 and ensure 'magick' is in PATH.")
    # Non-Windows: "convert" is typically ImageMagick
    if convert:
        return [convert]
    if magick:
        return [magick, "convert"]
    raise HTTPException(500, "ImageMagick not found. Install imagemagick to enable PNG rendering.")


def _ghostscript_available() -> bool:
    """Check Ghostscript availability for dvisvgm PDF processing."""
    # Comments in English by request
    if os.name == "nt":
        return shutil.which("gswin64c") is not None or shutil.which("gswin32c") is not None
    return shutil.which("gs") is not None


@app.post("/render")
def render(req: RenderReq):
    if len(req.body_latex.encode("utf-8")) > 20_000:
        raise HTTPException(413, "Input too large")

    with tempfile.TemporaryDirectory() as td:
        tex = TEX_TEMPLATE % req.body_latex
        (pathlib.Path(td) / "doc.tex").write_text(tex, encoding="utf-8")

        # Compile to PDF
        run(["pdflatex", "-interaction=nonstopmode", "-halt-on-error", "doc.tex"], cwd=td, timeout=120)

        if req.fmt == "svg":
            # Convert PDF to SVG
            if not _ghostscript_available():
                raise HTTPException(400, "Ghostscript is not installed or not in PATH (gswin64c/gs required).")
            # Use explicit --pdf flag for broader compatibility
            run(["dvisvgm", "--pdf", "doc.pdf", "-n", "-a", "-o", "doc.svg"], cwd=td, timeout=60)
            data = (pathlib.Path(td) / "doc.svg").read_bytes()
            return {"content_type": "image/svg+xml", "b64": base64.b64encode(data).decode()}
        elif req.fmt == "png":
            # Convert PDF to PNG
            convert_cmd = _imagemagick_convert_cmd()
            run(convert_cmd + ["-density", str(req.density), "doc.pdf", "-units", "PixelsPerInch", "-trim", "+repage", "doc.png"], cwd=td, timeout=60)
            data = (pathlib.Path(td) / "doc.png").read_bytes()
            return {"content_type": "image/png", "b64": base64.b64encode(data).decode()}
        else:
            raise HTTPException(400, "fmt must be svg or png")


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)


