# Crossref Integration Guide

This guide explains how to integrate and use the Crossref module for querying bibliographic data from the Crossref API.

## Overview

Crossref is a definitive source for scholarly citations and references. The Crossref module provides comprehensive functionality for:

- Querying works by DOI, title, author, or other metadata
- Fetching detailed bibliographic information
- Processing and transforming Crossref data
- Converting PMIDs to DOIs and vice versa
- Batch processing with rate limiting

## Installation

The Crossref module is part of the Information Composer package:

```bash
pip install information-composer
```

### Dependencies

The module requires:
- `habanero` - Crossref API client library
- `pydantic` - Data validation
- `requests` - HTTP requests

## Basic Usage

### Querying by DOI

```python
from information_composer import CrossrefClient

# Create a client
client = CrossrefClient()

# Query by DOI
work = client.query_by_doi("10.1038/nature12373")

print(f"Title: {work.title}")
print(f"Authors: {work.authors}")
print(f"Year: {work.year}")
print(f"Journal: {work.container_title}")
```

### Searching Works

```python
from information_composer import query_crossref

# Search for works
works = query_crossref(
    query="machine learning",
    limit=10,
    year_range=(2020, 2023)
)

for work in works:
    print(f"{work.title} ({work.year})")
    print(f"DOI: {work.doi}")
    print(f"Authors: {', '.join([a.family for a in work.authors[:3]])}")
    print("-" * 50)
```

### Converting PMID to DOI

```python
from information_composer.pubmed import pmid_to_doi

# Convert PMID to DOI
doi = pmid_to_doi("12345678", "your-email@example.com")
print(f"DOI: {doi}")
```

### Converting DOI to PMID

```python
from information_composer.pubmed import doi_to_pmid

# Convert DOI to PMID
pmid = doi_to_pmid("10.1038/nature12373")
print(f"PMID: {pmid}")
```

## CLI Usage

The Crossref module includes a command-line interface:

### Query Command

```bash
# Query by DOI
crossref-cli query --doi "10.1038/nature12373"

# Search by title
crossref-cli search --query "machine learning" --limit 10

# Search with filters
crossref-cli search --query "cancer" --year 2023 --journal "Nature"

# Export to JSON
crossref-cli search --query "deep learning" --output results.json
```

### Convert Command

```bash
# Convert PMID to DOI
crossref-cli convert pmid-to-doi --pmid 12345678 --email user@example.com

# Convert DOI to PMID
crossref-cli convert doi-to-pmid --doi "10.1038/nature12373"

# Batch conversion
crossref-cli convert pmid-to-doi --input pmids.txt --output dois.txt
```

## Advanced Usage

### Using the CrossrefWork Model

```python
from information_composer import CrossrefWork, CrossrefAuthor

# Create a work from Crossref data
work = CrossrefWork.from_crossref({
    "title": ["Example Paper"],
    "author": [{"family": "Smith", "given": "John"}],
    "published": {"date-parts": [[2023, 1, 1]]},
    "DOI": "10.1234/example.123"
})

# Access properties
print(work.title)
print(work.year)
print(work.doi)

# Convert to dict
work_dict = work.to_dict()
```

### Custom Queries

```python
from information_composer import CrossrefClient

client = CrossrefClient()

# Query with custom parameters
results = client.query_works(
    query="machine learning",
    filters={
        "type": "journal-article",
        "year": 2023,
        "publisher": "Elsevier"
    },
    limit=20,
    offset=0
)

# Process results
for item in results:
    if item.score > 0.9:  # High relevance
        print(f"{item.title} - {item.doi}")
```

### Batch Processing

```python
from information_composer import CrossrefClient

client = CrossrefClient()

# Batch DOI lookup
dois = [
    "10.1038/nature12373",
    "10.1126/science.1234567",
    "10.1016/j.cell.2023.01.001"
]

for doi in dois:
    try:
        work = client.query_by_doi(doi)
        print(f"{work.title} - {work.year}")
    except Exception as e:
        print(f"Error fetching {doi}: {e}")
```

## Integration Examples

### With PubMed

