#!/usr/bin/env python3
from build123d import *
import os

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

W = 80.0; D = 70.0; H = 50.0
WALL = 2.0
CORNER = 15.0
TOL = 0.15
BASE_H = 32.0; LID_H = 18.0
WIN_W = 14.0
SCREW_R = 1.3

def build_base():
    parts = []
    # 4 corner posts
    for sx in [-1, 1]:
        for sy in [-1, 1]:
            cx = sx * (W/2 - CORNER/2)
            cy = sy * (D/2 - CORNER/2)
            post = Box(CORNER, CORNER, BASE_H)
            hole = Pos(0, 0, 0) * Cylinder(SCREW_R + TOL, SCREW_R + TOL, BASE_H + 0.2)
            post = post - hole
            parts.append(Pos(cx, cy, BASE_H/2) * post)

    # Thin walls between posts
    for sy in [-1, 1]:
        py = sy * (D/2 - WALL/2)
        wall = Pos(0, py, BASE_H/2) * Box(W - 2*CORNER, WALL, BASE_H)
        parts.append(wall)
    for sx in [-1, 1]:
        px = sx * (W/2 - WALL/2)
        wall = Pos(px, 0, BASE_H/2) * Box(WALL, D - 2*CORNER, BASE_H)
        parts.append(wall)

    base = parts[0]
    for p in parts[1:]:
        base += p

    # Cut window openings
    slot_h = BASE_H - 4.0
    slot_gap = 2.0
    for sy in [-1, 1]:
        py = sy * (D/2 - WALL/2)
        sl = W - 2*CORNER - 2*slot_gap
        slot = Pos(0, py, 2.0 + slot_h/2) * Box(sl, WALL + 0.4, slot_h)
        base -= slot
    for sx in [-1, 1]:
        px = sx * (W/2 - WALL/2)
        sl = D - 2*CORNER - 2*slot_gap
        slot = Pos(px, 0, 2.0 + slot_h/2) * Box(WALL + 0.4, sl, slot_h)
        base -= slot

    return base

def build_lid():
    lid = Box(W, D, 2.0)
    # Thin edge walls
    for sx in [-1, 1]:
        lid += Pos(0, sx*(D/2 - WALL/2), 1.5/2) * Box(W, WALL, 1.5)
    for sy in [-1, 1]:
        lid += Pos(sy*(W/2 - WALL/2), 0, 1.5/2) * Box(WALL, D, 1.5)

    # Tongue blocks
    tsize = CORNER - 2.0
    th = 3.0
    for sx in [-1, 1]:
        for sy in [-1, 1]:
            cx = sx * (W/2 - CORNER/2)
            cy = sy * (D/2 - CORNER/2)
            tong = Pos(cx, cy, -th/2) * Box(tsize - TOL, tsize - TOL, th)
            lid += tong

    # Screw holes
    for sx in [-1, 1]:
        for sy in [-1, 1]:
            cx = sx * (W/2 - CORNER/2)
            cy = sy * (D/2 - CORNER/2)
            lid -= Pos(cx, cy, 0) * Cylinder(SCREW_R + TOL, SCREW_R + TOL, LID_H + 0.2)

    # Ribs
    for i in range(3):
        rx = -W/4 + i * W/4
        lid += Pos(rx, 0, -LID_H/2 + 4.0) * Box(1.5, D - 2*CORNER + 5, 8.0)
    for i in range(3):
        ry = -D/4 + i * D/4
        lid += Pos(0, ry, -LID_H/2 + 4.0) * Box(W - 2*CORNER + 5, 1.5, 8.0)

    return lid

def build_window_panel(cutouts=None):
    pw = W - 2*CORNER
    ph = WIN_W + 0.5
    pd = BASE_H - 4.0
    panel = Box(pw, ph, pd)
    for side in [-1, 1]:
        tab = Pos(0, side*(ph/2 - 1.0/2), 0) * Box(pw - 2, 1.0, pd + 0.5)
        panel += tab
    if cutouts:
        for cx, cy, cw, ch in cutouts:
            panel -= Pos(cx, cy, 0) * Box(cw, ch, pd + 0.2)
    return panel

def build_screw():
    s = Cylinder(3.0, 3.0, 2.0)
    s += Pos(0, 0, -5.0) * Cylinder(SCREW_R, SCREW_R, 10.0)
    return s

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

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

print("Building window panels...")
export_stl(build_window_panel(), "%s/window_smooth.stl" % OUT)
print("  -> window_smooth.stl (x2)")

kc = [(-W/4 + 1, 0, 17, 9), (W/4 - 1, 0, 9, 9)]
export_stl(build_window_panel(kc), "%s/window_keystone_dc.stl" % OUT)
print("  -> window_keystone_dc.stl")

usb_c = [(0, 0, 9, 5)]
export_stl(build_window_panel(usb_c), "%s/window_usb.stl" % OUT)
print("  -> window_usb.stl")

print("Building screw...")
export_stl(build_screw(), "%s/screw.stl" % OUT)
print("  -> screw.stl")

print("\nDONE: %.0fx%.0fx%.0fmm" % (W, D, H))
