#!/usr/bin/env python3
"""
Parametric Junction Box — follows original Junction Box PLUS Mini design.
Original: 60x60x17mm base + 60x60x10mm lid
Target:   80x70x50mm

Design: base with thick walls + window slots, lid with tongue + ribs,
window panels slide into wall slots.
"""
from build123d import *
import os

OUT = "/app/projects/esp32-box/exports"
os.makedirs(OUT, exist_ok=True)

# ============================================================
# PARAMETERS — change these to resize
# ============================================================
# Outer footprint
W = 80.0        # X width
D = 70.0        # Y depth
H_BASE = 32.0   # base height
H_LID  = 18.0   # lid height
H_TOTAL = H_BASE + H_LID  # = 50mm

# Wall structure (from original proportions)
WALL_OUTER = 6.5    # thick outer wall (holds window slots)
FLOOR_THICK = 3.0   # base floor thickness
LIP_THICK = 3.0     # top lip where lid sits
RIB_THICK = 1.0     # internal ribs

# Window slot
WIN_SLOT_W = 14.0   # window slot width (original: 13.9mm)
WIN_SLOT_H = H_BASE - FLOOR_THICK - LIP_THICK  # vertical opening
WIN_SLOT_DEPTH = WALL_OUTER  # how deep the slot cuts into wall

# Window panel
WIN_W = W - 2*WALL_OUTER + 2*3.0  # width between walls + tongue overlap
WIN_H = WIN_SLOT_H
WIN_THICK = 4.8     # panel thickness

# Lid tongue (fits into base)
TONGUE_W = 10.0     # tongue width at each corner
TONGUE_H = LIP_THICK - 0.3  # fits into lip area with clearance
TONGUE_CLEARANCE = 0.15

# Screws
SCREW_R = 1.3       # M2.5
SCREW_POST_R = 3.5
SCREW_HEAD_R = 3.0

TOL = 0.15

# ============================================================
# 1. BASE
# ============================================================
print("Building base (%.0fx%.0fx%.0fmm)..." % (W, D, H_BASE))

# Start with full box
base = Box(W, D, H_BASE)

# Hollow out interior (leave floor + walls)
int_w = W - 2*WALL_OUTER
int_d = D - 2*WALL_OUTER
int_h = H_BASE - FLOOR_THICK
interior = Pos(0, 0, FLOOR_THICK/2) * Box(int_w + TOL, int_d + TOL, int_h + 0.1)
base = base - interior

# Window slots on all 4 sides (vertical channels in the walls)
# X-axis walls (front/back): slots run along Y
slot_len_x = int_d - 1.0  # slightly short of full interior depth
for side in [-1, 1]:
    sy = side * (D/2 - WALL_OUTER/2)
    slot = Pos(0, sy, FLOOR_THICK + int_h/2) * Box(WALL_OUTER + 0.2, WIN_SLOT_W + TOL, int_h + 0.1)
    base = base - slot

# Y-axis walls (left/right): slots run along X
slot_len_y = int_w - 1.0
for side in [-1, 1]:
    sx = side * (W/2 - WALL_OUTER/2)
    slot = Pos(sx, 0, FLOOR_THICK + int_h/2) * Box(WIN_SLOT_W + TOL, WALL_OUTER + 0.2, int_h + 0.1)
    base = base - slot

# Reinforcement ribs at corners (inside)
rib_len = 12.0
for sx in [-1, 1]:
    for sy in [-1, 1]:
        cx_ = sx * (W/2 - WALL_OUTER/2)
        cy_ = sy * (D/2 - WALL_OUTER/2)
        # X-direction rib
        rib_x = Pos(cx_ - sx*rib_len/2, cy_, FLOOR_THICK + 1.5) * Box(rib_len, RIB_THICK, 3.0)
        base = base + rib_x
        # Y-direction rib
        rib_y = Pos(cx_, cy_ - sy*rib_len/2, FLOOR_THICK + 1.5) * Box(RIB_THICK, rib_len, 3.0)
        base = base + rib_y

# Screw posts at corners
post_h = int_h - 2.0
cx = int_w/2 - 5.0
cy = int_d/2 - 5.0
for sx in [-1, 1]:
    for sy in [-1, 1]:
        px, py = sx*cx, sy*cy
        post = Pos(px, py, FLOOR_THICK) * Cylinder(SCREW_POST_R, SCREW_POST_R, post_h)
        hole = Pos(px, py, FLOOR_THICK - 0.05) * Cylinder(SCREW_R + TOL, SCREW_R + TOL, post_h + 0.1)
        base = base + post - hole

export_stl(base, "%s/base.stl" % OUT)
print("  -> base.stl")

# ============================================================
# 2. LID
# ============================================================
print("Building lid (%.0fx%.0fx%.0fmm)..." % (W, D, H_LID))

lid = Box(W, D, H_LID)

# Tongue blocks on underside (4 corners, fit into base lip)
tongue_clear = TONGUE_CLEARANCE
for sx in [-1, 1]:
    for sy in [-1, 1]:
        tx = sx * (W/2 - TONGUE_W/2 - 0.5)
        ty = sy * (D/2 - TONGUE_W/2 - 0.5)
        tongue = Pos(tx, ty, -H_LID/2 + TONGUE_H/2) * Box(
            TONGUE_W - tongue_clear, TONGUE_W - tongue_clear, TONGUE_H)
        lid = lid + tongue

