"""Public professional-reference export assembly for the Jyotish API. This boundary performs no writing-agent, persistence, billing, or telemetry work. It validates the public export request, reuses the handler's one full-reading calculation, and delegates packet assembly/rendering to ``jyotish_engine``. """ from __future__ import annotations from importlib import import_module from types import SimpleNamespace from typing import Any class ProfessionalReportReferenceInputError(ValueError): """The professional-reference request is outside the public contract.""" def _normalize_format(value: Any) -> str: if value is None: return "json" if not isinstance(value, str): raise ProfessionalReportReferenceInputError("format must be json or markdown") normalized = value.strip().lower() if normalized not in {"json", "markdown"}: raise ProfessionalReportReferenceInputError("format must be json or markdown") return normalized def _normalize_packs(value: Any) -> list[str]: if value is None: return [] if isinstance(value, str): raw_items = value.split(",") elif isinstance(value, list): if any(not isinstance(item, str) for item in value): raise ProfessionalReportReferenceInputError("packs must contain only strings") raw_items = value else: raise ProfessionalReportReferenceInputError("packs must be a string or array of strings") selected: list[str] = [] seen: set[str] = set() for item in raw_items: pack_id = item.strip() if pack_id and pack_id not in seen: selected.append(pack_id) seen.add(pack_id) return selected def _load_engine(): try: return import_module("scripts.jyotish_engine") except ModuleNotFoundError: # pragma: no cover - direct scripts/ execution path return import_module("jyotish_engine") def _export_args(birth: dict[str, Any]) -> SimpleNamespace: normalized_birth = { **birth, "hour": int(birth["hour"]), "minute": int(birth["minute"]), "second": int(birth.get("second", 0)), } return SimpleNamespace( **normalized_birth, age=None, target_year=None, visual_chart_observations=None, startrack_language_bridge=False, ) def build_professional_report_reference(handler, body: dict[str, Any], *, engine=None) -> dict[str, Any]: """Build one JSON or Markdown response from one reused full-reading result.""" if not isinstance(body, dict): raise ProfessionalReportReferenceInputError("request body must be an object") output_format = _normalize_format(body.get("format")) packs = _normalize_packs(body.get("packs")) birth = handler._high_rigor_birth_payload(body) full_reading = handler._compute_full_reading_for_thematic(birth) resolved_engine = engine or _load_engine() try: packet = resolved_engine.build_professional_report_reference_packet( full_reading, _export_args(birth), packs, ) except ValueError as exc: raise ProfessionalReportReferenceInputError(str(exc)) from exc if output_format == "markdown": return { "format": "markdown", "markdown": resolved_engine.render_pl9_markdown(packet), } return { "format": "json", "report": packet, }