"""
Citation regression tests covering:
- Parametrized test across all 5 CitationModes
- Multi-source DOMAIN_ID_HYPERLINKS with repeated domains
- Export round-trip (Quarto BibTeX consistency)
- LaTeX math-mode edge cases
- RIS author extraction false positives
- Quarto hardcoded year=2024

Source: src/local_deep_research/text_optimization/citation_formatter.py
"""

import re

import pytest

from local_deep_research.text_optimization.citation_formatter import (
    CitationFormatter,
    CitationMode,
    QuartoExporter,
    RISExporter,
    LaTeXExporter,
)


# ---------------------------------------------------------------------------
# Shared test content
# ---------------------------------------------------------------------------

SAMPLE_CONTENT = """# Research Report

This is about AI [1] and ML [2].

## Sources

[1] Introduction to Artificial Intelligence
URL: https://arxiv.org/abs/2024.12345

[2] Machine Learning Fundamentals
URL: https://github.com/ml-project/fundamentals
"""

MULTI_DOMAIN_CONTENT = """# Report

Topic A [1] and topic B [2] with extra [3].

## Sources

[1] First arxiv paper
URL: https://arxiv.org/abs/2024.001

[2] Second arxiv paper
URL: https://arxiv.org/abs/2024.002

[3] GitHub project
URL: https://github.com/project/repo
"""


# ---------------------------------------------------------------------------
# Parametrized test across all 5 modes
# ---------------------------------------------------------------------------


class TestAllCitationModes:
    """Same document formatted across all 5 CitationModes."""

    @pytest.mark.parametrize(
        "mode,expected_fragment",
        [
            (CitationMode.NUMBER_HYPERLINKS, "[[1]](https://arxiv.org"),
            (CitationMode.DOMAIN_HYPERLINKS, "[[arxiv.org]](https://arxiv.org"),
            (CitationMode.DOMAIN_ID_HYPERLINKS, "arxiv.org"),
            (CitationMode.DOMAIN_ID_ALWAYS_HYPERLINKS, "arxiv.org-1"),
            (CitationMode.NO_HYPERLINKS, "[1]"),
        ],
    )
    def test_mode_produces_expected_fragment(self, mode, expected_fragment):
        """Each mode produces its characteristic citation fragment."""
        formatter = CitationFormatter(mode)
        result = formatter.format_document(SAMPLE_CONTENT)
        assert expected_fragment in result

    def test_no_hyperlinks_returns_content_unchanged(self):
        """NO_HYPERLINKS mode returns content unchanged."""
        formatter = CitationFormatter(CitationMode.NO_HYPERLINKS)
        result = formatter.format_document(SAMPLE_CONTENT)
        assert result == SAMPLE_CONTENT


# ---------------------------------------------------------------------------
# Multi-source DOMAIN_ID_HYPERLINKS
# ---------------------------------------------------------------------------


class TestDomainIdMultiSource:
    """DOMAIN_ID_HYPERLINKS adds IDs only for repeated domains."""

    def test_repeated_domain_gets_ids(self):
        """Two arxiv sources get arxiv.org-1 and arxiv.org-2."""
        formatter = CitationFormatter(CitationMode.DOMAIN_ID_HYPERLINKS)
        result = formatter.format_document(MULTI_DOMAIN_CONTENT)
        assert "arxiv.org-1" in result or "arxiv.org-2" in result

    def test_unique_domain_no_id(self):
        """Single github source gets just github.com (no -1)."""
        formatter = CitationFormatter(CitationMode.DOMAIN_ID_HYPERLINKS)
        result = formatter.format_document(MULTI_DOMAIN_CONTENT)
        # github.com should appear without -1 suffix
        assert "[[github.com]]" in result


# ---------------------------------------------------------------------------
# Quarto export
# ---------------------------------------------------------------------------


class TestQuartoExport:
    """Quarto export round-trip and consistency."""

    def test_all_refs_have_bibtex_entries(self):
        """Every @refN in Quarto body has matching BibTeX @misc{refN,...}."""
        exporter = QuartoExporter()
        result = exporter.export_to_quarto(SAMPLE_CONTENT, "Test Report")

        # Find all @refN references in body
        ref_pattern = re.compile(r"@ref(\d+)")
        refs_in_body = set(ref_pattern.findall(result))

        # Find all BibTeX entries
        bib_pattern = re.compile(r"@misc\{ref(\d+),")
        bib_entries = set(bib_pattern.findall(result))

        assert refs_in_body, "Should have at least one @ref in body"
        assert refs_in_body.issubset(bib_entries), (
            f"Missing BibTeX entries for: {refs_in_body - bib_entries}"
        )

    def test_bibtex_keys_unique(self):
        """All BibTeX keys are unique."""
        exporter = QuartoExporter()
        result = exporter.export_to_quarto(SAMPLE_CONTENT)

        bib_pattern = re.compile(r"@misc\{(ref\d+),")
        keys = bib_pattern.findall(result)
        assert len(keys) == len(set(keys)), f"Duplicate BibTeX keys: {keys}"

    def test_hardcoded_year_2024(self):
        """Documents the hardcoded year = {2024} at line 543."""
        exporter = QuartoExporter()
        result = exporter.export_to_quarto(SAMPLE_CONTENT)

        # Every BibTeX entry should have year = {2024}
        assert "year = {2024}" in result

    def test_yaml_header_included(self):
        """Quarto output includes YAML front matter."""
        exporter = QuartoExporter()
        result = exporter.export_to_quarto(SAMPLE_CONTENT, "My Report")
        assert result.startswith("---")
        assert 'title: "My Report"' in result

    def test_comma_citations_converted(self):
        """Comma-separated citations [1, 2] converted to [@ref1, @ref2]."""
        content = "Text [1, 2] here.\n\n## Sources\n\n[1] A\nURL: https://a.com\n\n[2] B\nURL: https://b.com\n"
        exporter = QuartoExporter()
        result = exporter.export_to_quarto(content)
        assert "@ref1" in result
        assert "@ref2" in result


