from pathlib import Path

Import("env")


def patch_nimble_address() -> None:
    libdeps_dir = Path(env.subst("$PROJECT_LIBDEPS_DIR"))
    env_name = env.subst("$PIOENV")
    source_path = libdeps_dir / env_name / "NimBLE-Arduino" / "src" / "NimBLEAddress.cpp"

    if not source_path.exists():
        return

    original = source_path.read_text(encoding="utf-8")
    updated = original

    include_old = '# include <algorithm>\n'
    include_new = '# include <algorithm>\n# include <cstdlib>\n'
    if include_old in updated and "# include <cstdlib>\n" not in updated:
        updated = updated.replace(include_old, include_new, 1)

    call_old = "        uint64_t address = std::stoull(mac, nullptr, 16);"
    call_new = "        uint64_t address = strtoull(mac.c_str(), nullptr, 16);"
    updated = updated.replace(call_old, call_new, 1)

    if updated != original:
        source_path.write_text(updated, encoding="utf-8")
        print("Patched NimBLE-Arduino for legacy ESP32 toolchain compatibility")


def patch_nimble_device() -> None:
    libdeps_dir = Path(env.subst("$PROJECT_LIBDEPS_DIR"))
    env_name = env.subst("$PIOENV")
    source_path = libdeps_dir / env_name / "NimBLE-Arduino" / "src" / "NimBLEDevice.cpp"

    if not source_path.exists():
        return

    original = source_path.read_text(encoding="utf-8")
    updated = original

    updated = updated.replace(
        "    ble_sm_io pkey{.action = BLE_SM_IOACT_INPUT, .passkey = passkey};\n",
        "    ble_sm_io pkey{};\n"
        "    pkey.action = BLE_SM_IOACT_INPUT;\n"
        "    pkey.passkey = passkey;\n",
        1,
    )
    updated = updated.replace(
        "    ble_sm_io pkey{.action = BLE_SM_IOACT_NUMCMP, .numcmp_accept = accept};\n",
        "    ble_sm_io pkey{};\n"
        "    pkey.action = BLE_SM_IOACT_NUMCMP;\n"
        "    pkey.numcmp_accept = accept;\n",
        1,
    )

    if updated != original:
        source_path.write_text(updated, encoding="utf-8")
        print("Patched NimBLEDevice.cpp for legacy ESP32 toolchain compatibility")


def patch_websockets_client() -> None:
    libdeps_dir = Path(env.subst("$PROJECT_LIBDEPS_DIR"))
    env_name = env.subst("$PIOENV")
    source_path = libdeps_dir / env_name / "WebSockets" / "src" / "WebSocketsClient.cpp"

    if not source_path.exists():
        return

    original = source_path.read_text(encoding="utf-8")
    updated = original

    old = (
        "#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 4)\n"
        "                _client.ssl->setCACertBundle(_CA_bundle, _CA_bundle_size);\n"
        "#else\n"
        "                _client.ssl->setCACertBundle(_CA_bundle);\n"
        "#endif\n"
    )
    new = (
        "#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 4)\n"
        "                _client.ssl->setCACertBundle(_CA_bundle, _CA_bundle_size);\n"
        "#else\n"
        "                // Arduino-ESP32 1.x has no CA bundle API; the project only uses\n"
        "                // WebSocketsServer, so keep the client path buildable with insecure TLS.\n"
        "                _client.ssl->setInsecure();\n"
        "#endif\n"
    )
    updated = updated.replace(old, new, 1)

    if updated != original:
        source_path.write_text(updated, encoding="utf-8")
        print("Patched WebSocketsClient.cpp for legacy ESP32 toolchain compatibility")


patch_nimble_address()
patch_nimble_device()
patch_websockets_client()
