"""Tests for the huntpdf CLI."""

import json
import subprocess
import sys
from pathlib import Path
from unittest.mock import MagicMock

import pytest

from huntpdf.cli import fetch, main
from huntpdf.errors import InputNotRecognized, PDFNotFound


class TestFetch:
    def test_dispatches_arxiv(self, monkeypatch, tmp_path):
        expected = tmp_path / "paper.pdf"
        mock = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.cli.resolve_arxiv", mock)
        result = fetch("2301.07041", expected)
        assert result == expected
        mock.assert_called_once_with("2301.07041", expected)

    def test_dispatches_doi(self, monkeypatch, tmp_path):
        expected = tmp_path / "paper.pdf"
        mock = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.cli.resolve_doi", mock)
        result = fetch("10.1038/nature12373", expected)
        assert result == expected
        mock.assert_called_once_with("10.1038/nature12373", expected)

    def test_dispatches_pmc(self, monkeypatch, tmp_path):
        expected = tmp_path / "paper.pdf"
        mock = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.cli.resolve_pmc", mock)
        result = fetch("PMC4056847", expected)
        assert result == expected
        mock.assert_called_once_with("PMC4056847", expected)

    def test_dispatches_pmid(self, monkeypatch, tmp_path):
        expected = tmp_path / "paper.pdf"
        mock = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.cli.resolve_pubmed", mock)
        result = fetch("25428566", expected)
        assert result == expected
        mock.assert_called_once_with("25428566", expected)

    def test_dispatches_url(self, monkeypatch, tmp_path):
        expected = tmp_path / "paper.pdf"
        mock = MagicMock(return_value=expected)
        monkeypatch.setattr("huntpdf.cli.resolve_url", mock)
        result = fetch("https://arxiv.org/abs/2301.07041", expected)
        assert result == expected
        mock.assert_called_once_with("https://arxiv.org/abs/2301.07041", expected)

    def test_unrecognized_input_raises(self):
        with pytest.raises(InputNotRecognized):
            fetch("not-a-thing")


class TestMainCLI:
    def test_success_json_output(self, monkeypatch, capsys, tmp_path):
        pdf_path = tmp_path / "result.pdf"
        monkeypatch.setattr(
            "huntpdf.cli.fetch", MagicMock(return_value=pdf_path)
        )
        main(["2301.07041"])
        output = json.loads(capsys.readouterr().out)
        assert output["status"] == "success"
        assert "pdf_path" in output

    def test_failure_json_output(self, monkeypatch, capsys):
        monkeypatch.setattr(
            "huntpdf.cli.fetch",
            MagicMock(side_effect=PDFNotFound("test error")),
        )
        with pytest.raises(SystemExit) as exc_info:
            main(["2301.07041"])
        assert exc_info.value.code == 1
        output = json.loads(capsys.readouterr().out)
        assert output["status"] == "failure"
        assert output["error"] == "test error"
        assert "pdf_path" not in output

    def test_output_flag(self, monkeypatch, tmp_path):
        pdf_path = tmp_path / "custom.pdf"
        mock_fetch = MagicMock(return_value=pdf_path)
        monkeypatch.setattr("huntpdf.cli.fetch", mock_fetch)
        main(["2301.07041", "--output", str(pdf_path)])
        call_args = mock_fetch.call_args
        assert call_args[0][1] == pdf_path

    def test_no_output_flag_passes_none(self, monkeypatch, tmp_path):
        mock_fetch = MagicMock(return_value=tmp_path / "auto.pdf")
        monkeypatch.setattr("huntpdf.cli.fetch", mock_fetch)
        main(["2301.07041"])
        call_args = mock_fetch.call_args
        assert call_args[0][1] is None

    def test_entrypoint_runs(self):
        result = subprocess.run(
            [sys.executable, "-m", "huntpdf.cli", "--help"],
            capture_output=True,
            text=True,
        )
        assert result.returncode == 0
        assert "huntpdf" in result.stdout
