"""
Test suite for Ingenta Connect dance function.
Tests CLAUDE.md compliant implementation with DOI patterns.

Test approach:
- Tests simple DOI resolution + URL transformation pattern
- Validates CLAUDE.md compliance (no huge try-except, standard verification)
- Uses real PMIDs: 38884108, 34707797
"""

import unittest
from unittest.mock import patch, Mock

from metapub.findit.dances.ingenta import the_ingenta_flux
from metapub.exceptions import AccessDenied, NoPDFLink
from metapub import PubMedFetcher
from tests.fixtures import load_pmid_xml, INGENTACONNECT_EVIDENCE_PMIDS


class TestIngentaConnectDance(unittest.TestCase):
    """Evidence-driven test suite for Ingenta Connect dance function"""

    def setUp(self):
        """Set up test fixtures with real evidence PMIDs"""
        self.fetch = PubMedFetcher()
        
        # Real evidence PMIDs from Ingenta Connect with diverse DOI patterns
        self.evidence_pmids = [
            '38884108',  # DOI: 10.5129/001041522x16222193902161 (Comp Polit)
            '34707797'   # DOI: 10.21300/21.4.2021.7 (Technol Innov)
        ]
        
        # Create mock PMA with evidence data
        self.mock_pma = Mock()
        self.mock_pma.doi = '10.5129/001041522x16222193902161'
        self.mock_pma.journal = 'Comp Polit'
        self.mock_pma.pmid = '38884108'


    @patch('metapub.findit.dances.ingenta.the_doi_2step')
    def test_doi_resolution_and_url_transformation(self, mock_doi_2step):
        """Test DOI resolution and URL pattern transformation"""
        # Mock DOI resolution to return Ingenta Connect article URL
        mock_doi_2step.return_value = 'https://www.ingentaconnect.com/content/cuny/cp/2022/00000054/00000002/art00007'
        
        result = the_ingenta_flux(self.mock_pma, verify=False)
        
        expected_url = 'https://www.ingentaconnect.com/contentone/cuny/cp/2022/00000054/00000002/art00007/pdf'
        self.assertEqual(result, expected_url)
        mock_doi_2step.assert_called_once_with(self.mock_pma.doi)

    @patch('metapub.findit.dances.ingenta.verify_pdf_url')
    @patch('metapub.findit.dances.ingenta.the_doi_2step')
    def test_verification_success(self, mock_doi_2step, mock_verify):
        """Test successful verification using standard verify_pdf_url"""
        mock_doi_2step.return_value = 'https://www.ingentaconnect.com/content/cuny/cp/2022/00000054/00000002/art00007'
        expected_pdf_url = 'https://www.ingentaconnect.com/contentone/cuny/cp/2022/00000054/00000002/art00007/pdf'
        mock_verify.return_value = expected_pdf_url
        
        result = the_ingenta_flux(self.mock_pma, verify=True)
        
        self.assertEqual(result, expected_pdf_url)
        mock_verify.assert_called_once_with(expected_pdf_url, 'Ingenta Connect', request_timeout=10, max_redirects=3)

    @patch('metapub.findit.dances.ingenta.verify_pdf_url')
    @patch('metapub.findit.dances.ingenta.the_doi_2step')
    def test_verification_access_denied_bubbles_up(self, mock_doi_2step, mock_verify):
        """Test that AccessDenied from verify_pdf_url bubbles up correctly"""
        mock_doi_2step.return_value = 'https://www.ingentaconnect.com/content/cuny/cp/2022/00000054/00000002/art00007'
        expected_pdf_url = 'https://www.ingentaconnect.com/contentone/cuny/cp/2022/00000054/00000002/art00007/pdf'
        mock_verify.side_effect = AccessDenied('DENIED: Access forbidden')
        
        with self.assertRaises(AccessDenied):
            the_ingenta_flux(self.mock_pma, verify=True)

    @patch('metapub.findit.dances.ingenta.the_doi_2step')
    def test_non_ingenta_domain_raises_invalid(self, mock_doi_2step):
        """Test that DOI resolving to non-Ingenta domain raises NoPDFLink"""
        mock_doi_2step.return_value = 'https://other-publisher.com/article'
        
        with self.assertRaises(NoPDFLink) as context:
            the_ingenta_flux(self.mock_pma, verify=False)
        
        self.assertIn('INVALID:', str(context.exception))
        self.assertIn('did not resolve to Ingenta Connect domain', str(context.exception))

    @patch('metapub.findit.dances.ingenta.the_doi_2step')
    def test_unexpected_url_pattern_raises_invalid(self, mock_doi_2step):
        """Test that unexpected URL pattern raises NoPDFLink"""
        mock_doi_2step.return_value = 'https://www.ingentaconnect.com/other-pattern/article'
        
        with self.assertRaises(NoPDFLink) as context:
            the_ingenta_flux(self.mock_pma, verify=False)
        
        self.assertIn('INVALID:', str(context.exception))
        self.assertIn('expected /content/', str(context.exception))

    def test_real_pmid_metadata_validation(self):
        """Test with real PMID metadata to validate approach"""
        try:
            # Use first evidence PMID
            pma = self.fetch.article_by_pmid(self.evidence_pmids[0])
            
            # Validate we have expected data
            self.assertIsNotNone(pma.doi)
            self.assertEqual(pma.journal, 'Comp Polit')
            
            # Test URL construction without verification
            result = the_ingenta_flux(pma, verify=False)
            self.assertIn('ingentaconnect.com', result)
            self.assertIn('/contentone/', result)
            self.assertTrue(result.endswith('/pdf'))
            
            print(f"Real PMID validation: DOI={pma.doi}, Journal={pma.journal}")
            print(f"PDF URL: {result}")
            
        except Exception as e:
            self.skipTest(f"Could not fetch real PMID data: {e}")


    def test_evidence_based_url_transformation(self):
        """Test that URL transformation follows evidence-based pattern"""
        test_cases = [
            # (article_url, expected_pdf_url)
            (
                'https://www.ingentaconnect.com/content/cuny/cp/2022/00000054/00000002/art00007',
                'https://www.ingentaconnect.com/contentone/cuny/cp/2022/00000054/00000002/art00007/pdf'
            ),
            (
                'https://www.ingentaconnect.com/content/nai/ti/2021/00000022/00000001/art00007',
                'https://www.ingentaconnect.com/contentone/nai/ti/2021/00000022/00000001/art00007/pdf'
            ),
            # Test with session ID (should be preserved)
            (
                'https://www.ingentaconnect.com/content/pub/journal/2023/vol/issue/article;jsessionid=123',
                'https://www.ingentaconnect.com/contentone/pub/journal/2023/vol/issue/article;jsessionid=123/pdf'
            )
        ]
        
        for article_url, expected_pdf_url in test_cases:
            with patch('metapub.findit.dances.ingenta.the_doi_2step') as mock_doi:
                mock_doi.return_value = article_url
                
                result = the_ingenta_flux(self.mock_pma, verify=False)
                self.assertEqual(result, expected_pdf_url)



    def test_multi_publisher_platform_handling(self):
        """Test that function handles Ingenta Connect's multi-publisher nature"""
        # Ingenta Connect hosts content from 250+ publishers with diverse DOI prefixes
        diverse_dois = [
            '10.5129/001041522x16222193902161',  # Evidence DOI 1
            '10.21300/21.4.2021.7',             # Evidence DOI 2
            '10.3751/example.2023.123',         # Different publisher pattern
            '10.5588/test.2024.456'             # Another publisher pattern
        ]
        
        for doi in diverse_dois:
            pma = Mock()
            pma.doi = doi
            
            with patch('metapub.findit.dances.ingenta.the_doi_2step') as mock_doi:
                mock_doi.return_value = f'https://www.ingentaconnect.com/content/pub/journal/2023/vol/issue/article'
                
                result = the_ingenta_flux(pma, verify=False)
                self.assertIn('/contentone/', result)
                self.assertTrue(result.endswith('/pdf'))


