"""Tests for markdown generation."""
# pyright: reportPrivateUsage=false

import re
from datetime import date

import pytest

from mouc import styling
from mouc.backends import MarkdownBackend
from mouc.document import DocumentGenerator
from mouc.models import Entity, FeatureMap, FeatureMapMetadata
from mouc.parser import resolve_graph_edges
from mouc.scheduler.core import ScheduleAnnotations
from mouc.unified_config import MarkdownConfig, OrganizationConfig
from tests.conftest import deps


def create_generator(feature_map: FeatureMap, config: MarkdownConfig | None = None) -> str:
    """Helper to create markdown output from a feature map."""
    styling_context = styling.create_styling_context(feature_map)
    backend = MarkdownBackend(feature_map, styling_context)
    generator = DocumentGenerator(feature_map, backend, config)
    result = generator.generate()
    assert isinstance(result, str), "MarkdownBackend should return a string"
    return result


class TestMarkdownGenerator:
    """Test the markdown document generator."""

    @pytest.fixture
    def simple_feature_map(self) -> FeatureMap:
        """Create a simple feature map for testing."""
        metadata = FeatureMapMetadata(
            version="1.0",
            team="test_team",
            last_updated="2024-01-15",
        )

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Description of capability 1.",
            tags=["infra"],
            links=[
                "[DD-123](https://example.com/dd123)",
                "jira:JIRA-456",
            ],
        )
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Description of capability 2.",
            requires=deps("cap1"),
        )

        story1 = Entity(
            type="user_story",
            id="story1",
            name="Story 1",
            description="Description of story 1.",
            requires=deps("cap2"),
            tags=["urgent"],
            meta={"requestor": "team_alpha"},
        )

        outcome1 = Entity(
            type="outcome",
            id="outcome1",
            name="Outcome 1",
            description="Description of outcome 1.",
            requires=deps("story1"),
            meta={"target_date": "2024-Q3"},
        )

        entities = [cap1, cap2, story1, outcome1]
        resolve_graph_edges(entities)

        return FeatureMap(
            metadata=metadata,
            entities=entities,
        )

    def test_generate_header(self, simple_feature_map: FeatureMap) -> None:
        """Test header generation."""
        markdown = create_generator(simple_feature_map)

        assert "# Feature Map" in markdown
        assert "| Team | test_team |" in markdown
        assert "| Last Updated | 2024-01-15 |" in markdown
        assert "| Version | 1.0 |" in markdown

    def test_generate_toc(self, simple_feature_map: FeatureMap) -> None:
        """Test table of contents generation."""
        # Use by_type organization to get type-based sections
        config = MarkdownConfig(organization=OrganizationConfig(primary="by_type"))
        markdown = create_generator(simple_feature_map, config)

        assert "## Table of Contents" in markdown
        assert "### Capabilities" in markdown
        assert "- [Cap 1](#cap-1)" in markdown
        assert "- [Cap 2](#cap-2)" in markdown
        assert "### User Stories" in markdown
        assert "- [Story 1](#story-1)" in markdown
        assert "### Outcomes" in markdown
        assert "- [Outcome 1](#outcome-1)" in markdown

    def test_generate_capabilities_section(self, simple_feature_map: FeatureMap) -> None:
        """Test capabilities section generation."""
        # Use by_type organization to get type-based sections
        config = MarkdownConfig(organization=OrganizationConfig(primary="by_type"))
        markdown = create_generator(simple_feature_map, config)

        assert "## Capabilities" in markdown
        assert "### Cap 1" in markdown
        assert "Description of capability 1." in markdown
        assert "| Id | `cap1` |" in markdown
        assert "| Tags | `infra` |" in markdown

        # Check links formatting - the Link parser treats markdown links as plain links
        assert "| Link | [DD-123](https://example.com/dd123) |" in markdown
        assert "| Jira | `JIRA-456` |" in markdown

        # Check dependencies
        assert "### Cap 2" in markdown
        assert "#### Requires" in markdown
        assert "- [Cap 1](#cap-1) (`cap1`)" in markdown

    def test_generate_user_stories_section(self, simple_feature_map: FeatureMap) -> None:
        """Test user stories section generation."""
        # Use by_type organization to get type-based sections
        config = MarkdownConfig(organization=OrganizationConfig(primary="by_type"))
        markdown = create_generator(simple_feature_map, config)

        assert "## User Stories" in markdown
        assert "### Story 1" in markdown
        assert "| Requestor | team_alpha |" in markdown
        assert "#### Requires" in markdown
        assert "- [Cap 2](#cap-2) (`cap2`)" in markdown

    def test_generate_outcomes_section(self, simple_feature_map: FeatureMap) -> None:
        """Test outcomes section generation."""
        # Use by_type organization to get type-based sections
        config = MarkdownConfig(organization=OrganizationConfig(primary="by_type"))
        markdown = create_generator(simple_feature_map, config)

        assert "## Outcomes" in markdown
        assert "### Outcome 1" in markdown
        assert "#### Requires" in markdown
        assert "- [Story 1](#story-1) (`story1`) [User Story]" in markdown

    def test_dependency_tracking(self) -> None:
        """Test that dependencies and dependents are tracked correctly."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(type="capability", id="cap1", name="Cap 1", description="Desc")
        cap2 = Entity(
            type="capability", id="cap2", name="Cap 2", description="Desc", requires=deps("cap1")
        )
        cap3 = Entity(
            type="capability", id="cap3", name="Cap 3", description="Desc", requires=deps("cap1")
        )
        story1 = Entity(
            type="user_story",
            id="story1",
            name="Story 1",
            description="Desc",
            requires=deps("cap2", "cap3"),
        )

        entities = [cap1, cap2, cap3, story1]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        markdown = create_generator(feature_map)

        # Check that cap1 shows it's required by cap2 and cap3
        cap1_section = markdown[markdown.find("### Cap 1") : markdown.find("### Cap 2")]
        assert "#### Enables" in cap1_section
        assert "- [Cap 2](#cap-2) (`cap2`)" in cap1_section
        assert "- [Cap 3](#cap-3) (`cap3`)" in cap1_section

        # Check that story1 shows dependencies on both caps
        story1_section = markdown[markdown.find("### Story 1") :]
        assert "- [Cap 2](#cap-2) (`cap2`) [Capability]" in story1_section
        assert "- [Cap 3](#cap-3) (`cap3`) [Capability]" in story1_section

    def test_anchor_generation(self) -> None:
        """Test that anchors are generated correctly."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="complex_id_123",
            name="Complex Name with Special Chars!",
            description="Desc",
        )

        entities = [cap1]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        # Create backend to test anchor generation
        styling_context = styling.create_styling_context(feature_map)
        backend = MarkdownBackend(feature_map, styling_context)

        # Test the anchor generation
        anchor = backend.make_anchor("complex_id_123", "Complex Name with Special Chars!")
        assert anchor == "complex-name-with-special-chars"

        # Test with simple text
        anchor2 = backend.make_anchor("", "non existent")
        assert anchor2 == "non-existent"

    def test_empty_sections(self) -> None:
        """Test that empty sections are not generated."""
        metadata = FeatureMapMetadata()

        # Only capabilities, no stories or outcomes
        cap1 = Entity(type="capability", id="cap1", name="Cap 1", description="Desc")

        entities = [cap1]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        # Use by_type organization to get type-based sections
        config = MarkdownConfig(organization=OrganizationConfig(primary="by_type"))
        markdown = create_generator(feature_map, config)

        assert "## Capabilities" in markdown
        assert "## User Stories" not in markdown
        assert "## Outcomes" not in markdown

    def test_timeline_generation(self) -> None:
        """Test timeline section generation."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            meta={"timeframe": "2024-Q1"},
        )
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            requires=deps("cap1"),
            meta={"timeframe": "2024-Q2"},
        )
        cap3 = Entity(
            type="capability",
            id="cap3",
            name="Cap 3",
            description="Desc",
            meta={"timeframe": "2024-Q1"},
        )
        story1 = Entity(
            type="user_story",
            id="story1",
            name="Story 1",
            description="Desc",
            requires=deps("cap2"),
        )

        entities = [cap1, cap2, cap3, story1]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        markdown = create_generator(feature_map)

        # Check timeline section exists (inside TOC)
        assert "### Timeline" in markdown

        # Check timeframes are in lexical order
        assert markdown.find("#### 2024-Q1") < markdown.find("#### 2024-Q2")

        # Check entities are grouped by timeframe in timeline section
        # Timeline is now inside the TOC between "### Timeline" and the first body section
        toc_start = markdown.find("## Table of Contents")
        body_start = markdown.find("## Capabilities", toc_start)
        timeline_section = markdown[toc_start:body_start]

        # In 2024-Q1 section
        assert "[Cap 1](#cap-1) [Capability]" in timeline_section
        assert "[Cap 3](#cap-3) [Capability]" in timeline_section

        # In 2024-Q2 section
        assert "[Cap 2](#cap-2) [Capability]" in timeline_section

        # Unscheduled section
        assert "#### Unscheduled" in timeline_section
        assert "[Story 1](#story-1) [User Story]" in timeline_section

    def test_no_timeline_when_no_timeframes(self) -> None:
        """Test that timeline section is not generated when no entities have timeframes."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(type="capability", id="cap1", name="Cap 1", description="Desc")
        story1 = Entity(type="user_story", id="story1", name="Story 1", description="Desc")

        entities = [cap1, story1]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        markdown = create_generator(feature_map)

        # No timeline section should be generated
        assert "## Timeline" not in markdown

    def test_metadata_display_all_fields(self) -> None:
        """Test that all metadata fields are displayed in entity sections."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            meta={
                "requestor": "team_alpha",
                "timeframe": "2024-Q1",
                "priority": "high",
                "cost_estimate": 50000,
                "custom_field": "custom_value",
            },
        )

        entities = [cap1]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        markdown = create_generator(feature_map)

        # Check all metadata fields are displayed
        cap1_section = markdown[markdown.find("### Cap 1") :]
        assert "| Requestor | team_alpha |" in cap1_section
        assert "| Timeframe | 2024-Q1 |" in cap1_section
        assert "| Priority | high |" in cap1_section
        assert "| Cost Estimate | 50000 |" in cap1_section
        assert "| Custom Field | custom_value |" in cap1_section

    def test_backward_dependency_warnings(self) -> None:
        """Test detection and display of backward dependencies in timeline."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            requires=deps("cap2"),  # Depends on something in the future
            meta={"timeframe": "2024-Q1"},
        )
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            meta={"timeframe": "2024-Q2"},
        )
        story1 = Entity(
            type="user_story",
            id="story1",
            name="Story 1",
            description="Desc",
            requires=deps("cap2"),
            meta={"timeframe": "2024-Q1"},  # Also backward dependency
        )

        entities = [cap1, cap2, story1]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        markdown = create_generator(feature_map)

        # Check warning section exists
        assert "## ⚠️ Timeline Warnings" in markdown
        assert "The following dependencies go backward in timeline order:" in markdown

        # Check specific warnings
        assert "`Cap 1` (2024-Q1) depends on `Cap 2` (2024-Q2)" in markdown
        assert "`Story 1` (2024-Q1) depends on `Cap 2` (2024-Q2)" in markdown

    def test_no_warnings_when_dependencies_correct(self) -> None:
        """Test that no warnings are shown when dependencies follow timeline order."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            meta={"timeframe": "2024-Q1"},
        )
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            requires=deps("cap1"),  # Correct order
            meta={"timeframe": "2024-Q2"},
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        markdown = create_generator(feature_map)

        # No warning section should be generated
        assert "## ⚠️ Timeline Warnings" not in markdown

    def test_backward_dependency_console_output(self, capsys: pytest.CaptureFixture[str]) -> None:
        """Test that backward dependencies print warnings to console."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            requires=deps("cap2"),  # Backward dependency
            meta={"timeframe": "2024-Q1"},
        )
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            meta={"timeframe": "2024-Q2"},
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        # Generating the document triggers console warnings
        create_generator(feature_map)

        # Check console output
        captured = capsys.readouterr()
        assert "WARNING: Backward dependency" in captured.err
        assert "Cap 1" in captured.err
        assert "2024-Q1" in captured.err
        assert "Cap 2" in captured.err
        assert "2024-Q2" in captured.err

    def test_scheduled_depending_on_unscheduled_is_backward(self) -> None:
        """Test that scheduled entities depending on unscheduled entities are flagged."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            # No timeframe - unscheduled
        )
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            requires=deps("cap1"),  # Scheduled depending on unscheduled
            meta={"timeframe": "2024-Q2"},
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        markdown = create_generator(feature_map)

        # Check warning section exists
        assert "## ⚠️ Timeline Warnings" in markdown
        assert "`Cap 2` (2024-Q2) depends on `Cap 1` (Unscheduled)" in markdown

    def test_unscheduled_depending_on_scheduled_is_ok(self) -> None:
        """Test that unscheduled entities can depend on scheduled entities without warning."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            meta={"timeframe": "2024-Q1"},
        )
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            requires=deps("cap1"),  # Unscheduled depending on scheduled - OK
            # No timeframe
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        markdown = create_generator(feature_map)

        # No warning section should be generated
        assert "## ⚠️ Timeline Warnings" not in markdown

    def test_unscheduled_depending_on_unscheduled_is_ok(self) -> None:
        """Test that unscheduled entities depending on other unscheduled entities is OK."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            # No timeframe
        )
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            requires=deps("cap1"),  # Unscheduled depending on unscheduled - OK
            # No timeframe
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        markdown = create_generator(feature_map)

        # No warning section should be generated
        assert "## ⚠️ Timeline Warnings" not in markdown

    def test_backward_dependency_uses_scheduler_annotations(self) -> None:
        """Test that scheduler estimated_end is used for backward dependency checking."""
        metadata = FeatureMapMetadata()

        # cap1 finishes later (March) according to scheduler
        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            # No manual timeframe - will use scheduler
        )
        cap1.annotations["schedule"] = ScheduleAnnotations(
            estimated_start=date(2025, 3, 1),
            estimated_end=date(2025, 3, 15),
            computed_deadline=None,
            computed_priority=None,
            deadline_violated=False,
            resource_assignments=[],
            resources_were_computed=False,
            was_fixed=False,
        )

        # cap2 finishes earlier (January) but depends on cap1 - this is backward!
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            requires=deps("cap1"),
        )
        cap2.annotations["schedule"] = ScheduleAnnotations(
            estimated_start=date(2025, 1, 1),
            estimated_end=date(2025, 1, 15),
            computed_deadline=None,
            computed_priority=None,
            deadline_violated=False,
            resource_assignments=[],
            resources_were_computed=False,
            was_fixed=False,
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(metadata=metadata, entities=entities)

        markdown = create_generator(feature_map)

        # Should detect backward dependency based on scheduler dates
        assert "## ⚠️ Timeline Warnings" in markdown
        assert "`Cap 2`" in markdown
        assert "depends on" in markdown
        assert "`Cap 1`" in markdown

    def test_no_backward_warning_when_scheduler_order_correct(self) -> None:
        """Test that no warning when scheduler dates are in correct order."""
        metadata = FeatureMapMetadata()

        # cap1 finishes first (January)
        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
        )
        cap1.annotations["schedule"] = ScheduleAnnotations(
            estimated_start=date(2025, 1, 1),
            estimated_end=date(2025, 1, 15),
            computed_deadline=None,
            computed_priority=None,
            deadline_violated=False,
            resource_assignments=[],
            resources_were_computed=False,
            was_fixed=False,
        )

        # cap2 finishes later (March) and depends on cap1 - correct order
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            requires=deps("cap1"),
        )
        cap2.annotations["schedule"] = ScheduleAnnotations(
            estimated_start=date(2025, 3, 1),
            estimated_end=date(2025, 3, 15),
            computed_deadline=None,
            computed_priority=None,
            deadline_violated=False,
            resource_assignments=[],
            resources_were_computed=False,
            was_fixed=False,
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(metadata=metadata, entities=entities)

        markdown = create_generator(feature_map)

        # No warning - order is correct
        assert "## ⚠️ Timeline Warnings" not in markdown

    def test_manual_end_date_takes_precedence_over_scheduler(self) -> None:
        """Test that manual end_date in meta takes precedence over scheduler."""
        metadata = FeatureMapMetadata()

        # cap1 has manual end_date of March
        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            meta={"end_date": "2025-03-15"},
        )
        # Even though scheduler says January
        cap1.annotations["schedule"] = ScheduleAnnotations(
            estimated_start=date(2025, 1, 1),
            estimated_end=date(2025, 1, 15),
            computed_deadline=None,
            computed_priority=None,
            deadline_violated=False,
            resource_assignments=[],
            resources_were_computed=False,
            was_fixed=False,
        )

        # cap2 finishes in February and depends on cap1
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            requires=deps("cap1"),
        )
        cap2.annotations["schedule"] = ScheduleAnnotations(
            estimated_start=date(2025, 2, 1),
            estimated_end=date(2025, 2, 15),
            computed_deadline=None,
            computed_priority=None,
            deadline_violated=False,
            resource_assignments=[],
            resources_were_computed=False,
            was_fixed=False,
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(metadata=metadata, entities=entities)

        markdown = create_generator(feature_map)

        # Should detect backward dependency because manual end_date (March) > cap2's end (February)
        assert "## ⚠️ Timeline Warnings" in markdown
        assert "`Cap 2`" in markdown

    def test_manual_timeframe_takes_precedence_over_scheduler(self) -> None:
        """Test that manual timeframe in meta takes precedence over scheduler."""
        metadata = FeatureMapMetadata()

        # cap1 has manual timeframe of Q2
        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            meta={"timeframe": "2025q2"},
        )
        # Scheduler says January (would be Q1)
        cap1.annotations["schedule"] = ScheduleAnnotations(
            estimated_start=date(2025, 1, 1),
            estimated_end=date(2025, 1, 15),
            computed_deadline=None,
            computed_priority=None,
            deadline_violated=False,
            resource_assignments=[],
            resources_were_computed=False,
            was_fixed=False,
        )

        # cap2 has manual timeframe of Q1 and depends on cap1
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            requires=deps("cap1"),
            meta={"timeframe": "2025q1"},
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(metadata=metadata, entities=entities)

        markdown = create_generator(feature_map)

        # Should detect backward dependency based on manual timeframes (Q1 depends on Q2)
        assert "## ⚠️ Timeline Warnings" in markdown
        assert "`Cap 2` (2025q1) depends on `Cap 1` (2025q2)" in markdown

    def test_workflow_phases_without_timeframe_use_scheduler(self) -> None:
        """Test workflow-generated phases use scheduler for backward checking."""
        metadata = FeatureMapMetadata()

        # Design phase (no manual timeframe, workflow-generated)
        design = Entity(
            type="capability",
            id="auth_design",
            name="Auth Design",
            description="Design phase",
            # No timeframe - workflow generated
        )
        design.annotations["schedule"] = ScheduleAnnotations(
            estimated_start=date(2025, 1, 1),
            estimated_end=date(2025, 1, 10),
            computed_deadline=None,
            computed_priority=None,
            deadline_violated=False,
            resource_assignments=[],
            resources_were_computed=False,
            was_fixed=False,
        )

        # Implementation phase depends on design, scheduled after
        impl = Entity(
            type="capability",
            id="auth",
            name="Auth Implementation",
            description="Impl phase",
            requires=deps("auth_design"),
        )
        impl.annotations["schedule"] = ScheduleAnnotations(
            estimated_start=date(2025, 1, 20),
            estimated_end=date(2025, 2, 15),
            computed_deadline=None,
            computed_priority=None,
            deadline_violated=False,
            resource_assignments=[],
            resources_were_computed=False,
            was_fixed=False,
        )

        entities = [design, impl]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(metadata=metadata, entities=entities)

        markdown = create_generator(feature_map)

        # No warning - design finishes before impl starts (correct order)
        assert "## ⚠️ Timeline Warnings" not in markdown

    def test_custom_section_ordering(self, simple_feature_map: FeatureMap) -> None:
        """Test that sections appear in configured order."""
        config = MarkdownConfig(
            organization=OrganizationConfig(
                primary="by_type", entity_type_order=["outcome", "user_story", "capability"]
            )
        )
        markdown = create_generator(simple_feature_map, config)

        # Find positions of section headers
        outcomes_pos = markdown.find("## Outcomes")
        stories_pos = markdown.find("## User Stories")
        capabilities_pos = markdown.find("## Capabilities")

        # Verify they appear in the configured order
        assert outcomes_pos < stories_pos
        assert stories_pos < capabilities_pos

    def test_section_exclusion(self, simple_feature_map: FeatureMap) -> None:
        """Test that excluded types don't appear when not in entity_type_order."""
        config = MarkdownConfig(
            organization=OrganizationConfig(
                primary="by_type",
                entity_type_order=["capability", "outcome"],  # Exclude user_story
            )
        )
        markdown = create_generator(simple_feature_map, config)

        # Capabilities and outcomes should appear
        assert "## Capabilities" in markdown
        assert "## Outcomes" in markdown

        # User stories should not appear
        assert "## User Stories" not in markdown

    def test_timeline_visibility_control(self) -> None:
        """Test that timeline section can be excluded via config."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            meta={"timeframe": "2024-Q1"},
        )

        entities = [cap1]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(metadata=metadata, entities=entities)

        # With timeline in sections
        config_with_timeline = MarkdownConfig(toc_sections=["timeline", "entity_types"])
        markdown_with = create_generator(feature_map, config_with_timeline)
        assert "## Timeline" in markdown_with

        # Without timeline in sections
        config_without_timeline = MarkdownConfig(toc_sections=["entity_types"])
        markdown_without = create_generator(feature_map, config_without_timeline)
        assert "## Timeline" not in markdown_without

    def test_toc_respects_section_ordering(self, simple_feature_map: FeatureMap) -> None:
        """Test that TOC entries match body organization."""
        config = MarkdownConfig(
            organization=OrganizationConfig(
                primary="by_type", entity_type_order=["user_story", "outcome", "capability"]
            )
        )
        markdown = create_generator(simple_feature_map, config)

        # Extract TOC section (ends at first body section or warnings)
        toc_start = markdown.find("## Table of Contents")
        # TOC ends at warnings or first body section (both are ##)
        toc_end = markdown.find("\n## ", toc_start + len("## Table of Contents"))
        toc_section = markdown[toc_start:toc_end]

        # Find positions within TOC (now using section headings, not list items)
        stories_toc = toc_section.find("### User Stories")
        outcomes_toc = toc_section.find("### Outcomes")
        capabilities_toc = toc_section.find("### Capabilities")

        # Verify order in TOC matches body organization
        assert stories_toc < outcomes_toc
        assert outcomes_toc < capabilities_toc

    def test_toc_excludes_missing_sections(self, simple_feature_map: FeatureMap) -> None:
        """Test that TOC only includes sections from body organization."""
        config = MarkdownConfig(
            organization=OrganizationConfig(
                primary="by_type",
                entity_type_order=["capability", "outcome"],  # Exclude user_story
            )
        )
        markdown = create_generator(simple_feature_map, config)

        # Extract TOC section (ends at first body section or warnings)
        toc_start = markdown.find("## Table of Contents")
        # TOC ends at warnings or first body section (both are ##)
        toc_end = markdown.find("\n## ", toc_start + len("## Table of Contents"))
        toc_section = markdown[toc_start:toc_end]

        # Capabilities and outcomes should be in TOC (as section headings)
        assert "### Capabilities" in toc_section
        assert "### Outcomes" in toc_section

        # User stories should not be in TOC
        assert "### User Stories" not in toc_section

    def test_two_level_organization_entity_heading_levels(self) -> None:
        """Test that entities use h4 (####) headings in two-level organization."""
        metadata = FeatureMapMetadata()

        # Create capabilities with different timeframes
        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            meta={"timeframe": "2024-Q1"},
        )
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            meta={"timeframe": "2024-Q2"},
        )
        story1 = Entity(
            type="user_story",
            id="story1",
            name="Story 1",
            description="Desc",
            meta={"timeframe": "2024-Q1"},
        )

        entities = [cap1, cap2, story1]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(
            metadata=metadata,
            entities=entities,
        )

        # Use two-level organization: by_type then by_timeframe
        config = MarkdownConfig(
            organization=OrganizationConfig(primary="by_type", secondary="by_timeframe")
        )
        markdown = create_generator(feature_map, config)

        # In two-level organization:
        # ## Capabilities (level 1 - primary section)
        # ### 2024-Q1 (level 2 - secondary subsection)
        # #### Cap 1 (level 3 - entity - should be h4)
        # ### 2024-Q2 (level 2 - secondary subsection)
        # #### Cap 2 (level 3 - entity - should be h4)

        # Find the Capabilities section in the BODY (after TOC and warnings)
        # Skip past TOC which now has "### Capabilities"
        toc_end = markdown.find("## ⚠️ Timeline Warnings")
        if toc_end == -1:
            # No warnings, find first body section
            toc_end = markdown.find("## Table of Contents")
            toc_end = markdown.find("\n## ", toc_end + 1)

        cap_start = markdown.find("## Capabilities", toc_end)
        cap_end = markdown.find("## User Stories", cap_start)
        if cap_end == -1:
            cap_end = len(markdown)
        capabilities_section = markdown[cap_start:cap_end]

        # Check structure in Capabilities section (BODY, not TOC)
        assert "## Capabilities" in capabilities_section  # Primary section: h2
        assert "### 2024-Q1" in capabilities_section  # Secondary subsection: h3
        assert "### 2024-Q2" in capabilities_section  # Secondary subsection: h3

        # Entities should be h4 in two-level organization
        cap1_match = re.search(r"^(#{1,6}) Cap 1$", capabilities_section, re.MULTILINE)
        assert cap1_match is not None, "Cap 1 heading not found"
        assert cap1_match.group(1) == "####", f"Cap 1 should be h4, got {cap1_match.group(1)}"

        cap2_match = re.search(r"^(#{1,6}) Cap 2$", capabilities_section, re.MULTILINE)
        assert cap2_match is not None, "Cap 2 heading not found"
        assert cap2_match.group(1) == "####", f"Cap 2 should be h4, got {cap2_match.group(1)}"

        # Find the User Stories section
        stories_start = markdown.find("## User Stories")
        stories_end = markdown.find("## Outcomes")
        if stories_end == -1:
            stories_end = markdown.find("## Table of Contents", stories_start + 1)
        stories_section = markdown[stories_start:stories_end]

        # Check structure in User Stories section
        assert "## User Stories" in stories_section  # Primary section: h2
        assert "### 2024-Q1" in stories_section  # Secondary subsection: h3

        # Entity should be h4 in two-level organization
        story1_match = re.search(r"^(#{1,6}) Story 1$", stories_section, re.MULTILINE)
        assert story1_match is not None, "Story 1 heading not found"
        assert story1_match.group(1) == "####", f"Story 1 should be h4, got {story1_match.group(1)}"

    def test_enables_requires_heading_levels_single_level_organization(self) -> None:
        """Test that Enables/Requires use h4 headings in single-level organization."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(type="capability", id="cap1", name="Cap 1", description="Desc")
        cap2 = Entity(
            type="capability", id="cap2", name="Cap 2", description="Desc", requires=deps("cap1")
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(metadata=metadata, entities=entities)

        # Use single-level organization (by_type, no secondary)
        config = MarkdownConfig(organization=OrganizationConfig(primary="by_type"))
        markdown = create_generator(feature_map, config)

        # In single-level organization:
        # ## Capabilities (level 1 - primary section)
        # ### Cap 1 (entity - should be h3)
        # #### Enables (h4 heading)
        # ### Cap 2 (entity - should be h3)
        # #### Requires (h4 heading)

        # Check entity headings are h3 (search entire document - headings should be unique)
        cap1_match = re.search(r"^(#{1,6}) Cap 1$", markdown, re.MULTILINE)
        assert cap1_match is not None, "Cap 1 heading not found"
        assert cap1_match.group(1) == "###", f"Cap 1 should be h3, got {cap1_match.group(1)}"

        cap2_match = re.search(r"^(#{1,6}) Cap 2$", markdown, re.MULTILINE)
        assert cap2_match is not None, "Cap 2 heading not found"
        assert cap2_match.group(1) == "###", f"Cap 2 should be h3, got {cap2_match.group(1)}"

        # Check Enables and Requires are h4 headings
        assert "#### Enables" in markdown, "Enables h4 heading not found"
        assert "#### Requires" in markdown, "Requires h4 heading not found"

    def test_enables_requires_heading_levels_two_level_organization(self) -> None:
        """Test that Enables/Requires use h5 headings in two-level organization."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            meta={"timeframe": "2024-Q1"},
        )
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            requires=deps("cap1"),
            meta={"timeframe": "2024-Q1"},
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(metadata=metadata, entities=entities)

        # Use two-level organization: by_type then by_timeframe
        config = MarkdownConfig(
            organization=OrganizationConfig(primary="by_type", secondary="by_timeframe")
        )
        markdown = create_generator(feature_map, config)

        # In two-level organization:
        # ## Capabilities (level 1 - primary section)
        # ### 2024-Q1 (level 2 - secondary subsection)
        # #### Cap 1 (entity - should be h4)
        # ##### Enables (h5 heading)
        # #### Cap 2 (entity - should be h4)
        # ##### Requires (h5 heading)

        # Find the Capabilities section in the BODY (after TOC)
        toc_end = markdown.find("## Table of Contents")
        toc_end = markdown.find("\n## ", toc_end + 1)

        cap_start = markdown.find("## Capabilities", toc_end)
        cap_end = markdown.find("\n## ", cap_start + len("## Capabilities"))
        if cap_end == -1:
            cap_end = len(markdown)
        capabilities_section = markdown[cap_start:cap_end]

        # Check entity headings are h4
        cap1_match = re.search(r"^(#{1,6}) Cap 1$", capabilities_section, re.MULTILINE)
        assert cap1_match is not None, "Cap 1 heading not found"
        assert cap1_match.group(1) == "####", f"Cap 1 should be h4, got {cap1_match.group(1)}"

        cap2_match = re.search(r"^(#{1,6}) Cap 2$", capabilities_section, re.MULTILINE)
        assert cap2_match is not None, "Cap 2 heading not found"
        assert cap2_match.group(1) == "####", f"Cap 2 should be h4, got {cap2_match.group(1)}"

        # Check Enables and Requires are h5 headings
        assert "##### Enables" in capabilities_section, "Enables h5 heading not found"
        assert "##### Requires" in capabilities_section, "Requires h5 heading not found"

    def test_default_behavior_without_config(self, simple_feature_map: FeatureMap) -> None:
        """Test that default behavior includes all sections in standard order."""
        markdown = create_generator(simple_feature_map)

        # All sections should appear
        assert "## Capabilities" in markdown
        assert "## User Stories" in markdown
        assert "## Outcomes" in markdown

        # Verify default order (capabilities, user_stories, outcomes)
        cap_pos = markdown.find("## Capabilities")
        stories_pos = markdown.find("## User Stories")
        outcomes_pos = markdown.find("## Outcomes")

        assert cap_pos < stories_pos
        assert stories_pos < outcomes_pos

    def test_backward_dependencies_always_shown(self) -> None:
        """Test that backward dependency warnings always appear when present."""
        metadata = FeatureMapMetadata()

        cap1 = Entity(
            type="capability",
            id="cap1",
            name="Cap 1",
            description="Desc",
            requires=deps("cap2"),
            meta={"timeframe": "2024-Q1"},
        )
        cap2 = Entity(
            type="capability",
            id="cap2",
            name="Cap 2",
            description="Desc",
            meta={"timeframe": "2024-Q2"},
        )

        entities = [cap1, cap2]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(metadata=metadata, entities=entities)

        # With only entity types in TOC (no timeline)
        config = MarkdownConfig(toc_sections=["entity_types"])
        markdown = create_generator(feature_map, config)

        # Warning section should still appear because warnings always show
        assert "## ⚠️ Timeline Warnings" in markdown

    def test_empty_sections_list(self) -> None:
        """Test that empty sections list produces minimal output."""
        metadata = FeatureMapMetadata()
        cap1 = Entity(type="capability", id="cap1", name="Cap 1", description="Desc")

        entities = [cap1]
        resolve_graph_edges(entities)
        feature_map = FeatureMap(metadata=metadata, entities=entities)

        config = MarkdownConfig(toc_sections=[])
        markdown = create_generator(feature_map, config)

        # Header should appear
        assert "# Feature Map" in markdown

        # Content sections should still appear (toc_sections only controls ToC)
        assert "## Capabilities" in markdown

        # No TOC (since toc_sections is empty)
        assert "## Table of Contents" not in markdown
