"""
Tests for COSING Service

Test coverage:
- parse_cas_numbers: CAS number parsing logic
- cosing_search: API search functionality
- clean_cosing: JSON cleaning and formatting
"""

import pytest
from unittest.mock import Mock, patch
from pif_compiler.services.cosing_service import (
    parse_cas_numbers,
    cosing_search,
    clean_cosing,
)


class TestParseCasNumbers:
    """Test CAS number parsing function."""

    def test_single_cas_number(self):
        """Test parsing a single CAS number."""
        result = parse_cas_numbers(["7732-18-5"])
        assert result == ["7732-18-5"]

    def test_multiple_cas_with_slash(self):
        """Test parsing multiple CAS numbers separated by slash."""
        result = parse_cas_numbers(["7732-18-5/56-81-5"])
        assert result == ["7732-18-5", "56-81-5"]

    def test_multiple_cas_with_semicolon(self):
        """Test parsing multiple CAS numbers separated by semicolon."""
        result = parse_cas_numbers(["7732-18-5;56-81-5"])
        assert result == ["7732-18-5", "56-81-5"]

    def test_multiple_cas_with_comma(self):
        """Test parsing multiple CAS numbers separated by comma."""
        result = parse_cas_numbers(["7732-18-5,56-81-5"])
        assert result == ["7732-18-5", "56-81-5"]

    def test_double_dash_separator(self):
        """Test parsing CAS numbers with double dash separator."""
        result = parse_cas_numbers(["7732-18-5--56-81-5"])
        assert result == ["7732-18-5", "56-81-5"]

    def test_cas_with_parentheses(self):
        """Test that parenthetical info is removed."""
        result = parse_cas_numbers(["7732-18-5 (hydrate)"])
        assert result == ["7732-18-5"]

    def test_cas_with_extra_whitespace(self):
        """Test that extra whitespace is trimmed."""
        result = parse_cas_numbers(["  7732-18-5  /  56-81-5  "])
        assert result == ["7732-18-5", "56-81-5"]

    def test_removes_invalid_dash(self):
        """Test that standalone dashes are removed."""
        result = parse_cas_numbers(["7732-18-5/-/56-81-5"])
        assert result == ["7732-18-5", "56-81-5"]

    def test_complex_mixed_separators(self):
        """Test with multiple separator types."""
        result = parse_cas_numbers(["7732-18-5/56-81-5;50-00-0"])
        assert result == ["7732-18-5", "56-81-5", "50-00-0"]


class TestCosingSearch:
    """Test COSING API search functionality."""

    @patch('pif_compiler.services.cosing_service.req.post')
    def test_search_by_name_success(self, mock_post):
        """Test successful search by ingredient name."""
        # Mock API response
        mock_response = Mock()
        mock_response.json.return_value = {
            "results": [{
                "metadata": {
                    "inciName": ["WATER"],
                    "casNo": ["7732-18-5"],
                    "substanceId": ["12345"]
                }
            }]
        }
        mock_post.return_value = mock_response

        result = cosing_search("WATER", mode="name")

        assert result is not None
        assert result["inciName"] == ["WATER"]
        assert result["casNo"] == ["7732-18-5"]

    @patch('pif_compiler.services.cosing_service.req.post')
    def test_search_by_cas_success(self, mock_post):
        """Test successful search by CAS number."""
        mock_response = Mock()
        mock_response.json.return_value = {
            "results": [{
                "metadata": {
                    "inciName": ["WATER"],
                    "casNo": ["7732-18-5"]
                }
            }]
        }
        mock_post.return_value = mock_response

        result = cosing_search("7732-18-5", mode="cas")

        assert result is not None
        assert "7732-18-5" in result["casNo"]

    @patch('pif_compiler.services.cosing_service.req.post')
    def test_search_by_ec_success(self, mock_post):
        """Test successful search by EC number."""
        mock_response = Mock()
        mock_response.json.return_value = {
            "results": [{
                "metadata": {
                    "ecNo": ["231-791-2"]
                }
            }]
        }
        mock_post.return_value = mock_response

        result = cosing_search("231-791-2", mode="ec")

        assert result is not None
        assert "231-791-2" in result["ecNo"]

    @patch('pif_compiler.services.cosing_service.req.post')
    def test_search_by_id_success(self, mock_post):
        """Test successful search by substance ID."""
        mock_response = Mock()
        mock_response.json.return_value = {
            "results": [{
                "metadata": {
                    "substanceId": ["12345"]
                }
            }]
        }
        mock_post.return_value = mock_response

        result = cosing_search("12345", mode="id")

        assert result is not None
        assert result["substanceId"] == ["12345"]

    @patch('pif_compiler.services.cosing_service.req.post')
    def test_search_no_results(self, mock_post):
        """Test search with no results returns status code."""
        mock_response = Mock()
        mock_response.json.return_value = {"results": []}
        mock_post.return_value = mock_response

        result = cosing_search("NONEXISTENT", mode="name")
        assert result == None  # Should return None

    def test_search_invalid_mode(self):
        """Test that invalid mode raises ValueError."""
        with pytest.raises(ValueError):
            cosing_search("WATER", mode="invalid_mode")


