"""
Tests for CodeMapper.

Validates: Requirements 13.2, 13.3
"""

import pytest
from datetime import datetime
from pathlib import Path
import tempfile
import yaml

from src.pipeline_mco_pmsi.referentiels import CodeMapper, CodeMapping


def test_code_mapper_initialization():
    """Test CodeMapper initialization."""
    mapper = CodeMapper()
    assert mapper.mappings_dir is not None
    assert len(mapper.cim10_mappings) == 0
    assert len(mapper.ccam_mappings) == 0


def test_add_mapping():
    """
    Test adding a code mapping.
    
    Validates: Requirement 13.2
    """
    mapper = CodeMapper()
    
    mapping = CodeMapping(
        obsolete_code="J45.0",
        current_code="J45.00",
        obsolete_label="Asthme à prédominance allergique",
        current_label="Asthme à prédominance allergique, non précisé",
        effective_date=datetime(2024, 1, 1),
        reason="split",
        notes="Code divisé"
    )
    
    mapper.add_mapping(mapping, "cim10")
    
    assert "J45.0" in mapper.cim10_mappings
    assert mapper.cim10_mappings["J45.0"].current_code == "J45.00"


def test_map_obsolete_code():
    """
    Test mapping an obsolete code to current code.
    
    Validates: Requirement 13.2
    """
    mapper = CodeMapper()
    
    mapping = CodeMapping(
        obsolete_code="J45.0",
        current_code="J45.00",
        obsolete_label="Asthme",
        current_label="Asthme précisé",
        effective_date=datetime(2024, 1, 1),
        reason="split"
    )
    
    mapper.add_mapping(mapping, "cim10")
    
    # Map obsolete code
    current = mapper.map_code("J45.0", "cim10")
    assert current == "J45.00"
    
    # Current code returns None
    current = mapper.map_code("J45.00", "cim10")
    assert current is None


def test_add_alias():
    """
    Test adding a code alias.
    
    Validates: Requirement 13.3
    """
    mapper = CodeMapper()
    
    mapper.add_alias("K29.70", "K29.7", "cim10")
    
    assert "K29.70" in mapper.cim10_aliases
    assert mapper.cim10_aliases["K29.70"] == "K29.7"


def test_map_alias_code():
    """
    Test mapping an alias code to canonical code.
    
    Validates: Requirement 13.3
    """
    mapper = CodeMapper()
    
    mapper.add_alias("K29.70", "K29.7", "cim10")
    
    # Map alias
    canonical = mapper.map_code("K29.70", "cim10")
    assert canonical == "K29.7"


def test_is_obsolete():
    """Test checking if a code is obsolete."""
    mapper = CodeMapper()
    
    mapping = CodeMapping(
        obsolete_code="J45.0",
        current_code="J45.00",
        obsolete_label="Asthme",
        current_label="Asthme précisé",
        effective_date=datetime(2024, 1, 1),
        reason="split"
    )
    
    mapper.add_mapping(mapping, "cim10")
    
    assert mapper.is_obsolete("J45.0", "cim10") is True
    assert mapper.is_obsolete("J45.00", "cim10") is False


def test_get_mapping_info():
    """Test getting detailed mapping information."""
    mapper = CodeMapper()
    
    mapping = CodeMapping(
        obsolete_code="J45.0",
        current_code="J45.00",
        obsolete_label="Asthme",
        current_label="Asthme précisé",
        effective_date=datetime(2024, 1, 1),
        reason="split",
        notes="Test note"
    )
    
    mapper.add_mapping(mapping, "cim10")
    
    info = mapper.get_mapping_info("J45.0", "cim10")
    assert info is not None
    assert info.current_code == "J45.00"
    assert info.reason == "split"
    assert info.notes == "Test note"


def test_track_label_change():
    """
    Test tracking label changes.
    
    Validates: Requirement 13.3
    """
    mapper = CodeMapper()
    
    mapper.track_label_change(
        code="K29.7",
        old_label="Gastrite, sans précision",
        new_label="Gastrite non précisée",
        referentiel_type="cim10",
        effective_date=datetime(2024, 1, 1)
    )
    
    history = mapper.get_label_history("K29.7", "cim10")
    assert len(history) == 1
    assert history[0]["old_label"] == "Gastrite, sans précision"
    assert history[0]["new_label"] == "Gastrite non précisée"


def test_load_mappings_yaml(tmp_path):
    """
    Test loading mappings from YAML file.
    
    Validates: Requirement 13.2
    """
    # Create test mapping file
    mapping_file = tmp_path / "test_mappings.yaml"
    data = {
        "referentiel_type": "cim10",
        "mappings": [
            {
                "obsolete_code": "J45.0",
                "current_code": "J45.00",
                "obsolete_label": "Asthme",
                "current_label": "Asthme précisé",
                "effective_date": "2024-01-01T00:00:00",
                "reason": "split",
                "notes": "Test"
            }
        ],
        "aliases": [
            {"alias": "K29.70", "canonical": "K29.7"}
        ]
    }
    
    with open(mapping_file, "w") as f:
        yaml.dump(data, f)
    
    mapper = CodeMapper()
    count = mapper.load_mappings("cim10", mapping_file)
    
    assert count == 1
    assert "J45.0" in mapper.cim10_mappings
    assert "K29.70" in mapper.cim10_aliases


