"""
Tests for Crossref module.
"""

import pytest

from information_composer.crossref.core.client import CrossrefAPIError, CrossrefClient
from information_composer.crossref.core.models import (
    CrossrefAuthor,
    CrossrefReference,
    CrossrefWork,
)


class TestCrossrefAuthor:
    """Tests for CrossrefAuthor model."""

    def test_from_crossref_full_data(self) -> None:
        """Test creating CrossrefAuthor from full Crossref data."""
        data = {
            "given": "John",
            "family": "Doe",
            "affiliation": [{"name": "MIT"}],
            "sequence": "first",
            "ORCID": "http://orcid.org/0000-0001-2345-6789",
        }
        author = CrossrefAuthor.from_crossref(data)
        assert author.given_name == "John"
        assert author.family_name == "Doe"
        assert author.full_name == "John Doe"
        assert author.affiliation == ["MIT"]
        assert author.sequence == "first"
        assert author.orcid == "http://orcid.org/0000-0001-2345-6789"

    def test_from_crossref_minimal_data(self) -> None:
        """Test creating CrossrefAuthor with minimal data."""
        data = {}
        author = CrossrefAuthor.from_crossref(data)
        assert author.given_name is None
        assert author.family_name is None
        assert author.full_name is None


class TestCrossrefReference:
    """Tests for CrossrefReference model."""

    def test_from_crossref_full_data(self) -> None:
        """Test creating CrossrefReference from full Crossref data."""
        data = {
            "DOI": "10.1000/xyz123",
            "key": "ref1",
            "doi-asserted-by": "crossref",
            "unstructured": "Smith, J. (2020) Example Paper. Journal of Examples.",
            "article-title": "Example Paper",
            "journal-title": "Journal of Examples",
            "volume": "10",
            "first-page": "100",
            "year": "2020",
            "author": "Smith J.",
        }
        ref = CrossrefReference.from_crossref(data)
        assert ref.doi == "10.1000/xyz123"
        assert ref.key == "ref1"
        assert ref.article_title == "Example Paper"
        assert ref.year == 2020

    def test_from_crossref_year_conversion(self) -> None:
        """Test year is properly converted to int."""
        data = {"year": "2020"}
        ref = CrossrefReference.from_crossref(data)
        assert ref.year == 2020

    def test_from_crossref_invalid_year(self) -> None:
        """Test invalid year string returns None."""
        data = {"year": "unknown"}
        ref = CrossrefReference.from_crossref(data)
        assert ref.year is None


class TestCrossrefWork:
    """Tests for CrossrefWork model."""

    def test_from_crossref_full_data(self) -> None:
        """Test creating CrossrefWork from full Crossref API response."""
        data = {
            "message": {
                "DOI": "10.1126/science.291.5503.447",
                "title": ["Insulators and Boundaries: Versatile Regulatory Elements"],
                "type": "journal-article",
                "container-title": ["Science"],
                "publisher": "American Association for the Advancement of Science",
                "published-print": {"date-parts": [[2001, 1, 19]]},
                "volume": "291",
                "issue": "5503",
                "page": "447-450",
                "ISSN": ["0036-8075", "1095-9203"],
                "is-referenced-by-count": 297,
                "reference-count": 54,
                "author": [
                    {
                        "given": "Adam C.",
                        "family": "Bell",
                        "affiliation": [{"name": "NIDDK, NIH"}],
                    }
                ],
            }
        }
        work = CrossrefWork.from_crossref(data)
        assert work.doi == "10.1126/science.291.5503.447"
        assert work.title == [
            "Insulators and Boundaries: Versatile Regulatory Elements"
        ]
        assert work.journal_title == ["Science"]
        assert work.publisher == "American Association for the Advancement of Science"
        assert work.volume == "291"
        assert work.issue == "5503"
        assert work.page == "447-450"
        assert work.is_referenced_by_count == 297
        assert len(work.authors) == 1
        assert work.authors[0].given_name == "Adam C."
        assert work.authors[0].family_name == "Bell"

    def test_to_dict(self) -> None:
        """Test CrossrefWork serialization to dictionary."""
        data = {
            "message": {
                "DOI": "10.1126/science.291.5503.447",
                "title": ["Test Paper"],
                "type": "journal-article",
                "is-referenced-by-count": 10,
                "reference-count": 5,
            }
        }
        work = CrossrefWork.from_crossref(data)
        result = work.to_dict()
        assert result["doi"] == "10.1126/science.291.5503.447"
        assert result["title"] == ["Test Paper"]
        assert result["is_referenced_by_count"] == 10

    def test_url_generation(self) -> None:
        """Test DOI URL is properly generated."""
        data = {"message": {"DOI": "10.1126/science.291.5503.447", "title": ["Test"]}}
        work = CrossrefWork.from_crossref(data)
        assert work.url == "https://doi.org/10.1126/science.291.5503.447"

    def test_no_doi_url(self) -> None:
        """Test URL is None when DOI is missing."""
        data = {"message": {"title": ["Test"]}}
        work = CrossrefWork.from_crossref(data)
        assert work.url is None


class TestCrossrefClient:
    """Tests for CrossrefClient."""

    def test_clean_doi_with_prefix(self) -> None:
        """Test cleaning DOI with doi: prefix."""
        client = CrossrefClient()
        assert (
            client._clean_doi("doi:10.1126/science.291.5503.447")
            == "10.1126/science.291.5503.447"
        )

    def test_clean_doi_with_url(self) -> None:
        """Test cleaning DOI with https://doi.org/ prefix."""
        client = CrossrefClient()
        assert (
            client._clean_doi("https://doi.org/10.1126/science.291.5503.447")
            == "10.1126/science.291.5503.447"
        )

    def test_clean_doi_already_clean(self) -> None:
        """Test cleaning already clean DOI."""
        client = CrossrefClient()
        assert (
            client._clean_doi("10.1126/science.291.5503.447")
            == "10.1126/science.291.5503.447"
        )

    def test_clean_doi_with_whitespace(self) -> None:
        """Test cleaning DOI with whitespace."""
        client = CrossrefClient()
        assert (
            client._clean_doi("  10.1126/science.291.5503.447  ")
            == "10.1126/science.291.5503.447"
        )