# ---------------------------------------------------------------------------
# RIS export
# ---------------------------------------------------------------------------


class TestRISExport:
    """RIS format export tests."""

    def test_basic_ris_structure(self):
        """RIS output has TY, TI, UR, ER tags."""
        exporter = RISExporter()
        result = exporter.export_to_ris(SAMPLE_CONTENT)
        assert "TY  - ELEC" in result
        assert "TI  -" in result
        assert "ER  - " in result

    def test_url_included_in_ris(self):
        """URL from source is included in RIS entry."""
        exporter = RISExporter()
        result = exporter.export_to_ris(SAMPLE_CONTENT)
        assert "UR  - https://arxiv.org" in result

    def test_author_extraction_by_keyword(self):
        """'by Author Name' extracts author correctly."""
        content = """# Report
Text [1].
## Sources
[1] Research Paper by John Smith and Jane Doe
URL: https://example.com
"""
        exporter = RISExporter()
        result = exporter.export_to_ris(content)
        assert "AU  -" in result

    def test_author_false_positive_stand_by_me(self):
        """'Stand by Me' should NOT extract 'Me' as an author.

        The regex \\bby\\s+([^.\\n]+?) matches 'by Me' in 'Stand by Me'.
        This documents the false positive behavior of the current regex.
        """
        content = """# Report
Text [1].
## Sources
[1] Stand by Me - A Classic Film Analysis
URL: https://example.com
"""
        exporter = RISExporter()
        result = exporter.export_to_ris(content)
        # The regex WILL match "by Me" — this documents the current behavior
        # The "AU  - Me" line documents this false positive
        if "AU  -" in result:
            # If authors are extracted, "Me" would be one of them
            # This is a known false positive from the simple regex
            pass  # Document behavior without asserting it's correct

    def test_no_sources_section_returns_empty(self):
        """Content without sources section returns empty string."""
        exporter = RISExporter()
        result = exporter.export_to_ris("Just some text without sources")
        assert result == ""

    def test_arxiv_publisher(self):
        """arxiv.org URL produces PB  - arXiv."""
        exporter = RISExporter()
        result = exporter.export_to_ris(SAMPLE_CONTENT)
        assert "PB  - arXiv" in result

    def test_github_publisher(self):
        """github.com URL produces PB  - GitHub."""
        exporter = RISExporter()
        result = exporter.export_to_ris(SAMPLE_CONTENT)
        assert "PB  - GitHub" in result


# ---------------------------------------------------------------------------
# LaTeX export
# ---------------------------------------------------------------------------


class TestLaTeXExport:
    """LaTeX export edge cases."""

    def test_basic_latex_structure(self):
        """LaTeX output includes documentclass and begin{document}."""
        exporter = LaTeXExporter()
        result = exporter.export_to_latex(SAMPLE_CONTENT)
        assert "\\documentclass" in result
        assert "\\begin{document}" in result
        assert "\\end{document}" in result

    def test_headings_converted(self):
        """Markdown headings converted to LaTeX sections."""
        exporter = LaTeXExporter()
        result = exporter.export_to_latex("# Title\n\n## Subtitle\n\nText")
        assert "\\section{" in result
        assert "\\subsection{" in result

    def test_unbalanced_dollar_sign(self):
        """Unbalanced $ (e.g., 'costs $100') in content.

        LaTeX exporter should handle or at least not crash on unbalanced $.
        """
        content = "# Report\n\nThis costs $100 per unit.\n\n## Sources\n\n[1] Test\nURL: https://a.com\n"
        exporter = LaTeXExporter()
        # Should not raise
        result = exporter.export_to_latex(content)
        assert isinstance(result, str)

    def test_citations_converted_to_cite(self):
        """[1] converted to \\cite{ref1} or similar."""
        exporter = LaTeXExporter()
        result = exporter.export_to_latex(SAMPLE_CONTENT)
        assert "\\cite{" in result or "ref1" in result
