import os
import tempfile
import types
import unittest
from unittest.mock import patch

from apps.resm.title_utils import (
    assess_title,
    extract_title_from_pdf,
    extract_title_from_xml,
    is_better_title,
)


class TitleAssessmentTests(unittest.TestCase):
    def test_normal_title_is_not_suspect(self):
        result = assess_title("Optimal Nonlinear PID Speed Control for an Electric Vehicle")
        self.assertFalse(result.suspect)

    def test_abstract_stored_as_title_is_suspect(self):
        text = (
            "In many situations, a beam opening is necessary near a plastic hinge. "
            "However, few studies investigated the resulting behavior. "
            "In this study, nine full-scale joints were tested with several configurations. "
            "The results show that additional reinforcement improves strength and ductility. "
        ) * 2
        result = assess_title(text)
        self.assertTrue(result.suspect)
        self.assertIn("abstract_like_prose", result.reasons)

    def test_mathml_markup_does_not_trigger_raw_length_false_positive(self):
        markup = "<mml:math>" + "<mml:mi>x</mml:mi>" * 100 + "</mml:math>"
        result = assess_title(f"Behavior of {markup} under pressure")
        self.assertFalse(result.suspect)

    def test_short_candidate_is_better_than_abstract(self):
        old = ("This study investigates reinforced concrete joints. " * 20).strip()
        new = "Cyclic Behavior of Reinforced Concrete Beam-Column Joints"
        self.assertTrue(is_better_title(old, new))


class XmlTitleExtractionTests(unittest.TestCase):
    def _xml_file(self, body):
        handle = tempfile.NamedTemporaryFile("w", suffix=".xml", delete=False, encoding="utf-8")
        self.addCleanup(lambda: os.path.exists(handle.name) and os.unlink(handle.name))
        handle.write(body)
        handle.close()
        return handle.name

    def test_extracts_elsevier_title_and_verifies_doi(self):
        path = self._xml_file("""<?xml version="1.0"?>
        <response xmlns:dc="http://purl.org/dc/elements/1.1/"
                  xmlns:prism="http://prismstandard.org/namespaces/basic/2.0/">
          <coredata>
            <prism:doi>10.1234/example.1</prism:doi>
            <dc:title>Correct &amp; Verified Article Title</dc:title>
          </coredata>
        </response>""")
        candidate = extract_title_from_xml(path, "10.1234/example.1")
        self.assertIsNotNone(candidate)
        self.assertEqual(candidate.title, "Correct & Verified Article Title")
        self.assertEqual(candidate.confidence, "high")

    def test_rejects_xml_for_another_doi(self):
        path = self._xml_file("""<article>
          <article-meta><article-id pub-id-type="doi">10.1234/wrong</article-id>
          <title-group><article-title>A Correct Looking Title</article-title></title-group>
          </article-meta></article>""")
        candidate = extract_title_from_xml(path, "10.1234/expected")
        self.assertIsNone(candidate)


class PdfTitleExtractionTests(unittest.TestCase):
    def test_pdf_metadata_requires_identity_evidence_and_stays_medium(self):
        handle = tempfile.NamedTemporaryFile("wb", suffix=".pdf", delete=False)
        self.addCleanup(lambda: os.path.exists(handle.name) and os.unlink(handle.name))
        handle.write(b"%PDF-placeholder")
        handle.close()

        page = types.SimpleNamespace(
            extract_text=lambda: (
                "Correct Article Title\nMohamed Shamseldin\n"
                "https://doi.org/10.1234/example.1\nAbstract"
            )
        )
        reader = types.SimpleNamespace(
            pages=[page],
            metadata=types.SimpleNamespace(title="Correct Article Title"),
        )
        module = types.SimpleNamespace(PdfReader=lambda *args, **kwargs: reader)
        with patch.dict("sys.modules", {"pypdf": module}):
            candidate = extract_title_from_pdf(
                handle.name, "10.1234/example.1", "Mohamed Shamseldin"
            )
        self.assertIsNotNone(candidate)
        self.assertEqual(candidate.title, "Correct Article Title")
        self.assertEqual(candidate.confidence, "medium")
        self.assertEqual(candidate.evidence, "pdf_metadata+doi")

    def test_rejects_layout_filename_and_keeps_first_page_low_confidence(self):
        handle = tempfile.NamedTemporaryFile("wb", suffix=".pdf", delete=False)
        self.addCleanup(lambda: os.path.exists(handle.name) and os.unlink(handle.name))
        handle.write(b"%PDF-placeholder")
        handle.close()

        page = types.SimpleNamespace(
            extract_text=lambda: (
                "Correct Article Title\nMohamed Shamseldin\n"
                "https://doi.org/10.1234/example.1\nAbstract"
            )
        )
        reader = types.SimpleNamespace(
            pages=[page], metadata=types.SimpleNamespace(title="article-layout.indd")
        )
        module = types.SimpleNamespace(PdfReader=lambda *args, **kwargs: reader)
        with patch.dict("sys.modules", {"pypdf": module}):
            candidate = extract_title_from_pdf(
                handle.name, "10.1234/example.1", "Mohamed Shamseldin"
            )
        self.assertIsNotNone(candidate)
        self.assertEqual(candidate.source, "pdf_first_page")
        self.assertEqual(candidate.confidence, "low")


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