```python
from information_composer.pubmed import query_pmid
from information_composer import pmid_to_doi

# Search PubMed
pmids = query_pmid("cancer immunotherapy", "user@example.com", 10)

# Convert to DOIs and get Crossref data
from information_composer import CrossrefClient

client = CrossrefClient()
for pmid in pmids:
    doi = pmid_to_doi(pmid, "user@example.com")
    if doi:
        work = client.query_by_doi(doi)
        print(f"PMID: {pmid}, DOI: {doi}, Title: {work.title}")
```

### With DOI Downloader

```python
from information_composer import CrossrefClient, DOIDownloader

# Search Crossref for papers
client = CrossrefClient()
works = query_crossref("quantum computing", limit=10)

# Download full text
downloader = DOIDownloader()
for work in works:
    if work.doi:
        try:
            result = downloader.download_doi(work.doi)
            print(f"Downloaded: {work.title}")
        except Exception as e:
            print(f"Failed: {e}")
```

### With Google Scholar

```python
from information_composer.sites.google_scholar import google_scholar_search, SearchConfig
from information_composer import pmid_to_crossref_work

# Search Google Scholar
config = SearchConfig(query="deep learning", num_results=20)
results = google_scholar_search(config)

# Get Crossref data for papers with DOI
for paper in results.papers:
    if paper.doi:
        try:
            crossref_work = pmid_to_crossref_work(paper.doi)
            print(f"{crossref_work.title} - {crossref_work.year}")
        except Exception as e:
            print(f"Error fetching Crossref data: {e}")
```

## Configuration

### Rate Limiting

Crossref has rate limits. The client handles this automatically:

```python
from information_composer import CrossrefClient

# Create client with custom rate limiter
client = CrossrefClient(
    max_requests_per_second=10,  # Crossref allows up to 50/sec
    mailto="your-email@example.com"  # Polite identifier
)
```

### Error Handling

```python
from information_composer import (
    CrossrefClient,
    CrossrefAPIError,
    CrossrefRateLimitExceeded
)

client = CrossrefClient()

try:
    work = client.query_by_doi("10.1038/nature12373")
except CrossrefRateLimitExceeded:
    print("Rate limit exceeded. Please wait.")
except CrossrefAPIError as e:
    print(f"API error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")
```

## Data Models

### CrossrefWork

The main data model for Crossref works:

```python
@dataclass
class CrossrefWork:
    """Represents a work from Crossref."""

    doi: str | None
    title: str
    authors: list[CrossrefAuthor]
    year: int
    container_title: str | None
    publisher: str | None
    type: str
    url: str
    references: list[CrossrefReference]
    score: float

    def to_dict(self) -> dict[str, Any]: ...
    @classmethod
    def from_crossref(cls, data: dict) -> "CrossrefWork": ...
```

### CrossrefAuthor

```python
@dataclass
class CrossrefAuthor:
    """Represents an author from Crossref."""

    given: str | None
    family: str | None
    name: str | None
    orcid: str | None
    sequence: str | None
```

### CrossrefReference

```python
@dataclass
class CrossrefReference:
    """Represents a reference from Crossref."""

    doi: str | None
    year: int | None
    unstructured: str | None
    key: str | None
```

## Best Practices

1. **Always provide a mailto parameter**: Crossref requests this for polite identification

2. **Handle rate limits gracefully**: The client handles rate limiting automatically

3. **Cache results**: Store queried data to avoid redundant requests

4. **Validate DOIs**: Always validate DOI format before querying

5. **Use appropriate filters**: Use Crossref filters to narrow down results

6. **Batch process efficiently**: Group queries to minimize API calls

7. **Handle errors**: Implement proper error handling for network issues

## Troubleshooting

### Common Issues

1. **Rate Limiting**: You're making too many requests. Implement backoff.

2. **Invalid DOI**: Check the DOI format and prefix.

3. **Empty Results**: Try broadening your search query.

4. **Network Issues**: Check your internet connection and proxy settings.

### Debug Mode

```python
import logging

# Enable debug logging
logging.basicConfig(level=logging.DEBUG)

# Your Crossref operations
client = CrossrefClient()
work = client.query_by_doi("10.1038/nature12373")
```

## Examples Repository

For more examples, see the `examples/` directory:

- `crossref_query_example.py` - Basic querying examples
- `crossref_search_example.py` - Advanced search examples
- `crossref_integration_example.py` - Integration with other modules
