"""Decoded meshes (.ply) and descriptors (.fcp) of the open box: the mesh route on the clean mesh, and gwn with the 2D closing
(CLOSE = 0.75 spacings; sigma given on the noisy clouds) on its clean / pn0p12 / pn0p6 clouds at 10k and 2048 -> ../decoded/.
Also the input clouds (.ply points) next to them, and a summary.txt (parts, error x1e-3, normal median)."""
import sys
from pathlib import Path
import numpy as np, trimesh
sys.path.insert(0, str(Path(__file__).parent)); sys.path.insert(0, "/home/joao/code/data/meshes/fcp_2710_tests/scripts")
import gwn, fcp, fcp.tools  # noqa
from parts_report import OBJ, ROOT, stats  # noqa
from bench import sigma_of  # noqa

OUT = Path(__file__).parent.parent / "decoded"
OUT.mkdir(exist_ok=True)
name = "open_box"
g = trimesh.load(OBJ[name], force="mesh")
diag = float(np.linalg.norm(g.extents))
ref = np.asarray(g.sample(50_000, seed=1))
Ps, fi = trimesh.sample.sample_surface(g, 3000, seed=3); Ns = g.face_normals[fi]
lines = []


def out(label, d):
    fcp.save(d, OUT / f"{label}.fcp")
    m = fcp.decode(d, device="cuda")
    m.export(OUT / f"{label}.ply")
    Ne = fcp.tools.Shape(d, device="cuda").normal(Ps, method="sdf")
    Ne /= np.maximum(np.linalg.norm(Ne, axis=1, keepdims=True), 1e-12)
    nm = np.median(np.degrees(np.arccos(np.clip((Ne * Ns).sum(1), -1, 1))))
    s = f"{label:32s} parts {len(d.parts):3d}  error {1e3 * stats(d, ref, m)[0]:6.2f}  normal median {nm:5.1f} deg  bytes {d.nbytes}"
    lines.append(s); print(s, flush=True)


out(f"{name}_mesh_route", fcp.encode(g, device="cuda", up=(0, 0, 1)))
gwn.CLOSE = 0.75
for tag in ("clean", "pn0p12", "pn0p6"):
    for n in (10000, 2048):
        P = np.asarray(trimesh.load(ROOT / "pointclouds" / f"{name}_{tag}_{n}.ply").vertices)
        trimesh.PointCloud(P).export(OUT / f"{name}_{tag}_{n}_input.ply")
        out(f"{name}_{tag}_{n}_gwn", gwn.encode_gwn(P, up=(0, 0, 1), sigma=sigma_of(tag, diag)))
(OUT / "summary.txt").write_text("gwn = gwn.py defaults + CLOSE = 0.75 (2D closing), sigma given on pn* (fraction of the diagonal); "
                                 "1024 atoms, 128 layers, up +z; error = mean symmetric distance to the clean mesh / diagonal\n"
                                 + "\n".join(lines) + "\n")
