"""Whiteboard frame mode: fetches a Nextcloud Whiteboard (or any other
WebDAV server's) .whiteboard file and renders it via the local
render-service sidecar (server/render-service/, own README there) --
Excalidraw's real export code, not a hand-rolled reimplementation of its
element types/styling/fonts.

Deliberately renders at a fixed generous width, not the panel's exact
target size -- the resulting PNG then runs through
image_pipeline.compose_into exactly like a photo would (crop/letterbox
per the frame's own display_mode setting), so this module doesn't need
to know anything about panel dimensions/orientation, and whiteboard mode
reuses the same fit logic photos mode already has instead of a second
parallel implementation of it.

Pure functions -- no ORM, no FastAPI Depends -- same testability
philosophy as calendar_feed.py/weather.py.
"""

from __future__ import annotations

import json

import httpx

from . import webdav_client

RENDER_SERVICE_URL = "http://127.0.0.1:3001/render"
# Rendering (not just fetching) can take a moment for a busy board --
# more generous than a typical fetch timeout.
HTTP_TIMEOUT_S = 30.0
# Fixed render width regardless of the target frame's orientation/size --
# see module docstring. Comfortably above this panel's 800px long edge
# so downstream cropping isn't working from an upscaled source.
RENDER_WIDTH = 1600

CHECK_INTERVAL_S = 20 * 60  # same cadence as calendar_feed's merge-fetch throttle


class WhiteboardRenderError(Exception):
    """Fetch or render failed -- network, auth, an invalid/non-JSON
    file, or the render sidecar itself erroring. Raised loudly; callers
    decide what to do."""


def fetch_and_render(url: str, username: str, password: str) -> bytes:
    """Fetches the .whiteboard file at `url` and renders it to a PNG via
    the local render-service sidecar. Returns raw PNG bytes at
    RENDER_WIDTH wide, natural aspect ratio."""
    try:
        raw = webdav_client.fetch_file(url, username, password)
    except webdav_client.WebDavError as e:
        raise WhiteboardRenderError(f"Could not fetch whiteboard file: {e}") from e

    try:
        scene = json.loads(raw)
    except ValueError as e:
        raise WhiteboardRenderError(f"Not a valid whiteboard file (not JSON): {e}") from e
    if not isinstance(scene.get("elements"), list):
        raise WhiteboardRenderError('Not a valid whiteboard file (no "elements" array)')

    try:
        resp = httpx.post(
            RENDER_SERVICE_URL,
            json={
                "elements": scene.get("elements", []),
                "appState": scene.get("appState", {}),
                "files": scene.get("files", {}),
                "width": RENDER_WIDTH,
            },
            timeout=HTTP_TIMEOUT_S,
        )
        resp.raise_for_status()
        return resp.content
    except httpx.HTTPError as e:
        raise WhiteboardRenderError(f"Render sidecar failed: {e}") from e
