Feature: Output Rendering Framework — Registry, Renderer, and Capabilities

  # ================================================================
  # RendererRegistry
  # ================================================================

  Scenario: RendererRegistry registers and resolves built-in formats
    Given the default renderer registry
    Then the registry has format "plain" registered
    And the registry has format "color" registered
    And the registry has format "table" registered
    And the registry has format "rich" registered
    And the registry has format "json" registered
    And the registry has format "yaml" registered

  Scenario: RendererRegistry available_formats returns sorted list
    Given the default renderer registry
    Then the available formats are "color,json,plain,rich,table,yaml"

  Scenario: RendererRegistry is_registered returns False for unknown
    Given the default renderer registry
    Then the registry does not have format "csv" registered

  Scenario: RendererRegistry resolves plain format
    Given the default renderer registry
    When I resolve format "plain" from the registry
    Then the resolved renderer format name is "plain"

  Scenario: RendererRegistry resolves json format
    Given the default renderer registry
    When I resolve format "json" from the registry
    Then the resolved renderer format name is "json"

  Scenario: RendererRegistry resolve falls back from rich to plain on non-TTY
    Given the default renderer registry
    And a non-TTY terminal environment
    When I resolve format "rich" from the registry with terminal caps
    Then the resolved renderer format name is "plain"

  Scenario: RendererRegistry supports custom format registration
    Given a new empty renderer registry
    When I register a custom "csv" format in the registry
    Then the registry has format "csv" registered

  # ================================================================
  # ElementRenderer protocol
  # ================================================================

  Scenario: PlainElementRenderer renders panel element
    Given a PlainElementRenderer
    When I render a panel with title "Test" through the renderer
    Then the renderer output contains "Test"

  Scenario: PlainElementRenderer can_render always returns True
    Given a PlainElementRenderer
    Then the renderer can_render returns True for any terminal

  Scenario: ColorElementRenderer can_render requires ANSI
    Given a ColorElementRenderer
    Then the renderer can_render returns False without ANSI

  Scenario: RichElementRenderer can_render requires cursor movement
    Given a RichElementRenderer
    Then the renderer can_render returns False without cursor movement

  Scenario: JsonElementRenderer serializes output
    Given a JsonElementRenderer
    When I serialize a StructuredOutput through the renderer
    Then the serialized output is valid JSON

  Scenario: YamlElementRenderer serializes output with sorted keys
    Given a YamlElementRenderer
    When I serialize a StructuredOutput through the renderer
    Then the serialized output is valid YAML
    And the serialized output has sorted keys

  # ================================================================
  # TerminalCapabilities extended fields
  # ================================================================

  Scenario: TerminalCapabilities has all 11 spec fields
    When I create a full TerminalCapabilities
    Then the capabilities has width 120
    And the capabilities has height 40
    And the capabilities has supports_256_color True
    And the capabilities has supports_truecolor True
    And the capabilities has supports_unicode True
    And the capabilities has supports_alternate_screen True
    And the capabilities has no_color False
    And the capabilities has term_program "iTerm2"

  Scenario: TerminalCapabilities backward-compatible aliases work
    When I create a full TerminalCapabilities
    Then the capabilities supports_cursor property matches supports_cursor_movement
    And the capabilities term property matches term_program

  # ================================================================
  # ColumnDef.type serialisation
  # ================================================================

  Scenario: ColumnDef serialises type field as "type" in JSON
    Given an OutputSession with format "json" using JsonMaterializer
    When I create a table with ColumnDef objects "Name,Status"
    And I add a dict row with Name "Name" and Status "Alice"
    And I close the table handle
    And the session is closed
    Then the json output is valid JSON
    And the json output ColumnDef uses type key not col_type

  Scenario: ColumnDef accepts type alias in constructor
    When I create a ColumnDef with type alias "integer"
    Then the ColumnDef col_type is "integer"

  # ================================================================
  # YAML sorted keys
  # ================================================================

  Scenario: YAML output uses sorted keys
    Given an OutputSession with format "yaml" using YamlMaterializer
    When I create a panel handle with title "Sort Test"
    And I set entry "Zebra" to "last"
    And I set entry "Alpha" to "first"
    And I close the panel handle
    And the session is closed
    Then the yaml output is valid YAML

  # ================================================================
  # Progress omitted from JSON output
  # ================================================================

  Scenario: JSON output omits progress elements
    Given an OutputSession with format "json" using JsonMaterializer
    When I create a progress handle labelled "Building" with total 100
    And I set progress to 50 of 100
    And I close the progress handle
    And I create a panel handle with title "Info"
    And I set entry "Name" to "test"
    And I close the panel handle
    And the session is closed
    Then the json output is valid JSON
    And the json output does not contain element type "progress"
    And the json output contains element type "panel"

  # ================================================================
  # MaterializationStrategy.bind() method
  # ================================================================

  Scenario: PlainMaterializer has bind method
    Given a PlainMaterializer instance
    When I call bind on the materializer
    Then no error is raised

  Scenario: JsonMaterializer has bind method
    Given a JsonMaterializer instance
    When I call bind on the json materializer
    Then no error is raised

  # ================================================================
  # Render dispatch — concrete renderer methods coverage
  # ================================================================

  Scenario: PlainElementRenderer dispatches all element types via render_element
    Given a PlainElementRenderer
    When I call render_element with each element type
    Then no render dispatch error occurred

  Scenario: PlainElementRenderer serialize assembles rendered text
    Given a PlainElementRenderer
    When I call base serialize with a text element
    Then the base serialized output is a string

  Scenario: ColorElementRenderer dispatches all element types via render_element
    Given a ColorElementRenderer
    When I call render_element with each element type
    Then no render dispatch error occurred

  Scenario: ColorElementRenderer can_render returns True when ANSI is supported
    Given a ColorElementRenderer
    Then color renderer can_render is True with ANSI support

  Scenario: TableElementRenderer can_render checks is_tty flag
    Given a TableElementRenderer
    Then table renderer can_render is True on a TTY terminal
    And table renderer can_render is False on a non-TTY terminal

  Scenario: TableElementRenderer dispatches all element types via render_element
    Given a TableElementRenderer
    When I call render_element with each element type
    Then no render dispatch error occurred

  Scenario: RichElementRenderer dispatches all element types via render_element
    Given a RichElementRenderer
    When I call render_element with each element type
    Then no render dispatch error occurred

  Scenario: RichElementRenderer can_render returns True with cursor movement
    Given a RichElementRenderer
    Then rich renderer can_render is True with cursor movement

  Scenario: JsonElementRenderer dispatches all element types returning empty strings
    Given a JsonElementRenderer
    When I call render_element with each element type
    Then no render dispatch error occurred

  Scenario: YamlElementRenderer dispatches all element types returning empty strings
    Given a YamlElementRenderer
    When I call render_element with each element type
    Then no render dispatch error occurred

  # ================================================================
  # RendererRegistry edge-case paths
  # ================================================================

  Scenario: RendererRegistry resolve unknown format falls back to plain
    Given the default renderer registry
    When I resolve format "unregistered_format" from the registry
    Then the resolved renderer format name is "plain"

  Scenario: RendererRegistry resolve raises ValueError when no plain fallback exists
    Given a registry with no plain and a non-renderable format
    When I try to resolve the non-renderable format
    Then a ValueError is raised from resolve
