# Klubhaus Doorbell - justfile
# Run with: just <recipe>
# Set BOARD: just BOARD=esp32-32e-4 compile

# Default recipe - show help
default:
    @just --list

# Default BOARD — overridable via env var or CLI: BOARD=uno-r4-wifi just compile
BOARD := env_var_or_default('BOARD', 'esp32-s3-lcd-43')

# Helper to source board config
# just passes args as positional, so we source in each recipe

# Build token header for -include (generated fresh each compile)
BUILD_TOKEN_HEADER := "/tmp/doorbell-build-token.h"

# Compile firmware
compile:
    #!/usr/bin/env bash
    set -e
    source ./boards/{{BOARD}}/board-config.sh
    
    BUILD_TOKEN=$(git describe --always --dirty 2>/dev/null || echo "unknown")
    echo "#pragma once" > /tmp/doorbell-build-token.h
    echo "#define BUILD_TOKEN \"$BUILD_TOKEN\"" >> /tmp/doorbell-build-token.h
    echo "Build token: $BUILD_TOKEN"
    
    CFLAGS="$OPTS -include /tmp/doorbell-build-token.h"
    
    # Only regenerate compile_commands.json if needed (board changed or first run)
    NEED_GEN=false
    if [ ! -f compile_commands.json ]; then
        NEED_GEN=true
    elif [ ! -f .board-last ] || [ "$(cat .board-last)" != "{{BOARD}}" ]; then
        NEED_GEN=true
    fi
    
    if [ "$NEED_GEN" = "true" ]; then
        rm -rf /tmp/arduino-build
        arduino-cli compile --only-compilation-database --fqbn "$FQBN" --libraries ./libraries $LIBS --build-property "compiler.cpp.extra_flags=$CFLAGS" --build-path /tmp/arduino-build ./boards/{{BOARD}}
        cp /tmp/arduino-build/compile_commands.json .
        echo "{{BOARD}}" > .board-last
        echo "[OK] Generated compile_commands.json for {{BOARD}}"
    else
        echo "[SKIP] compile_commands.json already up to date for {{BOARD}}"
    fi
    
    arduino-cli compile --fqbn "$FQBN" --libraries ./libraries $LIBS --build-property "compiler.cpp.extra_flags=$CFLAGS" --warnings default ./boards/{{BOARD}}

# Upload firmware
upload: kill
    #!/usr/bin/env bash
    set -e
    source ./boards/{{BOARD}}/board-config.sh
    arduino-cli upload --fqbn "$FQBN" --port "$PORT" ./boards/{{BOARD}}

# Kill processes using serial port
kill:
    #!/usr/bin/env bash
    set +e
    source ./boards/{{BOARD}}/board-config.sh
    PORT="${PORT:-$PORT}"
    echo "Killing processes on $PORT..."
    fuser -k "$PORT" 2>/dev/null || true
    for pid in $(pgrep -f "monitor-agent.py.*{{BOARD}}" 2>/dev/null || true); do
        echo "Killing monitor-agent.py (PID: $pid)..."
        kill "$pid" 2>/dev/null || true
    done
    rm -f "/tmp/doorbell-{{BOARD}}.lock" 2>/dev/null || true
    sleep 1
    echo "[OK] Killed processes for {{BOARD}}"

# Monitor raw serial
monitor-raw: kill
    #!/usr/bin/env bash
    source ./boards/{{BOARD}}/board-config.sh
    PORT="${PORT:-$PORT}"
    TARGET="$(readlink -f "$PORT" 2>/dev/null || echo "$PORT")"
    arduino-cli monitor -p "$TARGET" --config baudrate=115200

# Show tio command
monitor-tio: kill
    #!/usr/bin/env bash
    source ./boards/{{BOARD}}/board-config.sh
    PORT="${PORT:-$PORT}"
    TARGET="$(readlink -f "$PORT" 2>/dev/null || echo "$PORT")"
    echo "Run: tio --map INLCRNL $TARGET -e"

# Monitor with JSON logging (runs in background)
monitor: kill
    #!/usr/bin/env bash
    nohup python3 ./scripts/monitor-agent.py "{{BOARD}}" > /dev/null 2>&1 &
    PID=$!
    echo "Monitor agent started for {{BOARD}} (PID: $PID)"
    echo "  Log:    /tmp/doorbell-{{BOARD}}.jsonl"
    echo "  State:  /tmp/doorbell-{{BOARD}}-state.json"
    echo "  Cmd:    echo 'dashboard' > /tmp/doorbell-{{BOARD}}-cmd.fifo"
    echo "  Stop:   kill $PID"

