"""
Crossref CLI command-line interface.
This module provides a CLI tool for querying Crossref API using DOIs.
"""

import json
from pathlib import Path
import sys

import click

from information_composer.crossref.core.client import CrossrefAPIError, CrossrefClient
from information_composer.crossref.core.models import CrossrefWork


@click.command()
@click.argument("doi", type=str)
@click.option(
    "--output",
    "-o",
    type=click.Choice(["json", "text"]),
    default="text",
    help="Output format (json or text).",
)
@click.option(
    "--output-file",
    "-f",
    type=click.Path(allow_dash=False, path_type=Path),
    default=None,
    help="Save output to a JSON file.",
)
@click.option(
    "--references-file",
    "-r",
    type=click.Path(allow_dash=False, path_type=Path),
    default=None,
    help="Save reference DOIs to a JSON file.",
)
@click.option(
    "--include-references/--no-include-references",
    default=True,
    help="Include reference data in output.",
)
@click.option(
    "--timeout",
    "-t",
    type=int,
    default=30,
    help="Request timeout in seconds.",
)
@click.option(
    "--mailto",
    "-m",
    type=str,
    default=None,
    help="Email address for polite pool access (faster rate limits).",
)
def main(
    doi: str,
    output: str,
    output_file: Path | None,
    references_file: Path | None,
    include_references: bool,
    timeout: int,
    mailto: str | None,
) -> None:
    """
    Query Crossref API for metadata associated with a DOI.

    Example:\n
        crossref-cli 10.1126/science.291.5503.447\n
        crossref-cli "https://doi.org/10.1126/science.291.5503.447"\n
        crossref-cli 10.1126/science.291.5503.447 -f output.json\n
        crossref-cli 10.1126/science.291.5503.447 -r refs.json
    """
    client = CrossrefClient(timeout=timeout, mailto=mailto)

    try:
        data = client.query_doi(doi, include_references=include_references)
        work = CrossrefWork.from_crossref(data)

        # Handle output to file
        if output_file:
            _save_to_file(output_file, work.to_dict())
            click.secho(f"Metadata saved to: {output_file}", fg="green")

        if references_file:
            refs_data = {
                "doi": work.doi,
                "title": work.title,
                "reference_dois": work.get_reference_dois(),
                "reference_count": work.get_reference_doi_count(),
            }
            _save_to_file(references_file, refs_data)
            click.secho(f"Reference DOIs saved to: {references_file}", fg="green")

        # Print output
        if output == "json" and not output_file:
            click.echo(json.dumps(work.to_dict(), indent=2, ensure_ascii=False))
        else:
            _print_work_details(work)

    except CrossrefAPIError as e:
        click.echo(f"Error: {e}", err=True)
        sys.exit(1)
    except KeyboardInterrupt:
        click.echo("\nOperation cancelled by user.", err=True)
        sys.exit(130)
    except Exception as e:
        click.echo(f"Unexpected error: {e!s}", err=True)
        sys.exit(1)


def _save_to_file(file_path: Path, data: dict) -> None:
    """
    Save data to a JSON file.

    Args:
        file_path: Path to the output file.
        data: Data to save.
    """
    try:
        with open(file_path, "w", encoding="utf-8") as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
    except OSError as e:
        raise click.ClickException(f"Failed to write file {file_path}: {e!s}")


def _print_work_details(work: CrossrefWork) -> None:
    """Print CrossrefWork details in human-readable format."""
    click.secho("=" * 60, bold=True)
    click.secho("Crossref Metadata", bold=True)
    click.secho("=" * 60)

    # Basic info
    click.secho("\nDOI: ", bold=True, nl=False)
    click.echo(work.doi)

    click.secho("Title: ", bold=True, nl=False)
    click.echo(" - ".join(work.title) if work.title else "N/A")

    if work.journal_title:
        click.secho("Journal: ", bold=True, nl=False)
        click.echo(work.journal_title)

    if work.publisher:
        click.secho("Publisher: ", bold=True, nl=False)
        click.echo(work.publisher)

    # Dates
    if work.published_print_date:
        click.secho("Published: ", bold=True, nl=False)
        click.echo(work.published_print_date.strftime("%Y-%m-%d"))

    # Volume/Issue/Page
    volume_info = []
    if work.volume:
        volume_info.append(f"Vol. {work.volume}")
    if work.issue:
        volume_info.append(f"No. {work.issue}")
    if work.page:
        volume_info.append(f"pp. {work.page}")

    if volume_info:
        click.secho("Volume: ", bold=True, nl=False)
        click.echo(" ".join(volume_info))

    # Authors
    if work.authors:
        click.secho("\nAuthors:", bold=True)
        for i, author in enumerate(work.authors, 1):
            name = (
                author.full_name
                or f"{author.given_name or ''} {author.family_name or ''}".strip()
            )
            click.echo(f"  {i}. {name}")
            if author.affiliation:
                for aff in author.affiliation:
                    click.echo(f"     - {aff}")
            if author.orcid:
                click.echo(f"     ORCID: {author.orcid}")

    # Citations
    click.secho("\nCitations: ", bold=True, nl=False)
    click.echo(f"{work.is_referenced_by_count} times")

    # References
    if work.references:
        click.secho(f"\nReferences ({work.reference_count}):", bold=True)
        dois = work.get_reference_dois()
        if dois:
            click.secho(f"  ({len(dois)} with DOI)", fg="cyan")
        for ref in work.references[:10]:  # Show first 10 references
            ref_str = f"  - {ref.author or ''}" if ref.author else "  - "
            if ref.article_title:
                ref_str += f" {ref.article_title}"
            if ref.journal_title:
                ref_str += f" ({ref.journal_title})"
            if ref.year:
                ref_str += f" ({ref.year})"
            if ref.doi:
                ref_str += f" DOI: {ref.doi}"
            click.echo(ref_str)
        if len(work.references) > 10:
            click.echo(f"  ... and {len(work.references) - 10} more references")

    # URL
    if work.url:
        click.secho("\nURL: ", bold=True, nl=False)
        click.echo(work.url)

    click.secho("\n" + "=" * 60, bold=True)
