esphome:
  debug_scheduler: true  # Enable scheduler leak detection
  name: scheduler-internal-id-test
  on_boot:
    priority: -100
    then:
      - logger.log: "Starting scheduler internal ID collision tests"

host:
api:
logger:
  level: VERBOSE

globals:
  - id: tests_done
    type: bool
    initial_value: 'false'

script:
  - id: test_internal_id_no_collision
    then:
      - logger.log: "Testing NUMERIC_ID_INTERNAL vs NUMERIC_ID isolation"
      - lambda: |-
          // All tests use the same component and the same uint32_t value (0).
          // NUMERIC_ID_INTERNAL and NUMERIC_ID are separate NameType values,
          // so the scheduler must treat them as independent timers.
          auto *comp = id(test_sensor);

          // ---- Test 1: Both timeout types fire independently ----
          // Set an internal timeout with ID 0
          App.scheduler.set_timeout(comp, InternalSchedulerID{0}, 50, []() {
            ESP_LOGI("test", "Internal timeout 0 fired");
          });
          // Set a component numeric timeout with the same ID 0
          App.scheduler.set_timeout(comp, 0U, 50, []() {
            ESP_LOGI("test", "Numeric timeout 0 fired");
          });

          // ---- Test 2: Cancelling numeric ID does NOT cancel internal ID ----
          // Set an internal timeout with ID 1
          App.scheduler.set_timeout(comp, InternalSchedulerID{1}, 100, []() {
            ESP_LOGI("test", "Internal timeout 1 survived cancel");
          });
          // Set a numeric timeout with the same ID 1
          App.scheduler.set_timeout(comp, 1U, 100, []() {
            ESP_LOGE("test", "ERROR: Numeric timeout 1 should have been cancelled");
          });
          // Cancel only the numeric one
          App.scheduler.cancel_timeout(comp, 1U);

          // ---- Test 3: Cancelling internal ID does NOT cancel numeric ID ----
          // Set a numeric timeout with ID 2
          App.scheduler.set_timeout(comp, 2U, 150, []() {
            ESP_LOGI("test", "Numeric timeout 2 survived cancel");
          });
          // Set an internal timeout with the same ID 2
          App.scheduler.set_timeout(comp, InternalSchedulerID{2}, 150, []() {
            ESP_LOGE("test", "ERROR: Internal timeout 2 should have been cancelled");
          });
          // Cancel only the internal one
          App.scheduler.cancel_timeout(comp, InternalSchedulerID{2});

          // ---- Test 4: Both interval types fire independently ----
          static int internal_interval_count = 0;
          static int numeric_interval_count = 0;
          App.scheduler.set_interval(comp, InternalSchedulerID{3}, 100, []() {
            internal_interval_count++;
            if (internal_interval_count == 2) {
              ESP_LOGI("test", "Internal interval 3 fired twice");
              App.scheduler.cancel_interval(id(test_sensor), InternalSchedulerID{3});
            }
          });
          App.scheduler.set_interval(comp, 3U, 100, []() {
            numeric_interval_count++;
            if (numeric_interval_count == 2) {
              ESP_LOGI("test", "Numeric interval 3 fired twice");
              App.scheduler.cancel_interval(id(test_sensor), 3U);
            }
          });

          // ---- Test 5: String name does NOT collide with internal ID ----
          // Use string name and internal ID 10 on same component
          App.scheduler.set_timeout(comp, "collision_test", 200, []() {
            ESP_LOGI("test", "String timeout collision_test fired");
          });
          App.scheduler.set_timeout(comp, InternalSchedulerID{10}, 200, []() {
            ESP_LOGI("test", "Internal timeout 10 fired");
          });

          // Log completion after all timers should have fired
          App.scheduler.set_timeout(comp, 9999U, 1500, []() {
            ESP_LOGI("test", "All collision tests complete");
          });

sensor:
  - platform: template
    name: Test Sensor
    id: test_sensor
    lambda: return 1.0;
    update_interval: never

interval:
  - interval: 0.1s
    then:
      - if:
          condition:
            lambda: 'return id(tests_done) == false;'
          then:
            - lambda: 'id(tests_done) = true;'
            - script.execute: test_internal_id_no_collision
