Feature: Materializers coverage boost
  As a developer maintaining the output rendering framework
  I want thorough test coverage on materializer strategies
  So that all code paths including edge cases are verified

  # ---------------------------------------------------------------
  # Scenario 1: Force-flush remaining buffers on session end
  # Targets lines 466-469 in materializers.py (_BaseBufferStrategy.on_session_end)
  # This exercises the path where elements remain in self._buffers
  # because they were closed out of declaration order and the session
  # ends before sequential flushing catches up.
  # ---------------------------------------------------------------

  Scenario: Session end force-flushes out-of-order buffered elements
    Given a PlainMaterializer buffer strategy
    And an OutputSession wired to that buffer strategy
    When I create three panels in declaration order
    And I close only the third and second panels
    And I end the session without closing the first panel
    Then the strategy output includes content from all three panels

  # ---------------------------------------------------------------
  # Scenario 2: Session end with non-empty buffers from skipped indices
  # Also targets lines 466-469 but with a different pattern: element
  # index 0 never closes, so _next_render_index stays at 0 and
  # elements 1 and 2 accumulate in self._buffers.
  # ---------------------------------------------------------------

  Scenario: Session end flushes buffered content when leading element never closes manually
    Given a ColorMaterializer buffer strategy
    And an OutputSession wired to that color buffer strategy
    When I create two status elements in order
    And I close only the second status element
    And the session is closed via context exit
    Then the color strategy output includes both status messages

  # ---------------------------------------------------------------
  # Scenario 3: _render_element_plain fallback for unknown type
  # Targets line 169 (_render_element_plain fallback to str())
  # ---------------------------------------------------------------

  Scenario: Plain renderer falls back to str for unknown element types
    Given an unknown element type object
    When I render it with the plain element dispatcher
    Then the result is the string representation of the object

  # ---------------------------------------------------------------
  # Scenario 4: _render_element_color fallback for unknown type
  # Targets line 269 (_render_element_color fallback to str())
  # ---------------------------------------------------------------

  Scenario: Color renderer falls back to str for unknown element types
    Given an unknown element type object
    When I render it with the color element dispatcher
    Then the color result is the string representation of the object

  # ---------------------------------------------------------------
  # Scenario 5: _element_to_dict fallback for unknown type
  # Targets line 372 (_element_to_dict returns {"type": "unknown"})
  # ---------------------------------------------------------------

  Scenario: Element to dict returns unknown type for unrecognized elements
    Given an unknown element type object
    When I convert it to a dict using element_to_dict
    Then the result dict has type equal to unknown

  # ---------------------------------------------------------------
  # Scenario 6: _BaseBufferStrategy._render_element default
  # Targets line 440 (base class fallback)
  # ---------------------------------------------------------------

  Scenario: Base buffer strategy render_element delegates to plain renderer
    Given a raw BaseBufferStrategy instance
    And a simple Panel element for rendering
    When I call the base strategy render_element with the panel
    Then the rendered output contains the panel title

  # ---------------------------------------------------------------
  # Scenario 7: _AccumulateStrategy._serialise default
  # Targets line 551 (base class returns empty string)
  # ---------------------------------------------------------------

  Scenario: Base accumulate strategy serialise returns empty string
    Given a raw AccumulateStrategy instance
    And a mock StructuredOutput snapshot
    When I call the base strategy serialise method
    Then the result is an empty string

  # ---------------------------------------------------------------
  # Scenario 8: _AccumulateStrategy._serialise_dict default
  # Targets line 576 (base class returns empty string)
  # ---------------------------------------------------------------

  Scenario: Base accumulate strategy serialise_dict returns empty string
    Given a raw AccumulateStrategy instance
    When I call the base strategy serialise_dict with a sample dict
    Then the serialise_dict result is an empty string

  # ---------------------------------------------------------------
  # Scenario 9: on_element_closed with unknown handle_id
  # Targets line 445 (early return when idx is None)
  # ---------------------------------------------------------------

  Scenario: Buffer strategy ignores element closed events for unknown handles
    Given a PlainMaterializer buffer strategy
    And an OutputSession wired to that buffer strategy
    When I dispatch an ElementClosed event with an unknown handle id
    Then the strategy output is empty

  # ---------------------------------------------------------------
  # Scenario 10: TableMaterializer renders non-table element via color
  # Targets _render_element_table delegates to render_element_color
  # (R2-C2 fix #12: table format now uses color for non-table elements)
  # ---------------------------------------------------------------

  Scenario: Table materializer renders status message via color fallback
    Given a TableMaterializer buffer strategy
    And an OutputSession wired to that table buffer strategy
    When I create and close a status element with message "deploy complete" and level "ok"
    Then the table strategy output contains "deploy complete"

  # ---------------------------------------------------------------
  # Scenario 11: Session end with empty buffers (no remaining)
  # Ensures line 465 is hit but loop body (466-469) is skipped
  # when all elements were already flushed
  # ---------------------------------------------------------------

  Scenario: Session end with all elements already flushed does not double-write
    Given a PlainMaterializer buffer strategy
    And an OutputSession wired to that buffer strategy
    When I create and close a panel with title "Already Flushed" and entry "k" "v"
    And the session is ended cleanly
    Then the strategy output contains "Already Flushed" exactly once

  # ---------------------------------------------------------------
  # Scenario 12: RichMaterializer delegates to color renderer
  # Ensures RichMaterializer._render_element hits line 526
  # ---------------------------------------------------------------

  Scenario: Rich materializer renders panel with ANSI color codes
    Given a RichMaterializer buffer strategy
    And an OutputSession wired to that rich buffer strategy
    When I create and close a rich panel with title "Rich Panel" and entry "host" "localhost"
    Then the rich strategy output contains ANSI escape codes
    And the rich strategy output contains "Rich Panel"
