"""Tests for agentkit readme command (D5)."""
from __future__ import annotations

from pathlib import Path
from unittest.mock import patch

import pytest

from agentkit_cli.commands.readme_cmd import (
    build_section,
    inject_section,
    remove_section,
    readme_command,
    _find_section_bounds,
    BADGE_PATTERN,
)


# ---------------------------------------------------------------------------
# Unit tests: inject_section
# ---------------------------------------------------------------------------

class TestInjectSection:
    def test_inject_new_badge_into_empty_readme(self):
        """Inject into an empty README appends a section."""
        result = inject_section("", score=75, section_header="## Agent Quality")
        assert "## Agent Quality" in result
        assert "[![agent quality]" in result
        assert "75%2F100" in result

    def test_inject_new_badge_appends_to_existing_content(self):
        """Inject into README with existing content preserves original content."""
        original = "# My Project\n\nSome description here.\n"
        result = inject_section(original, score=82)
        assert "# My Project" in result
        assert "Some description here." in result
        assert "## Agent Quality" in result
        assert "82%2F100" in result

    def test_inject_adds_blank_line_separator(self):
        """Injected section is separated from existing content by a blank line."""
        original = "# My Project\n"
        result = inject_section(original, score=50)
        # There should be a blank line before the section header
        assert "\n\n## Agent Quality" in result

    def test_update_existing_badge_score(self):
        """Update replaces the old score with the new one."""
        original = inject_section("# Repo\n\n", score=50)
        updated = inject_section(original, score=90)
        assert "90%2F100" in updated
        assert "50%2F100" not in updated
        assert "# Repo" in updated

    def test_idempotent_same_score(self):
        """Calling inject with the same score twice is idempotent."""
        base = "# My Project\n\n"
        first = inject_section(base, score=70)
        second = inject_section(first, score=70)
        # Content should be the same (no duplicate sections)
        assert second.count("## Agent Quality") == 1
        assert second.count("[![agent quality]") == 1

    def test_custom_section_header(self):
        """Custom section header is used instead of default."""
        result = inject_section("# Repo\n", score=60, section_header="## Quality Badge")
        assert "## Quality Badge" in result
        assert "## Agent Quality" not in result

    def test_generated_footer_present(self):
        """Injected section includes the generated-by footer."""
        result = inject_section("", score=80)
        assert "Generated by [agentkit-cli]" in result

    def test_inject_preserves_trailing_content(self):
        """Inject preserves content after the injected section (update mode)."""
        section = build_section(50)
        readme = "# Intro\n\n" + section + "\n## Another Section\n\nContent here.\n"
        updated = inject_section(readme, score=85)
        assert "## Another Section" in updated
        assert "Content here." in updated

    def test_badge_url_color_green(self):
        """Score >= 80 produces green badge."""
        result = inject_section("", score=85)
        assert "green" in result

    def test_badge_url_color_yellow(self):
        """Score 60-79 produces yellow badge."""
        result = inject_section("", score=65)
        assert "yellow" in result

    def test_badge_url_color_red(self):
        """Score < 40 produces red badge."""
        result = inject_section("", score=20)
        assert "red" in result


# ---------------------------------------------------------------------------
# Unit tests: remove_section
# ---------------------------------------------------------------------------

class TestRemoveSection:
    def test_remove_existing_section(self):
        """Remove deletes the injected section cleanly."""
        original = "# My Project\n\nSome text.\n"
        with_badge = inject_section(original, score=70)
        removed = remove_section(with_badge)
        assert "## Agent Quality" not in removed
        assert "[![agent quality]" not in removed
        assert "# My Project" in removed
        assert "Some text." in removed

    def test_remove_leaves_no_orphaned_blank_lines(self):
        """Remove doesn't leave double blank lines at EOF."""
        readme = "# My Project\n\nSome text.\n"
        with_badge = inject_section(readme, score=70)
        removed = remove_section(with_badge)
        # Should not end with multiple blank lines
        assert not removed.endswith("\n\n\n")

    def test_remove_no_section_is_noop(self):
        """Remove on README without section returns original content."""
        original = "# My Project\n\nNo badge here.\n"
        result = remove_section(original)
        assert result == original

    def test_remove_custom_header(self):
        """Remove respects custom section header."""
        original = "# Repo\n"
        with_badge = inject_section(original, score=60, section_header="## Quality Badge")
        removed = remove_section(with_badge, section_header="## Quality Badge")
        assert "## Quality Badge" not in removed
        assert "# Repo" in removed


# ---------------------------------------------------------------------------
# Integration tests: readme_command function
# ---------------------------------------------------------------------------