# Tail colored logs
watch:
    #!/usr/bin/env bash
    tail -f "/tmp/doorbell-{{BOARD}}.jsonl" | while read -r line; do
        ts=$(echo "$line" | python3 -c "import sys,json; print(json.load(sys.stdin)['ts'])" 2>/dev/null)
        txt=$(echo "$line" | python3 -c "import sys,json; print(json.load(sys.stdin)['line'])" 2>/dev/null)
        if [[ "$txt" == *"[STATE]"* ]]; then
            echo -e "\033[1;35m[$ts]\033[0m $txt"
        elif [[ "$txt" == *"[ADMIN]"* ]]; then
            echo -e "\033[1;36m[$ts]\033[0m $txt"
        elif [[ "$txt" == *"[TOUCH]"* ]]; then
            echo -e "\033[1;33m[$ts]\033[0m $txt"
        elif [[ "$txt" == *"ALERT"* ]]; then
            echo -e "\033[1;31m[$ts]\033[0m $txt"
        else
            echo "[$ts] $txt"
        fi
    done

# Send command to device
cmd command:
    #!/usr/bin/env bash
    echo -n "{{command}}" > "/tmp/doorbell-{{BOARD}}-cmd.fifo"
    echo "[SENT] {{command}}"

# Show device state
state:
    @cat "/tmp/doorbell-{{BOARD}}-state.json"

# Detect connected board
detect:
    #!/usr/bin/env bash
    bash ./scripts/detect-device.sh

# Install shared libraries
install-libs-shared:
    #!/usr/bin/env bash
    ./scripts/install-shared.sh

# Install all libraries
install: install-libs-shared
    #!/usr/bin/env bash
    if [ -f ./boards/{{BOARD}}/install.sh ]; then
        ./boards/{{BOARD}}/install.sh
        arduino-cli core install esp32:esp32
    else
        echo "[SKIP] No board-specific install script for {{BOARD}}"
    fi

# Full build-compile-monitor loop
full: compile upload monitor
    @just watch

# Clean build artifacts
clean:
    #!/usr/bin/env bash
    rm -rf vendor/
    rm -rf .cache/
    rm -rf boards/*/build/
    rm -f .board-last
    rm -f /tmp/doorbell-build-token.h
    echo "[OK] Build artifacts cleaned"

# Clean temporary files (monitor logs, FIFOs, state files)
clean-temp:
    #!/usr/bin/env bash
    rm -f /tmp/doorbell-*.jsonl /tmp/doorbell-*-state.json /tmp/doorbell-*-cmd.fifo
    rm -f .board-last
    echo "[OK] Temp files cleaned"

# Clean Arduino cache
arduino-clean:
    #!/usr/bin/env bash
    echo "Checking ~/.arduino15..."
    du -sh ~/.arduino15/staging 2>/dev/null || echo "No staging folder"
    du -sh ~/.arduino15/packages 2>/dev/null || echo "No packages folder"
    read -p "Delete staging + packages folders? [y/N] " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        rm -rf ~/.arduino15/staging
        rm -rf ~/.arduino15/packages
        echo "[OK] Arduino staging + packages cleared"
    else
        echo "Aborted"
    fi

# Format code
format:
    #!/usr/bin/env bash
    clang-format -i --style=file \
        boards/esp32-32e/*.cpp \
        boards/esp32-32e/*.h \
        boards/esp32-32e/*.ino \
        boards/esp32-32e-4/*.cpp \
        boards/esp32-32e-4/*.h \
        boards/esp32-32e-4/*.ino \
        boards/esp32-s3-lcd-43/*.cpp \
        boards/esp32-s3-lcd-43/*.h \
        boards/esp32-s3-lcd-43/*.ino \
        boards/uno-r4-wifi/*.cpp \
        boards/uno-r4-wifi/*.h \
        boards/uno-r4-wifi/*.ino \
        libraries/KlubhausCore/src/*.cpp \
        libraries/KlubhausCore/src/*.h \
        libraries/KlubhausCore/*.properties

# Generate compile_commands.json for LSP (no full compile)
gen-compile-commands:
    #!/usr/bin/env bash
    set -e
    source ./boards/{{BOARD}}/board-config.sh
    BUILD_TOKEN=$(git describe --always --dirty 2>/dev/null || echo "unknown")
    echo "#pragma once" > /tmp/doorbell-build-token.h
    echo "#define BUILD_TOKEN \"$BUILD_TOKEN\"" >> /tmp/doorbell-build-token.h
    CFLAGS="$OPTS -include /tmp/doorbell-build-token.h"
    rm -rf /tmp/arduino-build
    arduino-cli compile --only-compilation-database --fqbn "$FQBN" --libraries ./libraries $LIBS --build-property "compiler.cpp.extra_flags=$CFLAGS" --build-path /tmp/arduino-build ./boards/{{BOARD}}
    cp /tmp/arduino-build/compile_commands.json .
    echo "{{BOARD}}" > .board-last
    rm -f /tmp/doorbell-build-token.h
    echo "[OK] Generated compile_commands.json for {{BOARD}}"

# Generate crush config
gen-crush-config:
    #!/usr/bin/env bash
    set -e
    source ./boards/{{BOARD}}/board-config.sh
    printf '{\n  "lsp": {\n    "arduino": {\n      "command": "arduino-language-server",\n      "args": ["-fqbn", "%s"]\n    },\n    "cpp": {\n      "command": "clangd"\n    }\n  }\n}\n' "$FQBN" > .crush.json
    echo "[OK] Generated .crush.json with FQBN: $FQBN"
