Feature: Virtual Resource Type Base Class and Implementations
  As a developer
  I want to use virtual resources to represent computed/abstract resources
  So that I can work with non-physical resources like metrics and API endpoints

  Background:
    Given I have imported the virtual resource module

  Scenario: Create a basic VirtualResource with valid parameters
    When I create a VirtualResource with:
      | name        | value                          |
      | name        | test-metric                    |
      | description | A test metric resource         |
      | compute_fn  | lambda: 42.0                   |
    Then the VirtualResource should have:
      | name        | value                          |
      | name        | test-metric                    |
      | description | A test metric resource         |
    And the VirtualResource should be callable

  Scenario: Compute a virtual resource value on demand
    Given I have a VirtualResource named "cpu-usage" with compute_fn returning 45.2
    When I compute the virtual resource
    Then the computed value should be 45.2

  Scenario: Reject invalid resource names
    When I try to create a VirtualResource with invalid name "123-invalid"
    Then the virtual resource creation should raise ValueError with message containing "invalid characters"

  Scenario: Reject empty resource names
    When I try to create a VirtualResource with an empty name
    Then the virtual resource creation should raise ValueError with message containing "non-empty string"

  Scenario: Reject non-callable compute functions
    When I try to create a VirtualResource with non-callable compute_fn "not-a-function"
    Then the virtual resource creation should raise TypeError with message containing "callable"

  Scenario: Create a MetricResource with unit
    When I create a MetricResource with:
      | name        | value                          |
      | name        | memory-usage                   |
      | description | Current memory usage           |
      | compute_fn  | lambda: 78.5                   |
      | unit        | percent                        |
    Then the MetricResource should have:
      | name        | value                          |
      | name        | memory-usage                   |
      | description | Current memory usage           |
      | unit        | percent                        |

  Scenario: Compute a MetricResource value
    Given I have a MetricResource named "disk-usage" with compute_fn returning 62.3 and unit "percent"
    When I compute the metric resource
    Then the computed value should be 62.3

  Scenario: Create an APIEndpointResource with URL
    When I create an APIEndpointResource with:
      | name           | value                          |
      | name           | api-data                       |
      | description    | Data from external API         |
      | compute_fn     | lambda: {"status": "ok"}       |
      | endpoint_url   | https://api.example.com/data   |
    Then the APIEndpointResource should have:
      | name           | value                          |
      | name           | api-data                       |
      | description    | Data from external API         |
      | endpoint_url   | https://api.example.com/data   |

  Scenario: Compute an APIEndpointResource value
    Given I have an APIEndpointResource named "api-status" with compute_fn returning {"status": "ok", "code": 200}
    When I compute the API endpoint resource
    Then the API endpoint computed value is a dict with keys "status,code"
    And the API endpoint value["status"] is "ok"
    And the API endpoint value["code"] is "200"

  Scenario: Pass kwargs to compute function
    Given I have a VirtualResource with compute_fn that accepts kwargs
    When I compute the virtual resource with kwargs {"multiplier": 2}
    Then the computed value should reflect the passed kwargs

  Scenario: Virtual resource string representation
    Given I have a VirtualResource named "test-resource" with description "Test resource"
    When I get the string representation of the virtual resource
    Then the string representation should contain "VirtualResource"
    And the string representation should contain "test-resource"
    And the string representation should contain "Test resource"

  Scenario: MetricResource string representation
    Given I have a MetricResource named "cpu-usage" with unit "percent"
    When I get the string representation of the virtual resource
    Then the string representation should contain "MetricResource"
    And the string representation should contain "cpu-usage"
    And the string representation should contain "percent"

  Scenario: APIEndpointResource string representation
    Given I have an APIEndpointResource named "api-data" with endpoint_url "https://api.example.com"
    When I get the string representation of the virtual resource
    Then the string representation should contain "APIEndpointResource"
    And the string representation should contain "api-data"
    And the string representation should contain "https://api.example.com"

  Scenario: Virtual resource with complex compute function
    Given I have a VirtualResource with a complex compute function
    When I compute the virtual resource
    Then the complex computed value should be correct

  Scenario: Multiple virtual resources can coexist
    Given I have created 3 different virtual resources
    When I compute all of them
    Then each should return its expected value
    And they should not interfere with each other

  Scenario: Virtual resource compute function exception handling
    Given I have a VirtualResource with compute_fn that raises an exception
    When I compute the virtual resource
    Then it should raise the exception from compute_fn

  Scenario: Virtual resource with default kwargs
    Given I have a VirtualResource with compute_fn that has default kwargs
    When I compute without providing kwargs
    Then it should use the default values

  Scenario: Virtual resource inheritance
    Given I have created a custom VirtualResource subclass
    When I instantiate and compute it
    Then it should work correctly with the custom implementation
