"""Unit tests for markdown drift formatter."""

from __future__ import annotations

import re

import pytest

from agentmd.drift import DriftReport, FileDriftReport, SectionStaleDetail
from agentmd.formatters import render_markdown_report


def _make_drifted_file() -> FileDriftReport:
    return FileDriftReport(
        agent="claude",
        file="CLAUDE.md",
        status="stale",
        has_drift=True,
        sections_added=["New Section"],
        sections_removed=["Old Section"],
        sections_changed=["Project Overview"],
        sections_fresh=["Commands"],
        sections_stale=["Old Section", "Project Overview"],
        stale_details=[
            SectionStaleDetail(
                section="New Section",
                status="added",
                existing_line_count=0,
                generated_line_count=2,
                diff="--- New Section (existing)\n+++ New Section (generated)\n+hello\n",
            ),
            SectionStaleDetail(
                section="Project Overview",
                status="changed",
                existing_line_count=1,
                generated_line_count=1,
                diff="--- Project Overview (existing)\n+++ Project Overview (generated)\n-old\n+new\n",
            ),
            SectionStaleDetail(
                section="Old Section",
                status="removed",
                existing_line_count=1,
                generated_line_count=0,
                diff="--- Old Section (existing)\n+++ Old Section (generated)\n-old\n",
            ),
        ],
        diff="full diff",
    )


def test_markdown_report_includes_header_and_footer() -> None:
    report = DriftReport(
        root_path="/tmp/demo",
        has_drift=False,
        files=[
            FileDriftReport(
                agent="claude",
                file="CLAUDE.md",
                status="fresh",
                has_drift=False,
                sections_fresh=["Project Overview"],
            )
        ],
    )
    output = render_markdown_report(report)
    assert output.startswith("## 🔍 agentmd Context Drift Report")
    assert "Generated by [agentmd](https://github.com/mikiships/agentmd)" in output


def test_markdown_report_uses_fresh_summary_when_clean() -> None:
    report = DriftReport(
        root_path="/tmp/demo",
        has_drift=False,
        files=[
            FileDriftReport(
                agent="claude",
                file="CLAUDE.md",
                status="fresh",
                has_drift=False,
                sections_fresh=["Project Overview"],
            )
        ],
    )
    output = render_markdown_report(report)
    assert "✅ Context files are fresh" in output


def test_markdown_report_single_file_summary_mentions_filename() -> None:
    report = DriftReport(root_path="/tmp/demo", has_drift=True, files=[_make_drifted_file()])
    output = render_markdown_report(report)
    assert "⚠️ 3 sections drifted in CLAUDE.md" in output


def test_markdown_report_multiple_file_summary_mentions_file_count() -> None:
    file_one = _make_drifted_file()
    file_two = FileDriftReport(
        agent="codex",
        file="AGENTS.md",
        status="stale",
        has_drift=True,
        sections_added=[],
        sections_removed=[],
        sections_changed=["Commands"],
        sections_fresh=[],
        sections_stale=["Commands"],
        stale_details=[
            SectionStaleDetail(
                section="Commands",
                status="changed",
                existing_line_count=1,
                generated_line_count=1,
                diff="--- Commands (existing)\n+++ Commands (generated)\n-old\n+new\n",
            )
        ],
        diff="full diff",
    )
    report = DriftReport(root_path="/tmp/demo", has_drift=True, files=[file_one, file_two])
    output = render_markdown_report(report)
    assert "⚠️ 4 sections drifted across 2 files" in output


@pytest.mark.parametrize(
    ("needle", "status"),
    [
        ("CLAUDE.md :: Project Overview", "stale"),
        ("CLAUDE.md :: Old Section", "missing"),
        ("CLAUDE.md :: New Section", "new"),
        ("CLAUDE.md :: Commands", "fresh"),
    ],
)
def test_markdown_report_table_contains_status_rows(needle: str, status: str) -> None:
    report = DriftReport(root_path="/tmp/demo", has_drift=True, files=[_make_drifted_file()])
    output = render_markdown_report(report)
    assert f"| {needle} | {status} |" in output


def test_markdown_report_escapes_table_pipe_characters() -> None:
    file_report = FileDriftReport(
        agent="claude",
        file="CLAUDE.md",
        status="fresh",
        has_drift=False,
        sections_fresh=["Commands | Scripts"],
    )
    output = render_markdown_report(DriftReport(root_path="/tmp/demo", has_drift=False, files=[file_report]))
    assert "Commands \\| Scripts" in output


@pytest.mark.parametrize(
    ("section", "status_label"),
    [
        ("New Section", "new"),
        ("Project Overview", "stale"),
        ("Old Section", "missing"),
    ],
)
def test_markdown_report_details_map_status_labels(section: str, status_label: str) -> None:
    report = DriftReport(root_path="/tmp/demo", has_drift=True, files=[_make_drifted_file()])
    output = render_markdown_report(report)
    assert f"<summary>CLAUDE.md \u00b7 {section} ({status_label})</summary>" in output


def test_markdown_report_emits_diff_code_fences_for_details() -> None:
    report = DriftReport(root_path="/tmp/demo", has_drift=True, files=[_make_drifted_file()])
    output = render_markdown_report(report)
    assert output.count("```diff") == 3
    assert "--- Project Overview (existing)" in output
    assert "+++ Project Overview (generated)" in output


def test_markdown_report_omits_details_for_fresh_report() -> None:
    report = DriftReport(
        root_path="/tmp/demo",
        has_drift=False,
        files=[
            FileDriftReport(
                agent="claude",
                file="CLAUDE.md",
                status="fresh",
                has_drift=False,
                sections_fresh=["Project Overview"],
            )
        ],
    )
    output = render_markdown_report(report)
    assert "<details>" not in output


def test_markdown_report_full_document_fallback_for_headingless_files() -> None:
    file_report = FileDriftReport(
        agent="claude",
        file="CLAUDE.md",
        status="fresh",
        has_drift=False,
    )
    output = render_markdown_report(DriftReport(root_path="/tmp/demo", has_drift=False, files=[file_report]))
    assert "CLAUDE.md :: full_document" in output


def test_markdown_report_summary_uses_singular_section_word() -> None:
    file_report = FileDriftReport(
        agent="claude",
        file="CLAUDE.md",
        status="stale",
        has_drift=True,
        sections_changed=["Project Overview"],
        sections_stale=["Project Overview"],
        stale_details=[
            SectionStaleDetail(
                section="Project Overview",
                status="changed",
                existing_line_count=1,
                generated_line_count=1,
                diff="--- Project Overview (existing)\n+++ Project Overview (generated)\n-old\n+new\n",
            )
        ],
        diff="full diff",
    )
    output = render_markdown_report(DriftReport(root_path="/tmp/demo", has_drift=True, files=[file_report]))
    assert "⚠️ 1 section drifted in CLAUDE.md" in output


def test_markdown_report_is_stable_for_repeated_rendering() -> None:
    report = DriftReport(root_path="/tmp/demo", has_drift=True, files=[_make_drifted_file()])
    first = render_markdown_report(report)
    second = render_markdown_report(report)
    assert first == second
    assert re.search(r"\| Section \| Status \| Detail \|", first)
