"""Printable PDF surgical-plan report (for the OR / chart).

One dense page per planned trajectory: axis-aligned tri-planar views, the
probe-aligned reformats surgeons plan in (in-line + probe's-eye), a
clearance-vs-depth profile, full geometric metrics, and a per-structure
clearance table (static and deformation-aware) covering vessels, eloquent
cortex, deep nuclei, and tracts.

Research output only — pages are watermarked "NOT FOR CLINICAL USE".
"""
from __future__ import annotations
import datetime
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages

from . import reslice as R

_BAND = {"HIGH": "#c0392b", "CAUTION": "#b9770e", "LOW": "#1e8449"}


def _triplanar(axes, vol, traj):
    disp = vol.window().data
    ni, nj, nk = disp.shape
    tv = np.round(vol.world_to_voxel(traj.target)).astype(int)
    ev = np.round(vol.world_to_voxel(traj.entry)).astype(int)
    tv = np.clip(tv, 0, [ni - 1, nj - 1, nk - 1]); ev = np.clip(ev, 0, [ni - 1, nj - 1, nk - 1])
    views = [
        (disp[:, :, tv[2]].T, (ev[0], ev[1]), (tv[0], tv[1]), "Axial"),
        (disp[:, tv[1], :].T, (ev[0], ev[2]), (tv[0], tv[2]), "Coronal"),
        (disp[tv[0], :, :].T, (ev[1], ev[2]), (tv[1], tv[2]), "Sagittal"),
    ]
    for ax, (img, e, t, title) in zip(axes, views):
        ax.imshow(img, cmap="gray", origin="lower")
        ax.plot([e[0], t[0]], [e[1], t[1]], "-", color="#1e8449", lw=1.6)
        ax.plot(t[0], t[1], "o", color="#c0392b", ms=4); ax.plot(e[0], e[1], "o", color="#1e8449", ms=4)
        ax.set_title(title, fontsize=8); ax.axis("off")


def _reformats(ax_inline, ax_eye, vol, traj):
    inl, us = R.along_trajectory(vol, traj, width_mm=50.0, pad_mm=10.0, spacing_mm=1.0)
    ax_inline.imshow(inl, cmap="gray", origin="lower", aspect="auto")
    i0 = int(np.argmin(np.abs(us - 0.0))); iL = int(np.argmin(np.abs(us - traj.length)))
    cy = inl.shape[0] // 2
    ax_inline.plot([i0, iL], [cy, cy], "-", color="#b9770e", lw=1.6)
    ax_inline.plot(i0, cy, "o", color="#1e8449", ms=4); ax_inline.plot(iL, cy, "o", color="#c0392b", ms=4)
    ax_inline.set_title("In-line (trajectory plane)", fontsize=8); ax_inline.axis("off")
    eye = R.probes_eye(vol, traj, fov_mm=44.0, spacing_mm=0.6)
    ax_eye.imshow(eye, cmap="gray", origin="lower")
    c = eye.shape[0] // 2
    ax_eye.plot(c, c, "+", color="#c0392b", ms=10, mew=1.6)
    ax_eye.set_title("Probe's-eye (at target)", fontsize=8); ax_eye.axis("off")


def _profile(ax, depths, best):
    ax.set_facecolor("#f6f8fb")
    for d, c in zip(depths, best):
        band = "HIGH" if c < 3 else ("CAUTION" if c < 6 else "LOW")
        ax.bar(d, min(c, 15), width=(depths[1] - depths[0]) if len(depths) > 1 else 1,
               color=_BAND[band], edgecolor="none")
    ax.axhline(3, color="#c0392b", ls=":", lw=0.8); ax.axhline(6, color="#b9770e", ls=":", lw=0.8)
    ax.set_xlabel("depth from entry (mm)", fontsize=7); ax.set_ylabel("clearance (mm)", fontsize=7)
    ax.set_title("Clearance vs. depth", fontsize=8); ax.tick_params(labelsize=6)


def _metrics_lines(vol, traj):
    ev, tv = vol.world_to_voxel(traj.entry), vol.world_to_voxel(traj.target)
    return [
        "GEOMETRY",
        f"  Entry (mm):   {', '.join(f'{x:.0f}' for x in traj.entry)}    vox {', '.join(f'{x:.0f}' for x in ev)}",
        f"  Target (mm):  {', '.join(f'{x:.0f}' for x in traj.target)}    vox {', '.join(f'{x:.0f}' for x in tv)}",
        f"  Insertion depth:  {traj.length:.1f} mm",
        f"  Approach angle (from vertical):  {traj.angle_from_axis():.0f} deg",
    ]


