import json
import tempfile
import unittest
from pathlib import Path

from core.skills import SkillRegistry
from skills.literature.scripts.merge_publications import (
    exact_key,
    main,
    merge_publications,
    normalize_doi,
    normalize_isbn,
    normalize_record,
)


ROOT = Path(__file__).resolve().parents[1]


class LiteratureSkillTests(unittest.TestCase):
    def test_literature_is_the_only_publication_search_skill(self) -> None:
        registry = SkillRegistry(ROOT / "skills")
        self.assertIn("literature", registry.skills)
        self.assertNotIn("research", registry.skills)
        self.assertNotIn("documents", registry.skills)


class LiteratureNormalizationTests(unittest.TestCase):
    def test_normalizes_doi_and_isbn(self) -> None:
        self.assertEqual(normalize_doi("https://doi.org/10.1000/ABC.1."), "10.1000/abc.1")
        self.assertEqual(normalize_isbn("0-306-40615-2"), "9780306406157")

    def test_preserves_unknown_raw_type(self) -> None:
        record = normalize_record({"title": "A", "type": "future-object"}, "future")
        self.assertEqual(record["type"], "other")
        self.assertEqual(record["raw_type"], "future-object")

    def test_different_book_editions_have_different_keys(self) -> None:
        first = normalize_record(
            {"title": "Materials", "type": "book", "isbn": "9780306406157", "edition": "1st"},
            "books",
        )
        second = normalize_record(
            {"title": "Materials", "type": "book", "isbn": "9780306406157", "edition": "2nd"},
            "books",
        )
        self.assertNotEqual(exact_key(first), exact_key(second))

    def test_preserves_date_and_relations(self) -> None:
        record = normalize_record(
            {
                "title": "Chapter",
                "type": "book-chapter",
                "publication_date": "2025-03-09",
                "is_part_of": "Book A",
            },
            "books",
        )
        self.assertEqual(record["issued"], {"year": 2025, "month": 3, "day": 9})
        self.assertEqual(record["relations"]["is_part_of"], "Book A")


class LiteratureMergeTests(unittest.TestCase):
    def test_merges_same_doi_and_preserves_sources(self) -> None:
        result = merge_publications([
            ("paper_server", {"id": "p1", "doi": "10.1/ABC", "title": "Title", "abstract": "A"}),
            ("materials_library", {"id": "m1", "doi": "https://doi.org/10.1/abc", "title": "Title"}),
        ])
        self.assertEqual(len(result["publications"]), 1)
        self.assertEqual(
            {source["backend"] for source in result["publications"][0]["sources"]},
            {"paper_server", "materials_library"},
        )

    def test_does_not_merge_chapter_with_book(self) -> None:
        result = merge_publications([
            ("source", {"title": "Hydration", "type": "book", "first_author": "Li", "year": 2024}),
            ("source", {"title": "Hydration", "type": "book_chapter", "first_author": "Li", "year": 2024}),
        ])
        self.assertEqual(len(result["publications"]), 2)

    def test_keeps_standard_revisions_and_patent_family_members(self) -> None:
        result = merge_publications([
            ("standards", {"title": "Method", "type": "standard", "standard_number": "GB/T 1", "publisher": "SAC", "year": 2020}),
            ("standards", {"title": "Method", "type": "standard", "standard_number": "GB/T 1", "publisher": "SAC", "year": 2025}),
            ("patents", {"title": "Binder", "type": "patent", "patent_publication_number": "CN100A", "patent_family": "F1"}),
            ("patents", {"title": "Binder", "type": "patent", "patent_publication_number": "US100B", "patent_family": "F1"}),
        ])
        self.assertEqual(len(result["publications"]), 4)

    def test_marks_similar_titles_as_possible_duplicates(self) -> None:
        result = merge_publications([
            ("a", {"title": "Hydration of low carbon cement systems", "type": "article", "year": 2024}),
            ("b", {"title": "Hydration of low-carbon cement system", "type": "article", "year": 2024}),
        ])
        self.assertEqual(len(result["publications"]), 2)
        self.assertEqual(len(result["possible_duplicates"]), 1)

    def test_cli_writes_output(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp)
            source = root / "source.json"
            output = root / "output.json"
            source.write_text(json.dumps([{"title": "A", "doi": "10.1/a"}]), encoding="utf-8")
            self.assertEqual(main(["--input", f"paper_server={source}", "--output", str(output)]), 0)
            self.assertEqual(len(json.loads(output.read_text(encoding="utf-8"))["publications"]), 1)


if __name__ == "__main__":
    unittest.main()
