"""Gallery / reference renders for the Printables listing (system python: numpy + Pillow)."""
import os
import sys
import numpy as np

HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
from render import Mesh, Camera, render, load_stl  # noqa: E402
from render_views import parts, stand_parts, BASE_Y, M, AXIS_Y, AXIS_Z, CORAL, FACE_COL, BODY_COL  # noqa: E402

G = os.path.normpath(os.path.join(HERE, "..", "render", "gallery"))
os.makedirs(G, exist_ok=True)
OUT = os.path.normpath(os.path.join(HERE, "..", "out"))


def save(name, meshes, eye, target, fov=30, w=1600, h=1200, ss=2, **kw):
    cam = Camera(eye, target, fov=fov, width=w, height=h)
    im = render(meshes, cam, ss=ss, **kw)
    p = os.path.join(G, name)
    im.save(p)
    print("saved", p)


def mount(name, col=BODY_COL, offset=(0, 0, 0)):
    return Mesh(load_stl(os.path.join(M, name + ".stl")) + np.array(offset, float), col, 0.18, 30, name)


def on_bed(name, col, x, y, rot=None):
    """Print-orientation STL placed on a virtual print bed (bed = world XZ plane, y up)."""
    T = load_stl(os.path.join(OUT, name + ".stl"))
    # print files are z-up; the renderer is y-up
    T = T[..., [0, 2, 1]] * np.array([1, 1, -1])
    if rot is not None:
        a = np.radians(rot)
        R = np.array([[np.cos(a), 0, np.sin(a)], [0, 1, 0], [-np.sin(a), 0, np.cos(a)]])
        T = T @ R.T
    c = T.reshape(-1, 3)
    T = T - [(c[:, 0].min() + c[:, 0].max()) / 2, c[:, 1].min(), (c[:, 2].min() + c[:, 2].max()) / 2]
    return Mesh(T + [x, 0, y], col, 0.18, 30, name)


if __name__ == "__main__":
    which = set(sys.argv[1:]) or {"hero", "back", "front", "explode", "inside", "mounts", "plate", "ports"}
    if "hero" in which:
        save("01_ref_hero.png", parts() + stand_parts(), eye=(-115, 55, 205), target=(32.7, 8.0, 0.0),
             fov=31, ground_y=BASE_Y)
    if "back" in which:
        save("02_ref_back.png", parts() + stand_parts(), eye=(175, 45, -165), target=(32.7, 6.0, -8.0),
             fov=31, ground_y=BASE_Y)
    if "front" in which:
        save("03_ref_front.png", parts(), eye=(32.7, 26.5, 260), target=(32.7, 26.5, 0.0), fov=22)
    if "explode" in which:
        offs = {"body": 0, "plunger": 0, "board": 22, "cable": 40, "campcb": 52, "camconn": 52, "lens": 52,
                "face": 78, "twist": 92, "blade_up": 101, "blade_down": 101, "bezel": 112, "bezel_screws": 124,
                "screws_back": -14}
        ms = []
        for m in parts():
            ms.append(Mesh(m.tris + [0, 0, offs[m.name]], m.color * 255, m.spec, m.gloss, m.name))
        save("04_exploded.png", ms, eye=(-235, 120, 205), target=(32.7, 26.0, 48.0), fov=34)
    if "inside" in which:
        save("05_inside.png", parts(with_face=False), eye=(-70, 70, 175), target=(32.7, 24.0, 0.0), fov=30)
    if "mounts" in which:
        ms = [mount("CoralEye_Mount_Magnet", offset=(-108, 0, 0)),
              mount("CoralEye_Mount_Wall", offset=(-70, 0, 0)), mount("CoralEye_Mount_Tripod", offset=(-35, 0, 0)),
              mount("CoralEye_Mount_GoPro", offset=(0, 0, 0)), mount("CoralEye_Stand", offset=(48, 0, 0)),
              mount("CoralEye_Mount_GoPro", offset=(48, 0, 0))]
        knob = load_stl(os.path.join(OUT, "CoralEye_Stand_Knob.stl"))
        R = np.array([[0, 0, -1], [0, 1, 0], [1, 0, 0]], float)
        ms.append(Mesh(knob @ R.T + [32.7 + 48 - 6.3 - 1.5, AXIS_Y, AXIS_Z], CORAL, 0.3, 40, "knob"))
        save("06_mounts.png", ms, eye=(-35, 75, 245), target=(8.0, 0.0, -10.0), fov=40, ground_y=BASE_Y)
    if "plate" in which:
        case = [on_bed("CoralEye_Body", BODY_COL, -42, 0), on_bed("CoralEye_Face_hidden-LEDs", FACE_COL, 42, 0),
                on_bed("CoralEye_Shutter_Bezel", CORAL, -50, 62), on_bed("CoralEye_Shutter_TwistRing", BODY_COL, -8, 62),
                on_bed("CoralEye_Shutter_Blade_Upper", CORAL, 22, 54), on_bed("CoralEye_Shutter_Blade_Lower", CORAL, 22, 70),
                on_bed("CoralEye_Stand_Knob", CORAL, 44, 62), on_bed("CoralEye_UserButton", BODY_COL, 64, 62)]
        save("07_print_plate_case.png", case, eye=(0, 200, 170), target=(0, 0, 18), fov=38, ground_y=0.0)
        mounts = [on_bed("CoralEye_Stand", BODY_COL, -45, 0), on_bed("CoralEye_Mount_GoPro", BODY_COL, 18, -18),
                  on_bed("CoralEye_Mount_Tripod", BODY_COL, 18, 30), on_bed("CoralEye_Mount_Wall", BODY_COL, 58, -12),
                  on_bed("CoralEye_Mount_Magnet", BODY_COL, 58, 28)]
        save("07b_print_plate_mounts.png", mounts, eye=(0, 190, 160), target=(5, 0, 5), fov=38, ground_y=0.0)
    if "cut" in which:
        board = load_stl(os.path.join(M, "cut_board.stl"))
        cols = {"cut_body": BODY_COL, "cut_face": FACE_COL, "cut_bezel": CORAL, "cut_twist": BODY_COL,
                "cut_blade_up": CORAL, "cut_blade_down": CORAL, "cut_campcb": (30, 110, 60),
                "cut_lens": (20, 20, 22), "cut_camconn": (60, 60, 60), "cut_cable": (214, 128, 40)}
        ms = [Mesh(board, (236, 238, 236), 0.1, 20, "board")]
        for n, c in cols.items():
            ms.append(Mesh(load_stl(os.path.join(M, n + ".stl")), c, 0.2, 30, n))
        save("09_cable_section.png", ms, eye=(175, 40, 60), target=(40.0, 22.0, 3.0), fov=30)
    if "ports" in which:
        save("08_ports.png", parts(), eye=(10, -120, 120), target=(32.7, 5.0, 2.0), fov=30)
