"""Checks for the twist shutter: free motion over the whole sweep, end stops, light-tight
closing, clear field of view when open, and fit against the face, camera and board."""
import math

from build123d import Pos, Cone, Cylinder, Align, Vector

import coral_eye as ce
import shutter as sh


def vol(a, b):
    i = a & b
    return i.volume if i else 0.0


parts = {"bezel": sh.make_bezel(), "twist": sh.make_twist_ring(),
         "blade_up": sh.make_blade(True), "blade_down": sh.make_blade(False)}
for k, v in parts.items():
    print(f"{k:10s} volume {v.volume:7.1f} mm3  solids {len(v.solids())}")

print("== moving parts over the sweep (mm3). bezel/twist must be 0 except in the two click zones")
print("   near each end of the travel, where the bosses push the detent nubs aside")
pairs = [("bezel", "twist"), ("bezel", "blade_up"), ("bezel", "blade_down"), ("twist", "blade_up"),
         ("twist", "blade_down"), ("blade_up", "blade_down")]
for th in (0, 3, 6.0, 10, 15, 30, 45, 50, 54.0, 57, 60):
    a = sh.assembly(th, parts)
    row = "  ".join(f"{p}/{q} {vol(a[p], a[q]):6.3f}" for p, q in pairs)
    print(f"theta {th:5.1f}: {row}")

print("== end stops: turning past the ends must hit the bezel's bosses")
for th in (-3.0, sh.SWEEP + 3.0):
    a = sh.assembly(th, parts)
    print(f"theta {th:5.1f}: bezel/twist overlap {vol(a['bezel'], a['twist']):.3f} mm3 (>0 = blocked)")

print("== closed: every ray inside the eye must hit a blade")
a = sh.assembly(sh.SWEEP, parts)
blades = [a["blade_up"], a["blade_down"]]
zs = [ce.Z_FRONT + sh.BL_Z0 + 0.025 + 0.05 * k for k in range(20)]
leaks, n = 0, 0
for i in range(-12, 13):
    for j in range(-12, 13):
        x, y = i * 0.5, j * 0.5
        if x * x + y * y > (sh.R_EYE + 0.05) ** 2:
            continue
        n += 1
        hit = any(b.is_inside(Vector(ce.LENS_X + x, ce.LENS_Y + y, z)) for b in blades for z in zs)
        leaks += 0 if hit else 1
print(f"   {n} rays, {leaks} leaks")

print("== open: field of view (72 deg diagonal, pupil r 1.0, lens position +-1.0 mm) against every part")
lens_top = ce.CAM_Z_FRONT + ce.LENS_BLOCK_H
h = 12.0
r0 = 1.0 + 1.0
cone = Pos(ce.LENS_X, ce.LENS_Y, lens_top) * Cone(bottom_radius=r0, top_radius=r0 + h * math.tan(math.radians(36)),
                                                  height=h, align=(Align.CENTER, Align.CENTER, Align.MIN))
a0 = sh.assembly(0, parts)
face = ce.make_face("skin") - sh.face_pilots()
for k in ("bezel", "twist", "blade_up", "blade_down"):
    print(f"   {k:10s} in the field of view: {vol(cone, a0[k]):.3f} mm3")
print(f"   face       in the field of view: {vol(cone, face):.3f} mm3")

print("== fit against the face (bosses sit on it) and the camera")
for k in ("bezel", "twist", "blade_up", "blade_down"):
    print(f"   {k:10s} vs face {vol(a0[k], face):.3f} mm3")
pcb, lens, conn = ce.make_camera_mock()
print(f"   face pilots vs camera board, lens and connector: {vol(sh.face_pilots(), pcb + lens + conn):.3f} mm3")
gaps = []
for u, v in ce.CAM_HOLES_UV:                     # camera screws (any length) vs the shutter's M2 screws
    px, py = ce.cam_xy(u, v)
    for sx in (-1, 1):
        d = math.hypot(px - (ce.LENS_X + sx * sh.BOSS_X), py - ce.LENS_Y)
        gaps.append(d - ce.CAM_PILOT_D / 2 - sh.FACE_PILOT_D / 2)
print(f"   closest camera-screw pilot to a shutter-screw pilot: {min(gaps):.2f} mm of plastic between them")
bb = a0["twist"].bounding_box()
print(f"   twist ring reaches y {bb.min.Y:.2f} .. {bb.max.Y:.2f}, x {bb.min.X:.2f} .. {bb.max.X:.2f} "
      f"(face y {ce.OUT_Y0:.1f} .. {ce.OUT_Y1:.1f}, light bar top at y 0.7)")
print(f"   module front at z {ce.Z_FRONT + sh.BZ_Z1:.2f} (proud {sh.BZ_Z1:.2f} mm)")