# Hollow interior (thin lid shell)
lid_int_w = W - 2*WALL_OUTER
lid_int_d = D - 2*WALL_OUTER
lid_int_h = H_LID - 2.5  # leave 2.5mm top thickness
lid_hollow = Pos(0, 0, 2.5/2) * Box(lid_int_w, lid_int_d, lid_int_h + 0.1)
lid = lid - lid_hollow

# Internal ribs on lid underside
for i in range(3):
    rx = -int_w/4 + i * int_w/4
    rib = Pos(rx, 0, -H_LID/2 + 2.5 + lid_int_h/2) * Box(RIB_THICK, lid_int_d - 2, lid_int_h - 1)
    lid = lid + rib
for i in range(3):
    ry = -int_d/4 + i * int_d/4
    rib = Pos(0, ry, -H_LID/2 + 2.5 + lid_int_h/2) * Box(lid_int_w - 2, RIB_THICK, lid_int_h - 1)
    lid = lid + rib

# Screw holes through lid
for sx in [-1, 1]:
    for sy in [-1, 1]:
        px, py = sx*cx, sy*cy
        hole = Pos(px, py, 0) * Cylinder(SCREW_R + TOL, SCREW_R + TOL, H_LID + 0.2)
        lid = lid - hole

export_stl(lid, "%s/lid.stl" % OUT)
print("  -> lid.stl")

# ============================================================
# 3. WINDOW PANELS
# ============================================================
print("Building window panels...")

# Panel A: smooth (2x)
win_a = Box(WIN_W, WIN_SLOT_W, WIN_THICK)
# Small tongue on top/bottom edges for retention
ret_tongue = 0.8
for side in [-1, 1]:
    rt = Pos(0, side*(WIN_SLOT_W/2 - ret_tongue/2), 0) * Box(WIN_W - 1, ret_tongue, WIN_THICK + 0.6)
    win_a = win_a + rt
export_stl(win_a, "%s/window_smooth.stl" % OUT)
print("  -> window_smooth.stl (x2)")

# Panel B: keystone + DC jack
win_b = Box(WIN_W, WIN_SLOT_W, WIN_THICK)
# Retention tongues
for side in [-1, 1]:
    rt = Pos(0, side*(WIN_SLOT_W/2 - ret_tongue/2), 0) * Box(WIN_W - 1, ret_tongue, WIN_THICK + 0.6)
    win_b = win_b + rt
# Keystone cutout (14.5 x 16mm)
key = Pos(-15, 0, 0) * Box(16.5, WIN_SLOT_W + 0.4, WIN_THICK + 0.2)
win_b = win_b - key
# DC barrel jack (9mm)
dc = Pos(18, 0, 0) * Box(9.5, 9.5, WIN_THICK + 0.2)
win_b = win_b - dc
export_stl(win_b, "%s/window_keystone_dc.stl" % OUT)
print("  -> window_keystone_dc.stl")

# Panel C: mini-USB
win_c = Box(WIN_W, WIN_SLOT_W, WIN_THICK)
for side in [-1, 1]:
    rt = Pos(0, side*(WIN_SLOT_W/2 - ret_tongue/2), 0) * Box(WIN_W - 1, ret_tongue, WIN_THICK + 0.6)
    win_c = win_c + rt
# Mini-USB cutout (9 x 4.5mm)
usb = Pos(0, 0, 0) * Box(9.0, 4.5, WIN_THICK + 0.2)
win_c = win_c - usb
export_stl(win_c, "%s/window_usb.stl" % OUT)
print("  -> window_usb.stl")

# ============================================================
# 4. SCREW
# ============================================================
print("Building screw...")
screw = Cylinder(SCREW_HEAD_R, SCREW_HEAD_R, 2.0)
shaft = Pos(0, 0, -2.0/2 - 5.0) * Cylinder(SCREW_R, SCREW_R, 10.0)
screw = screw + shaft
export_stl(screw, "%s/screw.stl" % OUT)
print("  -> screw.stl")

# ============================================================
# DONE
# ============================================================
print("\n" + "="*50)
print("PARAMETRIC JUNCTION BOX")
print("="*50)
print("Footprint: %.0f x %.0f x %.0fmm" % (W, D, H_TOTAL))
print("Base:      %.0f x %.0f x %.0fmm" % (W, D, H_BASE))
print("Lid:       %.0f x %.0f x %.0fmm" % (W, D, H_LID))
print("Walls:     %.1fmm (window slots)" % WALL_OUTER)
print("Window:    %.0f x %.0f x %.1fmm" % (WIN_W, WIN_SLOT_W, WIN_THICK))
print("\nAssembly:")
print("  1. Slide window panels into base wall slots")
print("  2. Place components inside")
print("  3. Lid tongue fits into base")
print("  4. 4x M2.5 screws through lid into posts")
print("\nFiles: %s/" % OUT)
