#!/usr/bin/env bash
set -euo pipefail

DEVICES_DIR="$(cd "$(dirname "$0")" && pwd)"
ARDUINO_CLI="arduino-cli"
LIBRARIES_DIR="${DEVICES_DIR}"

GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; NC='\033[0m'

ok()   { echo -e "${GREEN}✓${NC} $*"; }
err()  { echo -e "${RED}✗${NC} $*"; }
info() { echo -e "${YELLOW}▸${NC} $*"; }

ERRORS=()

# ─────────────────────────────────────────────
# compile <sketch_dir> <fqbn> <output_dir> [channel_num]
#   channel_num — если передан, патчит CHANNEL_NUM в .ino во временной копии
# ─────────────────────────────────────────────
compile() {
    local sketch_dir="$1"
    local fqbn="$2"
    local output_dir="$3"
    local channel_num="${4:-}"

    local sketch_name
    sketch_name="$(basename "${sketch_dir}")"
    local label="${sketch_name} [${fqbn}]"
    [ -n "${channel_num}" ] && label="${sketch_name} x${channel_num} [${fqbn}]"

    info "Building ${label}..."

    local build_src="${sketch_dir}"

    # Для варианта с нестандартным CHANNEL_NUM — временная копия скетча
    # Папка должна называться как скетч, иначе arduino-cli не найдёт .ino
    local tmp_root=""
    local tmp_dir=""
    if [ -n "${channel_num}" ]; then
        tmp_root="$(mktemp -d)"
        tmp_dir="${tmp_root}/${sketch_name}"
        mkdir "${tmp_dir}"
        find "${sketch_dir}" -maxdepth 1 -type f -exec cp {} "${tmp_dir}/" \;
        local ino_file="${tmp_dir}/${sketch_name}.ino"
        sed -i "s/extern const uint8_t CHANNEL_NUM = [0-9]*/extern const uint8_t CHANNEL_NUM = ${channel_num}/" "${ino_file}"
        build_src="${tmp_dir}"
    fi

    mkdir -p "${output_dir}"

    if ${ARDUINO_CLI} compile \
        --fqbn "${fqbn}" \
        --libraries "${LIBRARIES_DIR}" \
        --output-dir "${output_dir}" \
        "${build_src}" \
        > /tmp/arduino_build.log 2>&1; then
        ok "${label} → ${output_dir}"
    else
        err "${label} — FAILED"
        cat /tmp/arduino_build.log | tail -20
        ERRORS+=("${label}")
    fi

    if [ -n "${tmp_root}" ]; then rm -rf "${tmp_root}"; fi
}

# ─────────────────────────────────────────────
# Targets
# ─────────────────────────────────────────────

echo ""
echo "═══════════════════════════════════════════"
echo "  Smart Home Firmware Build"
echo "═══════════════════════════════════════════"
echo ""

# relay — ESP-01S (esp8266 generic)
compile "${DEVICES_DIR}/relay" \
    "esp8266:esp8266:generic" \
    "${DEVICES_DIR}/relay/build/esp8266.esp8266.generic"

# relay — ESP32-C3
compile "${DEVICES_DIR}/relay" \
    "esp32:esp32:esp32c3" \
    "${DEVICES_DIR}/relay/build/esp32.esp32.esp32c3"

# button — D1 Mini, 2 канала (дефолт)
compile "${DEVICES_DIR}/button" \
    "esp8266:esp8266:d1_mini" \
    "${DEVICES_DIR}/button/build/esp8266.esp8266.d1_mini" \
    2

# button — D1 Mini, 4 канала
compile "${DEVICES_DIR}/button" \
    "esp8266:esp8266:d1_mini" \
    "${DEVICES_DIR}/button/build/esp8266.esp8266.d1_mini_x4" \
    4

# ─────────────────────────────────────────────
# Helpers для релизных пакетов
# ─────────────────────────────────────────────

extract_version() {
    local ino_file="$1"
    grep -oP 'const char\* FW_VERSION = "\K[^"]+' "${ino_file}" 2>/dev/null || echo "0.0.0"
}

create_firmware_package() {
    local src_dir="$1"
    local pkg_name="$2"
    local bin_name="$3"
    local ino_file="$4"
    local platform="$5"
    local channels="$6"

    local dst_dir="${DEVICES_DIR}/builds/${pkg_name}"
    mkdir -p "${dst_dir}"

    cp "${src_dir}/${bin_name}.bin" "${dst_dir}/${bin_name}.bin" 2>/dev/null || true
    cp "${src_dir}/${bin_name}.elf" "${dst_dir}/${bin_name}.elf" 2>/dev/null || true
    cp "${src_dir}/${bin_name}.map" "${dst_dir}/${bin_name}.map" 2>/dev/null || true

    local version
    version="$(extract_version "${ino_file}")"

    local manifest="${dst_dir}/manifest.json"
    cat > "${manifest}" <<EOF
{
  "id": "${pkg_name}",
  "device_type": "${bin_name%.ino}",
  "platform": "${platform}",
  "channels": ${channels},
  "version": "${version}",
  "core_version": "1.5.0",
  "bin_filename": "${bin_name}.bin"
}
EOF

    local zip_path="${DEVICES_DIR}/builds/${pkg_name}.zip"
    (cd "${dst_dir}" && zip -0 "${zip_path}" manifest.json "${bin_name}.bin" >/devdev/null)
    ok "Package ${pkg_name} → ${zip_path}"
}

# ─────────────────────────────────────────────
# Копируем релизные бинари и собираем ZIP
# ─────────────────────────────────────────────

echo ""
info "Creating release packages..."

create_firmware_package \
    "${DEVICES_DIR}/relay/build/esp8266.esp8266.generic" \
    "relay-esp8266-x8" \
    "relay.ino" \
    "${DEVICES_DIR}/relay/relay.ino" \
    "esp8266" \
    8

create_firmware_package \
    "${DEVICES_DIR}/relay/build/esp32.esp32.esp32c3" \
    "relay-esp32-x8" \
    "relay.ino" \
    "${DEVICES_DIR}/relay/relay.ino" \
    "esp32" \
    8

create_firmware_package \
    "${DEVICES_DIR}/button/build/esp8266.esp8266.d1_mini" \
    "button-esp8266-x2" \
    "button.ino" \
    "${DEVICES_DIR}/button/button.ino" \
    "esp8266" \
    2

create_firmware_package \
    "${DEVICES_DIR}/button/build/esp8266.esp8266.d1_mini_x4" \
    "button-esp8266-x4" \
    "button.ino" \
    "${DEVICES_DIR}/button/button.ino" \
    "esp8266" \
    4

# ─────────────────────────────────────────────
# Итог
# ─────────────────────────────────────────────
echo ""
echo "═══════════════════════════════════════════"
if [ ${#ERRORS[@]} -eq 0 ]; then
    ok "All builds succeeded"
else
    err "Failed builds:"
    for e in "${ERRORS[@]}"; do
        echo "    - ${e}"
    done
    exit 1
fi
echo "═══════════════════════════════════════════"
echo ""