def _risk_lines(rep):
    lines = ["RISK (min clearance to critical structures)"]
    nearest = rep.get("nearest"); mc = rep.get("min_clearance_mm"); band = rep.get("band")
    if mc is not None:
        lines.append(f"  Nearest: {nearest}   {mc:.1f} mm   [{band}]")
    if rep.get("deformed_min_clearance_mm") is not None:
        lines.append(f"  Deformation-aware: {rep['deformed_min_clearance_mm']:.1f} mm   [{rep.get('deformed_band')}]")
    per = rep.get("per_structure") or {}
    if per:
        lines.append("  Per structure           static   deformed")
        for name, v in per.items():
            s = f"{v.get('clearance_mm', float('nan')):>6.1f}"
            dpart = f"{v['deformed_clearance_mm']:>7.1f}" if v.get("deformed_clearance_mm") is not None else "     --"
            lines.append(f"    {name:<20}{s}   {dpart}  [{v.get('band')}]")
    return lines


def build_report(plan, vol, out_path, title="Sulcora Surgical Plan",
                 structures=None, deformation=True, clinical=False):
    """Write a multi-page PDF: cover + one rich page per planned trajectory.

    If `structures` (RiskStructures) are supplied, per-structure clearances,
    deformation-aware values, and a clearance-vs-depth profile are computed and
    included; otherwise the report falls back to each item's stored risk dict.
    """
    from . import session
    from .deformation import ProbeDeformation
    stamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")

    with PdfPages(out_path) as pdf:
        # ---- cover ----
        fig = plt.figure(figsize=(8.5, 11)); fig.patch.set_facecolor("white")
        fig.text(0.5, 0.82, title, ha="center", fontsize=22, fontweight="bold")
        fig.text(0.5, 0.77, f"Patient/Case: {plan.patient_id}", ha="center", fontsize=12)
        fig.text(0.5, 0.74, f"Generated: {stamp}", ha="center", fontsize=10, color="#555")
        fig.text(0.5, 0.68, f"{len(plan)} planned trajector{'y' if len(plan)==1 else 'ies'}",
                 ha="center", fontsize=12)
        y = 0.60
        for it in plan:
            t = it.trajectory
            line = f"• {it.name}:  depth {t.length:.0f} mm,  angle {t.angle_from_axis():.0f}°"
            rk = it.risk or {}
            cl = rk.get("min_clearance_mm") or rk.get("clearance_mm") or rk.get("static_clearance_mm")
            bd = rk.get("band") or rk.get("static_band")
            if cl is not None:
                line += f",  clearance {cl:.1f} mm ({bd})"
            fig.text(0.1, y, line, fontsize=11); y -= 0.032
        fig.text(0.5, 0.06,
                 "RESEARCH SOFTWARE — NOT FOR CLINICAL USE. Demonstration on public reference data.",
                 ha="center", fontsize=9, color="#c0392b")
        pdf.savefig(fig); plt.close(fig)

        # ---- one page per trajectory ----
        for it in plan:
            traj = it.trajectory
            if structures:
                defo = ProbeDeformation(traj) if deformation else None
                rep = session.risk_summary(traj, structures, deformation=defo)
                depths, best, _ = session.clearance_profile(traj, structures)
            else:
                rep = it.risk or {}
                depths = best = None

            fig = plt.figure(figsize=(11, 8.5)); fig.patch.set_facecolor("white")
            fig.suptitle(f"{plan.patient_id} — {it.name}", fontsize=15, fontweight="bold")
            tri = [fig.add_axes([0.04, 0.60, 0.28, 0.33]),
                   fig.add_axes([0.35, 0.60, 0.28, 0.33]),
                   fig.add_axes([0.66, 0.60, 0.28, 0.33])]
            _triplanar(tri, vol, traj)
            _reformats(fig.add_axes([0.04, 0.30, 0.28, 0.26]),
                       fig.add_axes([0.35, 0.32, 0.20, 0.24]), vol, traj)
            if depths is not None:
                _profile(fig.add_axes([0.62, 0.34, 0.33, 0.20]), depths, best)

            # geometry (left) and per-structure risk table (right) as two columns
            fig.text(0.06, 0.25, "\n".join(_metrics_lines(vol, traj)), fontsize=8.5,
                     family="monospace", va="top", linespacing=1.5)
            fig.text(0.50, 0.25, "\n".join(_risk_lines(rep)), fontsize=8.5,
                     family="monospace", va="top", linespacing=1.5)
            fig.text(0.5, 0.02, "RESEARCH SOFTWARE — NOT FOR CLINICAL USE.",
                     ha="center", fontsize=9, color="#c0392b")
            pdf.savefig(fig); plt.close(fig)
    return out_path