def test_save_mappings_yaml(tmp_path):
    """Test saving mappings to YAML file."""
    mapper = CodeMapper()
    
    mapping = CodeMapping(
        obsolete_code="J45.0",
        current_code="J45.00",
        obsolete_label="Asthme",
        current_label="Asthme précisé",
        effective_date=datetime(2024, 1, 1),
        reason="split"
    )
    
    mapper.add_mapping(mapping, "cim10")
    mapper.add_alias("K29.70", "K29.7", "cim10")
    
    # Save to file
    output_file = tmp_path / "output_mappings.yaml"
    mapper.save_mappings("cim10", output_file)
    
    assert output_file.exists()
    
    # Load and verify
    with open(output_file, "r") as f:
        data = yaml.safe_load(f)
    
    assert data["referentiel_type"] == "cim10"
    assert len(data["mappings"]) == 1
    assert len(data["aliases"]) == 1


def test_get_statistics():
    """Test getting mapping statistics."""
    mapper = CodeMapper()
    
    # Add multiple mappings with different reasons
    mapper.add_mapping(
        CodeMapping(
            obsolete_code="J45.0",
            current_code="J45.00",
            obsolete_label="Asthme",
            current_label="Asthme précisé",
            effective_date=datetime(2024, 1, 1),
            reason="split"
        ),
        "cim10"
    )
    
    mapper.add_mapping(
        CodeMapping(
            obsolete_code="I25.1",
            current_code="I25.10",
            obsolete_label="Cardiopathie",
            current_label="Cardiopathie précisée",
            effective_date=datetime(2024, 1, 1),
            reason="split"
        ),
        "cim10"
    )
    
    mapper.add_mapping(
        CodeMapping(
            obsolete_code="K29.0",
            current_code="K29.00",
            obsolete_label="Gastrite",
            current_label="Gastrite aiguë",
            effective_date=datetime(2024, 1, 1),
            reason="renamed"
        ),
        "cim10"
    )
    
    mapper.add_alias("K29.70", "K29.7", "cim10")
    
    stats = mapper.get_statistics("cim10")
    
    assert stats["total_mappings"] == 3
    assert stats["total_aliases"] == 1
    assert stats["mappings_by_reason"]["split"] == 2
    assert stats["mappings_by_reason"]["renamed"] == 1


def test_ccam_mappings():
    """Test CCAM code mappings."""
    mapper = CodeMapper()
    
    mapping = CodeMapping(
        obsolete_code="YYYY001",
        current_code="YYYY002",
        obsolete_label="Ancien acte",
        current_label="Nouvel acte",
        effective_date=datetime(2025, 1, 1),
        reason="renamed"
    )
    
    mapper.add_mapping(mapping, "ccam")
    
    assert "YYYY001" in mapper.ccam_mappings
    assert mapper.map_code("YYYY001", "ccam") == "YYYY002"
    assert mapper.is_obsolete("YYYY001", "ccam") is True


def test_multiple_label_changes():
    """Test tracking multiple label changes for same code."""
    mapper = CodeMapper()
    
    # First change
    mapper.track_label_change(
        code="K29.7",
        old_label="Gastrite",
        new_label="Gastrite, sans précision",
        referentiel_type="cim10",
        effective_date=datetime(2023, 1, 1)
    )
    
    # Second change
    mapper.track_label_change(
        code="K29.7",
        old_label="Gastrite, sans précision",
        new_label="Gastrite non précisée",
        referentiel_type="cim10",
        effective_date=datetime(2024, 1, 1)
    )
    
    history = mapper.get_label_history("K29.7", "cim10")
    assert len(history) == 2
    assert history[0]["effective_date"] == "2023-01-01T00:00:00"
    assert history[1]["effective_date"] == "2024-01-01T00:00:00"


def test_load_nonexistent_file():
    """Test loading from nonexistent file raises error."""
    mapper = CodeMapper()
    
    with pytest.raises(FileNotFoundError):
        mapper.load_mappings("cim10", Path("/nonexistent/file.yaml"))


def test_unsupported_file_format(tmp_path):
    """Test loading unsupported file format raises error."""
    mapper = CodeMapper()
    
    bad_file = tmp_path / "test.txt"
    bad_file.write_text("test")
    
    with pytest.raises(ValueError, match="Unsupported file format"):
        mapper.load_mappings("cim10", bad_file)