class TestReadmeCommand:
    def _make_readme(self, tmp_path: Path, content: str = "# My Project\n\nDescription.\n") -> Path:
        p = tmp_path / "README.md"
        p.write_text(content, encoding="utf-8")
        return p

    def test_inject_new_badge(self, tmp_path):
        """readme_command injects badge into README without existing badge."""
        readme = self._make_readme(tmp_path)
        readme_command(
            readme=readme,
            dry_run=False,
            remove=False,
            section_header="## Agent Quality",
            path=tmp_path,
            score_override=75,
        )
        content = readme.read_text(encoding="utf-8")
        assert "## Agent Quality" in content
        assert "75%2F100" in content

    def test_dry_run_does_not_modify_file(self, tmp_path):
        """--dry-run shows output but does not modify README.md."""
        readme = self._make_readme(tmp_path)
        original_content = readme.read_text(encoding="utf-8")
        readme_command(
            readme=readme,
            dry_run=True,
            remove=False,
            section_header="## Agent Quality",
            path=tmp_path,
            score_override=80,
        )
        assert readme.read_text(encoding="utf-8") == original_content

    def test_remove_flag(self, tmp_path):
        """--remove deletes an existing badge section."""
        readme = self._make_readme(tmp_path)
        # First inject
        readme_command(
            readme=readme,
            dry_run=False,
            remove=False,
            section_header="## Agent Quality",
            path=tmp_path,
            score_override=60,
        )
        assert "## Agent Quality" in readme.read_text(encoding="utf-8")
        # Then remove
        readme_command(
            readme=readme,
            dry_run=False,
            remove=True,
            section_header="## Agent Quality",
            path=tmp_path,
            score_override=None,
        )
        assert "## Agent Quality" not in readme.read_text(encoding="utf-8")

    def test_no_readme_found_exits_1(self, tmp_path):
        """readme_command exits with code 1 if README.md is missing."""
        import typer
        with pytest.raises(typer.Exit):
            readme_command(
                readme=tmp_path / "README.md",
                dry_run=False,
                remove=False,
                section_header="## Agent Quality",
                path=tmp_path,
                score_override=None,
            )

    def test_custom_readme_path(self, tmp_path):
        """--readme accepts a custom path."""
        custom = tmp_path / "docs" / "README.md"
        custom.parent.mkdir()
        custom.write_text("# Docs\n", encoding="utf-8")
        readme_command(
            readme=custom,
            dry_run=False,
            remove=False,
            section_header="## Agent Quality",
            path=tmp_path,
            score_override=55,
        )
        content = custom.read_text(encoding="utf-8")
        assert "55%2F100" in content

    def test_update_existing_badge(self, tmp_path):
        """readme_command updates score in existing badge section."""
        readme = self._make_readme(tmp_path)
        readme_command(
            readme=readme, dry_run=False, remove=False,
            section_header="## Agent Quality", path=tmp_path, score_override=50,
        )
        readme_command(
            readme=readme, dry_run=False, remove=False,
            section_header="## Agent Quality", path=tmp_path, score_override=95,
        )
        content = readme.read_text(encoding="utf-8")
        assert "95%2F100" in content
        assert "50%2F100" not in content
        assert content.count("## Agent Quality") == 1

    def test_empty_readme(self, tmp_path):
        """readme_command handles an empty README.md gracefully."""
        readme = tmp_path / "README.md"
        readme.write_text("", encoding="utf-8")
        readme_command(
            readme=readme, dry_run=False, remove=False,
            section_header="## Agent Quality", path=tmp_path, score_override=70,
        )
        content = readme.read_text(encoding="utf-8")
        assert "## Agent Quality" in content


# ---------------------------------------------------------------------------
# D4: run --readme and report --readme integration
# ---------------------------------------------------------------------------

class TestRunReportReadmeFlags:
    def test_run_readme_flag_injects_badge(self, tmp_path):
        """agentkit run --readme injects badge after pipeline."""
        from agentkit_cli.commands.run_cmd import run_command
        readme = tmp_path / "README.md"
        readme.write_text("# My Repo\n", encoding="utf-8")

        with patch("agentkit_cli.commands.run_cmd.is_installed", return_value=False), \
             patch("agentkit_cli.commands.run_cmd.find_project_root", return_value=tmp_path), \
             patch("agentkit_cli.commands.run_cmd.save_last_run"), \
             patch("agentkit_cli.commands.readme_cmd.compute_badge_score", return_value={"score": 72, "sources": ["override"], "raw_scores": {}}):
            run_command(
                path=tmp_path, skip=None, benchmark=False,
                json_output=False, notes=None, ci=True,
                publish=False, inject_readme=True,
            )

        content = readme.read_text(encoding="utf-8")
        assert "## Agent Quality" in content

    def test_report_readme_flag_injects_badge(self, tmp_path):
        """agentkit report --readme injects badge after report."""
        from agentkit_cli.commands.report_cmd import report_command
        readme = tmp_path / "README.md"
        readme.write_text("# My Repo\n", encoding="utf-8")

        with patch("agentkit_cli.commands.report_cmd.run_all", return_value={"agentlint": None, "agentmd": None, "coderace": None, "agentreflect": None}), \
             patch("agentkit_cli.commands.report_cmd.is_installed", return_value=False), \
             patch("agentkit_cli.commands.readme_cmd.compute_badge_score", return_value={"score": 65, "sources": [], "raw_scores": {}}):
            report_command(
                path=tmp_path, json_output=False, output=tmp_path / "report.html",
                open_browser=False, publish=False, inject_readme=True,
            )

        content = readme.read_text(encoding="utf-8")
        assert "## Agent Quality" in content

    def test_run_readme_flag_false_no_inject(self, tmp_path):
        """agentkit run without --readme does NOT inject badge."""
        from agentkit_cli.commands.run_cmd import run_command
        readme = tmp_path / "README.md"
        readme.write_text("# My Repo\n", encoding="utf-8")

        with patch("agentkit_cli.commands.run_cmd.is_installed", return_value=False), \
             patch("agentkit_cli.commands.run_cmd.find_project_root", return_value=tmp_path), \
             patch("agentkit_cli.commands.run_cmd.save_last_run"):
            run_command(
                path=tmp_path, skip=None, benchmark=False,
                json_output=False, notes=None, ci=True,
                publish=False, inject_readme=False,
            )

        content = readme.read_text(encoding="utf-8")
        assert "## Agent Quality" not in content