class TestCleanCosing:
    """Test COSING JSON cleaning function."""

    def test_clean_basic_fields(self, sample_cosing_response):
        """Test cleaning basic string and list fields."""

        result = clean_cosing(sample_cosing_response, full=False)

        assert result["inciName"] == "WATER"
        assert result["casNo"] == ["7732-18-5"]
        assert result["ecNo"] == ["231-791-2"]

    def test_removes_empty_tags(self, sample_cosing_response):
        """Test that <empty> tags are removed."""
        
        sample_cosing_response["inciName"] = ["<empty>"]
        sample_cosing_response["functionName"] = ["<empty>"]
        
        result = clean_cosing(sample_cosing_response, full=False)

        assert "<empty>" not in result["inciName"]
        assert result["functionName"] == []

    def test_parses_cas_numbers(self, sample_cosing_response):
        """Test that CAS numbers are parsed correctly."""
        sample_cosing_response["casNo"] = ["56-81-5"]

        result = clean_cosing(sample_cosing_response, full=False)

        assert result["casNo"] == ["56-81-5"]

    def test_creates_cosing_url(self, sample_cosing_response):
        """Test that COSING URL is created."""
        result = clean_cosing(sample_cosing_response, full=False)

        assert "cosingUrl" in result
        assert "12345" in result["cosingUrl"]
        assert result["cosingUrl"] == "https://ec.europa.eu/growth/tools-databases/cosing/details/12345"

    def test_renames_common_name(self, sample_cosing_response):
        """Test that nameOfCommonIngredientsGlossary is renamed."""
        result = clean_cosing(sample_cosing_response, full=False)

        assert "commonName" in result
        assert result["commonName"] == "Water"
        assert "nameOfCommonIngredientsGlossary" not in result

    def test_empty_lists_handled(self, sample_cosing_response):
        """Test that empty lists are handled correctly."""
        sample_cosing_response["inciName"] = []
        sample_cosing_response["casNo"] = []

        result = clean_cosing(sample_cosing_response, full=False)

        assert result["inciName"] == ""
        assert result["casNo"] == []


class TestIntegration:
    """Integration tests with real API (marked as slow)."""

    @pytest.mark.integration
    def test_real_water_search(self):
        """Test real API call for WATER (requires internet)."""
        result = cosing_search("WATER", mode="name")

        if result and isinstance(result, dict):
            # Real API call succeeded
            assert "inciName" in result or "casNo" in result

    @pytest.mark.integration
    def test_real_cas_search(self):
        """Test real API call by CAS number (requires internet)."""
        result = cosing_search("56-81-5", mode="cas")

        if result and isinstance(result, dict):
            assert "casNo" in result

    @pytest.mark.integration
    def test_full_workflow(self):
        """Test complete workflow: search -> clean."""
        # Search for glycerin
        raw_result = cosing_search("GLYCERIN", mode="name")

        if raw_result and isinstance(raw_result, dict):
            # Clean the result
            clean_result = clean_cosing(raw_result, full=False)

            # Verify cleaned structure
            assert "cosingUrl" in clean_result
            assert isinstance(clean_result.get("casNo"), list)
