"""The degree sweep's two effects apart, meshes only: the cut decision of tracked-fit (split_by_fit's height basis) and the
stored height basis (parts_system, the decoder) each at the default cap (KAPPA 1e2, M 24) or a high one (KAPPA 1e4, M 50).
"cut hi, basis lo" is the default encoder on the longer parts a high cap leaves; "cut lo, basis hi" the default parts with
higher degrees. Same measures as degree_sweep.py. Writes ../report/split_2x2.csv.

    env -u PYTHONPATH PYTHONWARNINGS=ignore .venv/bin/python ~/code/data/meshes/fcp_2810_partition/scripts/split_2x2.py
"""
import csv
import sys
import time
from pathlib import Path

import numpy as np
import trimesh

sys.path.insert(0, str(Path(__file__).parent))
from degree_sweep import BUDGETS, DEVICE, OBJ, REPORT, UP, Ref, set_kappa  # noqa: E402  (puts the package on the path)
import fcp  # noqa: E402
from fcp import _parts  # noqa: E402

CAPS = {"lo": (1e2, 24), "hi": (1e4, 50)}
OUT = REPORT / "split_2x2.csv"
FIELDS = ["object", "cut", "basis", "atoms", "parts", "max_deg", "mean_len", "chamfer", "p95", "n_mean", "n_over30", "seconds"]
_split = _parts.split_by_fit


def cut_with(cap, basis):
    """split_by_fit with the cut cap's basis, the basis cap restored for everything after it."""
    def split(parts, coeffs, areas, M, tol=None, follows=None):
        set_kappa(CAPS[cap][0])
        try:
            return _split(parts, coeffs, areas, CAPS[cap][1], tol, follows)
        finally:
            set_kappa(CAPS[basis][0])
    return split


def main():
    with OUT.open("w", newline="") as f:
        w = csv.writer(f)
        w.writerow(FIELDS)
        for name, path in OBJ.items():
            g = trimesh.load(path, force="mesh")
            ref = Ref(g)
            for cut in CAPS:
                for basis in CAPS:
                    _parts.split_by_fit = cut_with(cut, basis)
                    set_kappa(CAPS[basis][0])
                    M = CAPS[basis][1]
                    t = time.perf_counter()
                    d = fcp.encode(g, atoms=max(BUDGETS), up=UP, M=M, parts="tracked-fit", device=DEVICE)
                    sec = time.perf_counter() - t
                    lens = [h1 - h0 + 1 for _, h0, h1 in d.parts]
                    deg = max(_parts.height_degree(n, M) for n in lens)
                    for T in BUDGETS:
                        m = fcp.decode(d.prefix(T), device=DEVICE)
                        w.writerow([name, cut, basis, T, len(d.parts), deg, round(float(np.mean(lens)), 1),
                                    *[round(float(v), 5) for v in ref.measure(m)], round(sec, 3)])
                    f.flush()
                    print(f"{name:16s} cut={cut} basis={basis} parts={len(d.parts):3d} deg={deg:3d}", flush=True)
    _parts.split_by_fit = _split
    set_kappa(1e2)


if __name__ == "__main__":
    main()
