#!/usr/bin/env python3
"""
ESP32 + Relay 5V Box — 80x70x50mm
Modular design: base + lid + 4 removable side walls
Tongue-and-groove joints (3x3mm)
Side walls: 2 smooth, 1 keystone+DC jack, 1 mini-USB
"""
from build123d import *
import os

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

# ============================================================
# PARAMETERS
# ============================================================
BOX_X = 80.0    # width  (X)
BOX_Y = 70.0    # depth  (Y)
BOX_Z = 50.0    # height (Z)

WALL = 3.0      # wall thickness
TOL  = 0.15     # printing tolerance

BASE_H = 12.0   # base plate height (Z)
LID_H  = 10.0   # lid plate height (Z)
SIDE_H = BOX_Z - BASE_H - LID_H  # 28mm

TONGUE = 3.0    # tongue/groove size

INT_X = BOX_X - 2 * WALL  # 74
INT_Y = BOX_Y - 2 * WALL  # 64

# ============================================================
# 1. BASE PLATE — 80 x 70 x 12mm (Box(X,Y,Z))
# ============================================================
print("Building base plate...")
base = Box(BOX_X, BOX_Y, BASE_H)  # centered at origin

# Screw posts (4 corners, inside the box)
post_or = 3.5   # outer radius
post_ir = 1.3   # inner radius (M2.5)
post_h  = 6.0   # height above base bottom

cx = INT_X / 2 - 5.0  # 32mm from center
cy = INT_Y / 2 - 5.0  # 27mm from center

for sx in [-1, 1]:
    for sy in [-1, 1]:
        px, py = sx * cx, sy * cy
        # Post cylinder
        post = Pos(px, py, -BASE_H/2) * Cylinder(post_or, post_or, post_h)
        # Screw hole (goes through post)
        hole = Pos(px, py, -BASE_H/2 - 0.05) * Cylinder(post_ir, post_ir, post_h + 0.1)
        base = base + post - hole

export_stl(base, f"{OUT}/base.stl")
print(f"  -> base.stl ({BOX_X}x{BOX_Y}x{BASE_H}mm)")

# ============================================================
# 2. LID PLATE — 80 x 70 x 10mm
# ============================================================
print("Building lid plate...")
lid = Box(BOX_X, BOX_Y, LID_H)

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

# Alignment nubs on underside
nub_r = 1.0
nub_h = 1.5
for sx in [-1, 1]:
    for sy in [-1, 1]:
        px, py = sx * cx, sy * cy
        nub = Pos(px, py, -LID_H/2 + nub_h/2) * Cylinder(nub_r, nub_r, nub_h)
        lid = lid + nub

export_stl(lid, f"{OUT}/lid.stl")
print(f"  -> lid.stl ({BOX_X}x{BOX_Y}x{LID_H}mm)")

# ============================================================
# 3. SIDE WALL BUILDER
# ============================================================
def make_side_wall(length, height, wall, cutouts=None):
    """
    Create a side wall.
    length: along X axis
    height: along Z axis (vertical)
    wall: thickness along Y axis
    cutouts: list of (x, z, w, h) tuples for rectangular cutouts
    """
    # Main wall body, centered
    wall_body = Box(length, wall, height)
    
    # Grooves on top and bottom to receive lid/base tongues
    # Groove runs full length, cuts through wall from both sides
    groove_h = TONGUE + TOL  # 3.15mm groove height
    groove_w = wall + 0.2    # slightly wider than wall for clearance
    
    # Top groove (for lid tongue coming down)
    g_top = Pos(0, 0, height/2 - groove_h/2) * Box(length - 0.1, groove_w + 0.2, groove_h)
    # Bottom groove (for base tongue coming up)
    g_bot = Pos(0, 0, -height/2 + groove_h/2) * Box(length - 0.1, groove_w + 0.2, groove_h)
    
    result = wall_body - g_top - g_bot
    
    # Apply cutouts
    if cutouts:
        for (cx_, cz_, cw, ch) in cutouts:
            cutout = Pos(cx_, 0, cz_) * Box(cw, wall + 0.4, ch)
            result = result - cutout
    
    return result

# ============================================================
# 4. SIDE WALLS
# ============================================================
print("Building side walls...")

# Side A (Y-axis walls): length = INT_Y = 64mm
side_a = make_side_wall(INT_Y, SIDE_H, WALL)
export_stl(side_a, f"{OUT}/side_smooth_A.stl")
print(f"  -> side_smooth_A.stl ({INT_Y}x{WALL}x{SIDE_H}mm) x2")

# Side B (X-axis, front): keystone + DC jack
# Keystone: 14.5 x 16mm centered, DC jack: 8mm diameter, offset right
side_b_cutouts = [
    (-15.0, 0.0, 16.5, 18.0),   # Keystone cutout (16.5x18mm)
    ( 18.0, 0.0,  9.0,  9.0),   # DC barrel jack (9x9mm)
]
side_b = make_side_wall(INT_X, SIDE_H, WALL, side_b_cutouts)
export_stl(side_b, f"{OUT}/side_keystone_dc.stl")
print(f"  -> side_keystone_dc.stl ({INT_X}x{WALL}x{SIDE_H}mm)")

# Side C (X-axis, back): mini-USB cutout
# Mini-USB: ~8x3.5mm centered
side_c_cutouts = [
    (0.0, 0.0, 9.0, 4.5),  # Mini-USB (9x4.5mm with tolerance)
]
side_c = make_side_wall(INT_X, SIDE_H, WALL, side_c_cutouts)
export_stl(side_c, f"{OUT}/side_usb.stl")
print(f"  -> side_usb.stl ({INT_X}x{WALL}x{SIDE_H}mm)")

# ============================================================
# 5. SCREW
# ============================================================
print("Building screw...")
screw_head_r = 3.0
screw_head_h = 2.0
screw_shaft_r = 1.2
screw_shaft_h = 8.0

screw = Cylinder(screw_head_r, screw_head_r, screw_head_h)
shaft = Pos(0, 0, -(screw_head_h/2 + screw_shaft_h/2)) * Cylinder(screw_shaft_r, screw_shaft_r, screw_shaft_h)
screw = screw + shaft

export_stl(screw, f"{OUT}/screw.stl")
print(f"  -> screw.stl")

# ============================================================
# DONE
# ============================================================
print("\n" + "="*50)
print("ALL FILES GENERATED")
print("="*50)
print(f"\nAssembly:")
print(f"  1. Base plate (posts up)")
print(f"  2. 4 side walls slot into base grooves")
print(f"  3. Lid drops on top")
print(f"  4. 4x M3x8 screws through lid into posts")
print(f"\nSide wall layout:")
print(f"  Front (Y-): side_keystone_dc  (keystone + DC jack)")
print(f"  Back  (Y+): side_smooth_A    (smooth)")
print(f"  Left  (X-): side_smooth_A    (smooth)")
print(f"  Right (X+): side_usb         (mini-USB)")