def test_ingentaconnect_journal_recognition():
    """Test that Ingenta Connect journals are properly recognized in the registry."""
    from metapub.findit.registry import JournalRegistry

    registry = JournalRegistry()

    # Test sample Ingenta Connect journals
    test_journals = [
        'Comp Polit',
        'Technol Innov', 
        'Middle East J',
        'Public Health Action',
        'J Biomed Nanotechnol'
    ]

    # Test journal recognition using registry
    found_count = 0
    for journal in test_journals:
        publisher_info = registry.get_publisher_for_journal(journal)
        if publisher_info and publisher_info['name'] == 'ingentaconnect':
            assert publisher_info['dance_function'] == 'the_ingenta_flux'
            print(f"✓ {journal} correctly mapped to Ingenta Connect")
            found_count += 1
        else:
            print(f"⚠ {journal} mapped to different publisher: {publisher_info['name'] if publisher_info else 'None'}")

    # Just make sure we found at least one Ingenta Connect journal
    if found_count == 0:
        print("⚠ No Ingenta Connect journals found in registry - this may be expected if registry not populated")
    else:
        print(f"✓ Found {found_count} properly mapped Ingenta Connect journals")

    registry.close()




class TestIngentaConnectXMLFixtures:
    """Test IngentaConnect dance function with real XML fixtures."""

    def test_ingentaconnect_authentic_metadata_validation(self):
        """Validate authentic metadata from XML fixtures matches expected patterns."""
        for pmid, expected in INGENTACONNECT_EVIDENCE_PMIDS.items():
            pma = load_pmid_xml(pmid)
            assert pma.doi == expected['doi']
            assert pma.journal == expected['journal']
            assert pma.pmid == pmid
            print(f"✓ PMID {pmid}: {pma.journal} - {pma.doi}")

    def test_ingentaconnect_doi_pattern_consistency(self):
        """Test DOI patterns consistency."""
        for pmid, data in INGENTACONNECT_EVIDENCE_PMIDS.items():
            pma = load_pmid_xml(pmid)
            assert pma.doi == data['doi']
            print(f"✓ PMID {pmid} DOI consistent: {pma.doi}")


if __name__ == '__main__':
    # Run comprehensive test suite
    unittest.main(verbosity=2)
