@phase1 @domain @repository @resource_repository
Feature: Resource Repository Persistence
  As a system operator managing resources and resource types
  I want the resource repositories to reliably persist and retrieve entries
  So that the resource registry is durable and queryable

  Background:
    Given a clean resource repository database
    And a resource type repository backed by the database
    And a resource repository backed by the database

  # ---------------------------------------------------------------------------
  # ResourceTypeRepository: Creating resource types
  # ---------------------------------------------------------------------------

  @resource_type_create
  Scenario: A new resource type is persisted and retrievable
    Given a valid resource type spec named "myorg/test-type"
    When the resource type is saved through the repository
    Then the resource type repository should not raise an error
    And the persisted resource type should have name "myorg/test-type"

  @resource_type_create @error_handling
  Scenario: Saving a resource type with a duplicate name is rejected
    Given a valid resource type spec named "myorg/dup-type"
    And the resource type has already been saved once
    When a second resource type with the same name "myorg/dup-type" is saved
    Then a DuplicateResourceTypeError should be raised mentioning "myorg/dup-type"

  # ---------------------------------------------------------------------------
  # ResourceTypeRepository: Retrieving resource types
  # ---------------------------------------------------------------------------

  @resource_type_read
  Scenario: A resource type is retrieved by its name
    Given a valid resource type spec named "myorg/lookup-type"
    And the resource type has been saved through the repository
    When the resource type is looked up by name "myorg/lookup-type"
    Then the returned resource type should have name "myorg/lookup-type"

  @resource_type_read
  Scenario: Looking up a non-existent resource type returns nothing
    When the resource type is looked up by name "myorg/does-not-exist"
    Then no resource type should be returned

  # ---------------------------------------------------------------------------
  # ResourceTypeRepository: Listing resource types
  # ---------------------------------------------------------------------------

  @resource_type_list
  Scenario: All resource types are listed in order
    Given resource types "myorg/b-type" and "myorg/a-type" have been saved
    When all resource types are listed
    Then the resource type list should have 2 entries
    And the first resource type in the list should be "myorg/a-type"

  @resource_type_list
  Scenario: Resource types are filtered by namespace
    Given resource types "alpha/type-1" and "beta/type-2" have been saved
    When resource types are listed with namespace "alpha"
    Then the resource type list should have 1 entries
    And the first resource type in the list should be "alpha/type-1"

  @resource_type_list
  Scenario: Resource types are filtered by user_addable flag
    Given a resource type "myorg/addable-type" with user_addable true is saved
    And a resource type "myorg/non-addable" with user_addable false is saved
    When resource types are listed with user_addable true
    Then the resource type list should have 1 entries
    And the first resource type in the list should be "myorg/addable-type"

  # ---------------------------------------------------------------------------
  # ResourceTypeRepository: Updating resource types
  # ---------------------------------------------------------------------------

  @resource_type_update
  Scenario: A resource type description is updated
    Given a valid resource type spec named "myorg/update-type"
    And the resource type has been saved through the repository
    When the resource type description is updated to "New description"
    Then the resource type should be retrievable with description "New description"

  @resource_type_update @error_handling
  Scenario: Updating a non-existent resource type raises error
    When a non-existent resource type "myorg/phantom" is updated
    Then a ResourceTypeNotFoundError should be raised

  # ---------------------------------------------------------------------------
  # ResourceTypeRepository: Deleting resource types
  # ---------------------------------------------------------------------------

  @resource_type_delete
  Scenario: A resource type with no resources is deleted
    Given a valid resource type spec named "myorg/deletable-type"
    And the resource type has been saved through the repository
    When the resource type "myorg/deletable-type" is deleted
    Then the resource type deletion should return true
    And the resource type "myorg/deletable-type" should no longer exist

  @resource_type_delete
  Scenario: Deleting a non-existent resource type returns false
    When the resource type "myorg/phantom" is deleted
    Then the resource type deletion should return false

  @resource_type_delete @error_handling
  Scenario: Deleting a resource type with existing resources is rejected
    Given a valid resource type spec named "myorg/in-use-type"
    And the resource type has been saved through the repository
    And a resource of type "myorg/in-use-type" exists in the database
    When the resource type "myorg/in-use-type" is deleted
    Then a ResourceTypeHasResourcesError should be raised

  # ---------------------------------------------------------------------------
  # ResourceRepository: Creating resources
  # ---------------------------------------------------------------------------

  @resource_create
  Scenario: A new resource is persisted and retrievable
    Given a resource type "myorg/res-type" exists for resource tests
    And a valid resource domain object with name "myorg/test-resource"
    When the resource is saved through the repository
    Then the resource repository should not raise an error
    And the persisted resource should have name "myorg/test-resource"

  @resource_create @error_handling
  Scenario: Creating a resource with invalid type is rejected
    Given a valid resource domain object with type "myorg/nonexistent-type"
    When the resource is saved through the repository
    Then a ResourceTypeNotFoundError should be raised for type "myorg/nonexistent-type"

  @resource_create @error_handling
  Scenario: Creating a resource with duplicate name is rejected
    Given a resource type "myorg/dup-res-type" exists for resource tests
    And a resource with name "myorg/dup-resource" has been saved
    When a second resource with name "myorg/dup-resource" is saved
    Then a DuplicateResourceError should be raised mentioning "myorg/dup-resource"

  # ---------------------------------------------------------------------------
  # ResourceRepository: Retrieving resources
  # ---------------------------------------------------------------------------

  @resource_read
  Scenario: A resource is retrieved by its ULID
    Given a resource type "myorg/get-type" exists for resource tests
    And a resource with known ULID has been saved
    When the resource is looked up by its ULID
    Then the returned resource should have the correct ULID

  @resource_read
  Scenario: A resource is retrieved by its namespaced name
    Given a resource type "myorg/name-type" exists for resource tests
    And a resource with name "myorg/named-resource" has been saved
    When the resource is looked up by name "myorg/named-resource"
    Then the returned resource should have name "myorg/named-resource"

  @resource_read
  Scenario: Looking up a non-existent resource by ULID returns nothing
    When the resource is looked up by ULID "01ZZZZZZZZZZZZZZZZZZZZZZZZ"
    Then no resource should be returned

  @resource_read
  Scenario: Looking up a non-existent resource by name returns nothing
    When the resource is looked up by name "myorg/no-such-resource"
    Then no resource should be returned

  # ---------------------------------------------------------------------------
  # ResourceRepository: Listing resources
  # ---------------------------------------------------------------------------

  @resource_list
  Scenario: Resources are listed with pagination
    Given a resource type "myorg/list-type" exists for resource tests
    And 5 resources of type "myorg/list-type" have been saved
    When resources are listed with limit 3 and offset 0
    Then the resource list should have 3 entries

  @resource_list
  Scenario: Resources are filtered by type_name
    Given resource types "myorg/type-a" and "myorg/type-b" exist for resource tests
    And 2 resources of type "myorg/type-a" have been saved
    And 3 resources of type "myorg/type-b" have been saved
    When resources are listed with type_name "myorg/type-a"
    Then the resource list should have 2 entries

  # ---------------------------------------------------------------------------
  # ResourceRepository: Updating resources
  # ---------------------------------------------------------------------------

  @resource_update
  Scenario: A resource description is updated
    Given a resource type "myorg/upd-type" exists for resource tests
    And a resource with name "myorg/updatable-resource" has been saved
    When the resource description is updated to "Updated description"
    Then the resource should be retrievable with description "Updated description"

  @resource_update @error_handling
  Scenario: Updating a non-existent resource raises error
    When a non-existent resource with ULID "01ZZZZZZZZZZZZZZZZZZZZZZZZ" is updated
    Then a ResourceNotFoundRepoError should be raised

  # ---------------------------------------------------------------------------
  # ResourceRepository: Deleting resources
  # ---------------------------------------------------------------------------

  @resource_delete
  Scenario: A resource with no edges is deleted
    Given a resource type "myorg/del-type" exists for resource tests
    And a resource with name "myorg/deletable-resource" has been saved
    When the resource is deleted by its ULID
    Then the resource deletion should return true
    And the resource should no longer exist

  @resource_delete
  Scenario: Deleting a non-existent resource returns false
    When the resource with ULID "01ZZZZZZZZZZZZZZZZZZZZZZZZ" is deleted
    Then the resource deletion should return false

  @resource_delete @error_handling
  Scenario: Deleting a resource with edges is rejected
    Given a resource type "myorg/edge-type" exists for resource tests
    And a parent and child resource of type "myorg/edge-type" are linked
    When the parent resource is deleted
    Then a ResourceHasEdgesError should be raised

  # ---------------------------------------------------------------------------
  # ResourceRepository: resolve_namespaced_name helper
  # ---------------------------------------------------------------------------

  @resource_resolve
  Scenario: Resolve by name returns the resource
    Given a resource type "myorg/resolve-type" exists for resource tests
    And a resource with name "myorg/resolve-me" has been saved
    When the resource is resolved by name_or_id "myorg/resolve-me"
    Then the resolved resource should have name "myorg/resolve-me"

  @resource_resolve
  Scenario: Resolve by ULID returns the resource
    Given a resource type "myorg/resolve-ulid-type" exists for resource tests
    And a resource with known ULID has been saved for resolve test
    When the resource is resolved by its ULID
    Then the resolved resource should have the correct ULID

  @resource_resolve
  Scenario: Resolve with unknown name returns nothing
    When the resource is resolved by name_or_id "myorg/unknown"
    Then no resolved resource should be returned

  # ---------------------------------------------------------------------------
  # ResourceTypeRepository: domain round-trip
  # ---------------------------------------------------------------------------

  @resource_type_roundtrip
  Scenario: Resource type persists and restores all fields
    Given a full resource type spec with cli_args and capabilities
    When the full resource type is saved and retrieved
    Then the restored resource type should match the original fields
