"""Interoperability — export a plan to the tools a surgeon already uses.

The plan is most useful if it drops into existing navigation/planning systems
rather than replacing them:

* ``export_fcsv`` — 3D Slicer fiducial list (entry + target markups);
* ``export_json`` — a portable trajectory record;
* ``export_rtstruct`` — a DICOM **RT Structure Set** with Entry / Target point
  ROIs and a Trajectory line, importable into Brainlab / StealthStation and
  other RTSTRUCT-aware systems.

Coordinates are patient-space world mm (LPS is written for DICOM per the
standard; RAS is written for Slicer FCSV). Research software — not a medical device.
"""
from __future__ import annotations
import json
import numpy as np


def _xyz(p):
    p = np.asarray(p, float).ravel()
    return float(p[0]), float(p[1]), float(p[2])


def export_json(path, entry, target, meta=None) -> str:
    """Portable trajectory record (RAS world mm)."""
    e, t = _xyz(entry), _xyz(target)
    rec = {"schema": "sulcora.trajectory/1", "coordinate_system": "RAS_world_mm",
           "entry": e, "target": t,
           "length_mm": round(float(np.linalg.norm(np.array(t) - np.array(e))), 2),
           "meta": meta or {}}
    with open(path, "w") as f:
        json.dump(rec, f, indent=2)
    return path


def export_fcsv(path, entry, target, labels=("Entry", "Target")) -> str:
    """3D Slicer fiducial list (.fcsv). Slicer markups are RAS."""
    e, t = _xyz(entry), _xyz(target)
    lines = ["# Markups fiducial file version = 5.0",
             "# CoordinateSystem = RAS",
             "# columns = id,x,y,z,ow,ox,oy,oz,vis,sel,lock,label,desc,associatedNodeID"]
    for i, (p, lab) in enumerate([(e, labels[0]), (t, labels[1])], start=1):
        lines.append(f"vtkMRMLMarkupsFiducialNode_{i},{p[0]:.4f},{p[1]:.4f},{p[2]:.4f},"
                     f"0,0,0,1,1,1,0,{lab},,")
    with open(path, "w") as f:
        f.write("\n".join(lines) + "\n")
    return path


def _ras_to_lps(p):
    x, y, z = _xyz(p)
    return [-x, -y, z]              # DICOM patient coordinates are LPS


def export_rtstruct(path, entry, target, frame_of_reference_uid=None,
                    label="Sulcora Plan") -> str:
    """DICOM RT Structure Set: Entry/Target point ROIs + a Trajectory line.

    Points are converted RAS→LPS (DICOM patient coordinates). Importable into
    RTSTRUCT-aware navigation/planning systems. Requires pydicom.
    """
    import pydicom
    from pydicom.dataset import Dataset, FileDataset, FileMetaDataset
    from pydicom.uid import generate_uid, ImplicitVRLittleEndian

    RTSTRUCT_SOP = "1.2.840.10008.5.1.4.1.1.481.3"
    for_uid = frame_of_reference_uid or generate_uid()

    fm = FileMetaDataset()
    fm.MediaStorageSOPClassUID = RTSTRUCT_SOP
    fm.MediaStorageSOPInstanceUID = generate_uid()
    fm.TransferSyntaxUID = ImplicitVRLittleEndian
    ds = FileDataset(path, {}, file_meta=fm, preamble=b"\0" * 128)
    ds.SOPClassUID = RTSTRUCT_SOP
    ds.SOPInstanceUID = fm.MediaStorageSOPInstanceUID
    ds.Modality = "RTSTRUCT"
    ds.StructureSetLabel = label
    ds.StudyInstanceUID = generate_uid()
    ds.SeriesInstanceUID = generate_uid()
    ds.PatientName = "Sulcora^Plan"
    ds.PatientID = "SULCORA"

    frame = Dataset(); frame.FrameOfReferenceUID = for_uid
    ds.ReferencedFrameOfReferenceSequence = [frame]

    e_lps, t_lps = _ras_to_lps(entry), _ras_to_lps(target)
    rois = [("Entry", "POINT", [e_lps]),
            ("Target", "POINT", [t_lps]),
            ("Trajectory", "OPEN_PLANAR", [e_lps, t_lps])]

    ss_seq, rc_seq, obs_seq = [], [], []
    for i, (name, geom, pts) in enumerate(rois, start=1):
        roi = Dataset()
        roi.ROINumber = i
        roi.ReferencedFrameOfReferenceUID = for_uid
        roi.ROIName = name
        roi.ROIGenerationAlgorithm = "AUTOMATIC"
        ss_seq.append(roi)

        contour = Dataset()
        contour.ContourGeometricType = geom
        contour.NumberOfContourPoints = len(pts)
        contour.ContourData = [round(c, 3) for p in pts for c in p]
        rc = Dataset()
        rc.ReferencedROINumber = i
        rc.ROIDisplayColor = [255, 0, 0] if name != "Trajectory" else [0, 255, 0]
        rc.ContourSequence = [contour]
        rc_seq.append(rc)

        obs = Dataset()
        obs.ObservationNumber = i
        obs.ReferencedROINumber = i
        obs.RTROIInterpretedType = "MARKER" if geom == "POINT" else "CONTROL"
        obs.ROIObservationLabel = name
        obs_seq.append(obs)

    ds.StructureSetROISequence = ss_seq
    ds.ROIContourSequence = rc_seq
    ds.RTROIObservationsSequence = obs_seq
    ds.is_little_endian = True
    ds.is_implicit_VR = True
    ds.save_as(path, write_like_original=False)
    return path
