Feature: Async Resource Cleanup and Leak Prevention
  As a system operator
  I want async resources to be tracked and closed reliably
  So that the system does not leak connections, tasks, or subscriptions

  Background:
    Given I have an async resource tracker

  Scenario: Registering an async resource and closing it
    Given I have a mock async resource named "db-pool"
    When I register the resource with the tracker
    And I close all tracked resources
    Then the resource "db-pool" should be closed
    And the tracker should have zero open resources

  Scenario: close_all awaits registered resources with timeout
    Given I have 3 mock async resources with varied close times
    When I close all tracked resources with a 5 second timeout
    Then all 3 resources should be closed
    And the tracker should have zero open resources

  Scenario: Leaked resources are logged by name in finalizer
    Given I have a mock async resource named "leaky-conn"
    And I register the resource with the tracker
    When the tracker finalizer runs without close_all
    Then a warning should be logged mentioning "leaky-conn"

  Scenario: Graceful cancellation awaits in-flight tasks before cleanup
    Given I have an async task tracked by the bridge
    When I request graceful cleanup with a 2 second timeout
    Then the task should be cancelled
    And the bridge should have no active tasks

  Scenario: Time-bounded shutdown warns on forced termination
    Given I have a mock async resource named "slow-resource" that takes 5 seconds to close
    And I register the resource with the tracker
    When I close all tracked resources with a 0.1 second timeout
    Then a warning should be logged about forced termination
    And the tracker should report the timed-out resource

  Scenario: Cancelled async jobs persist cancellation reason
    Given I have an async task tracked by the bridge
    When I cancel the task with reason "user-requested-shutdown"
    Then the cancellation reason should be "user-requested-shutdown"

  Scenario: Checkpoint file handles are closed on cleanup
    Given I have a state manager with a temporary checkpoint directory
    When I save a checkpoint and then close the state manager
    Then the checkpoint file should exist and be readable
    And the state manager should be marked as closed

  Scenario: Subscriptions are disposed on cleanup
    Given I have an A2A event queue with 3 active subscriptions
    When I close the event queue
    Then all subscriptions should be removed
    And the subscription count should be zero

  Scenario: Tracker rejects duplicate resource names
    Given I have a mock async resource named "unique-res"
    And I register the resource with the tracker
    When I try to register another resource named "unique-res"
    Then a ValueError should be raised mentioning "unique-res"

  Scenario: Tracker rejects empty resource name
    When I try to register a resource with an empty name
    Then a ValueError should be raised mentioning "name"

  Scenario: Tracker rejects None resource
    When I try to register a None resource with name "valid-name"
    Then a ValueError should be raised mentioning "resource"

  Scenario: Tracker context manager closes resources on exit
    Given I have a mock async resource named "ctx-resource"
    When I use the tracker as an async context manager and register the resource
    Then the resource "ctx-resource" should be closed after exiting the context

  Scenario: close_all is idempotent
    Given I have a mock async resource named "once-resource"
    And I register the resource with the tracker
    When I close all tracked resources twice
    Then the resource "once-resource" should be closed exactly once
    And the tracker should have zero open resources

  Scenario: Enhanced bridge cleanup awaits tasks with timeout
    Given I have a bridge with 2 slow async tasks
    When I run enhanced cleanup with a 2 second timeout
    Then the bridge should have no active tasks
    And completed tasks should be logged

  Scenario: Registering a resource after close_all raises RuntimeError
    Given I have a mock async resource named "late-resource"
    And I register the resource with the tracker
    When I close all tracked resources
    And I try to register a resource named "post-close" after close_all
    Then a RuntimeError should be raised mentioning "closed"

  Scenario: State update after close raises RuntimeError
    Given I have a state manager with a temporary checkpoint directory
    When I close the state manager
    And I try to update state after close
    Then a RuntimeError should be raised mentioning "closed"

  Scenario: State reset after close raises RuntimeError
    Given I have a state manager with a temporary checkpoint directory
    When I close the state manager
    And I try to reset state after close
    Then a RuntimeError should be raised mentioning "closed"

  Scenario: Publish after close raises RuntimeError on A2aEventQueue
    Given I have an A2A event queue with 1 active subscriptions
    When I close the event queue
    And I try to publish an event after close
    Then a RuntimeError should be raised mentioning "closed"

  Scenario: A2aEventQueue exposes is_closed property
    Given I have an A2A event queue with 0 active subscriptions
    Then the event queue is_closed should be False
    When I close the event queue
    Then the event queue is_closed should be True
