Feature: Context analysis graph coverage
  As a maintainer
  I want uncovered code paths in the context analysis graph exercised
  So that regression risk is minimised

  Background:
    Given the context analysis graph module is importable
    And I have a fake LLM configured for context analysis graph tests

  @coverage
  Scenario: Agent initialises with an explicitly provided LLM
    When I create a ContextAnalysisAgent with a custom LLM
    Then the agent should use the provided LLM instance
    And the agent should be initialised successfully

  @coverage
  Scenario: Load files discovers missing file paths
    Given I have a ContextAnalysisAgent for graph coverage
    When I call load_files with a nonexistent file path
    Then the returned documents list should be empty
    And the returned error should contain "File not found"

  @coverage
  Scenario: Load files rejects directory paths
    Given I have a ContextAnalysisAgent for graph coverage
    And I have a temporary directory called "not_a_file"
    When I call load_files with the directory path
    Then the returned documents list should be empty
    And the returned error should contain "Not a file"

  @coverage
  Scenario: Load files reads a real file from disk
    Given I have a ContextAnalysisAgent for graph coverage
    And I have a temporary file "real.py" containing "print('hello')"
    When I call load_files with that file path
    Then the returned documents list should have 1 entry
    And the returned error should be empty

  @coverage
  Scenario: Load files combines missing and directory errors
    Given I have a ContextAnalysisAgent for graph coverage
    And I have a temporary directory called "adir"
    When I call load_files with both a missing file and the directory path
    Then the returned documents list should be empty
    And the returned error should contain "File not found"
    And the returned error should contain "Not a file"

  @coverage
  Scenario: Chunking splits documents exceeding chunk size
    Given I have a ContextAnalysisAgent for graph coverage with chunk_size 50 and chunk_overlap 10
    And I have a state with a single document of 140 characters
    When I call chunk_documents on the state
    Then the resulting chunks list should have at least 3 entries
    And every chunk should carry a chunk_index in its metadata

  @coverage
  Scenario: Relevance scoring skips duplicate file chunks
    Given I have a ContextAnalysisAgent for graph coverage
    And I have a state with two chunks from the same source file "dup.py"
    When I call score_relevance on the state
    Then the relevance scores dictionary should contain exactly 1 entry

  @coverage
  Scenario: Relevance parser returns 0.3 for low keyword
    Given I have a ContextAnalysisAgent for graph coverage
    When I parse relevance from the text "low confidence in result"
    Then the parsed relevance score should be 0.3

  @coverage
  Scenario: Relevance parser returns 0.5 for unknown text
    Given I have a ContextAnalysisAgent for graph coverage
    When I parse relevance from the text "undecided outcome"
    Then the parsed relevance score should be 0.5

  @coverage
  Scenario: Async invocation completes the full workflow
    Given I have a ContextAnalysisAgent for graph coverage
    And I have a temporary file "async_test.py" containing "x = 1"
    When I run the workflow asynchronously via ainvoke
    Then the async result should contain a summary
    And the async result should contain documents

  @coverage
  Scenario: Sync streaming produces node-level events
    Given I have a ContextAnalysisAgent for graph coverage
    And I have a temporary file "stream_test.py" containing "y = 2"
    When I stream the workflow synchronously
    Then I should receive at least 1 stream event
    And each stream event should be a dictionary with a node key

  @coverage
  Scenario: Async streaming produces node-level events
    Given I have a ContextAnalysisAgent for graph coverage
    And I have a temporary file "astream_test.py" containing "z = 3"
    When I stream the workflow asynchronously
    Then I should receive at least 1 async stream event
    And each async stream event should be a dictionary with a node key

  @coverage
  Scenario: Agent initialises with default FakeListLLM when no LLM provided
    When I create a ContextAnalysisAgent without providing an LLM
    Then the agent should be initialised successfully
    And the agent LLM should be a FakeListLLM

  @coverage
  Scenario: Sync invoke runs the complete workflow end to end
    Given I have a ContextAnalysisAgent for graph coverage
    And I have a temporary file "invoke_test.py" containing "val = 42"
    When I invoke the workflow synchronously
    Then the sync result should contain a summary
    And the sync result should contain documents

  @coverage
  Scenario: Load files returns preloaded documents unchanged
    Given I have a ContextAnalysisAgent for graph coverage
    And I have a state with preloaded documents
    When I call load_files on the preloaded state
    Then the returned documents should equal the preloaded documents
