esphome:
  name: sched-interval-resched

host:
api:
logger:
  level: DEBUG

globals:
  # Counters for each interval
  - id: fast_count
    type: int
    initial_value: "0"
  - id: medium_count
    type: int
    initial_value: "0"
  - id: slow_count
    type: int
    initial_value: "0"
  # Track interval that cancels itself
  - id: self_cancel_count
    type: int
    initial_value: "0"
  # Track interval that schedules a timeout from its callback
  - id: callback_timeout_fired
    type: bool
    initial_value: "false"
  # Track set_interval replacing itself from within callback
  - id: replace_count
    type: int
    initial_value: "0"
  - id: replaced_count
    type: int
    initial_value: "0"

interval:
  # Fast interval: 50ms
  - interval: 50ms
    then:
      - lambda: |-
          id(fast_count) += 1;
          if (id(fast_count) == 10) {
            ESP_LOGI("test", "FAST_10_REACHED");
          }

  # Medium interval: 100ms
  - interval: 100ms
    then:
      - lambda: |-
          id(medium_count) += 1;
          if (id(medium_count) == 5) {
            ESP_LOGI("test", "MEDIUM_5_REACHED fast_count=%d", id(fast_count));
          }

  # Slow interval: 200ms
  - interval: 200ms
    then:
      - lambda: |-
          id(slow_count) += 1;
          if (id(slow_count) == 3) {
            ESP_LOGI("test", "SLOW_3_REACHED fast_count=%d medium_count=%d", id(fast_count), id(medium_count));
          }

  # Interval that cancels itself after 3 fires
  - interval: 75ms
    id: self_cancelling
    then:
      - lambda: |-
          id(self_cancel_count) += 1;
          ESP_LOGI("test", "SELF_CANCEL_FIRE count=%d", id(self_cancel_count));
          if (id(self_cancel_count) >= 3) {
            id(self_cancelling)->stop_poller();
            ESP_LOGI("test", "SELF_CANCEL_STOPPED");
          }

  # Interval that schedules a timeout from its callback (tests to_add_ path)
  - interval: 150ms
    id: timeout_creator
    then:
      - lambda: |-
          if (!id(callback_timeout_fired)) {
            // Schedule a one-shot timeout from within an interval callback
            // This goes through to_add_ (not the direct push_heap path)
            id(timeout_creator)->set_timeout("test_timeout", 10, []() {
              id(callback_timeout_fired) = true;
              ESP_LOGI("test", "CALLBACK_TIMEOUT_FIRED");
            });
            // Stop this interval after scheduling the timeout
            id(timeout_creator)->stop_poller();
          }

  # Interval that calls set_interval with the same name from within its callback,
  # replacing itself. Tests that the old item (marked removed) is not rescheduled
  # via push_heap, and the new item goes through to_add_ correctly.
  - interval: 60ms
    id: replace_test
    then:
      - lambda: |-
          id(replace_count) += 1;
          if (id(replace_count) == 1) {
            ESP_LOGI("test", "REPLACE_ORIGINAL_FIRE");
            // Replace the polling interval with a named interval on the same component
            id(replace_test)->set_interval("replaced_interval", 80, []() {
              id(replaced_count) += 1;
              ESP_LOGI("test", "REPLACED_FIRE count=%d", id(replaced_count));
              if (id(replaced_count) >= 3) {
                id(replace_test)->cancel_interval("replaced_interval");
                ESP_LOGI("test", "REPLACED_STOPPED");
              }
            });
            // Stop the original polling interval
            id(replace_test)->stop_poller();
          }
