"""
자재 분류기 테스트
"""
import pytest
from unittest.mock import patch


class TestPipeClassifier:
    """파이프 분류기 테스트"""
    
    def test_pipe_classification_basic(self):
        """기본 파이프 분류 테스트"""
        from app.services.pipe_classifier import classify_pipe
        
        # 명확한 파이프 케이스
        result = classify_pipe("", "PIPE, SEAMLESS, A333-6, 6\", SCH40", "6\"", 1000)
        
        assert result["category"] == "PIPE"
        assert result["confidence"] > 0.8
        assert result["material_grade"] == "A333-6"
        assert result["schedule"] == "SCH40"
        assert result["size"] == "6\""
    
    def test_pipe_classification_welded(self):
        """용접 파이프 분류 테스트"""
        from app.services.pipe_classifier import classify_pipe
        
        result = classify_pipe("", "PIPE, WELDED, A53-B, 4\", SCH40", "4\"", 500)
        
        assert result["category"] == "PIPE"
        assert result["subcategory"] == "WELDED"
        assert result["material_grade"] == "A53-B"
        assert result["confidence"] > 0.8
    
    def test_pipe_classification_low_confidence(self):
        """낮은 신뢰도 파이프 분류 테스트"""
        from app.services.pipe_classifier import classify_pipe
        
        # 모호한 설명
        result = classify_pipe("", "STEEL TUBE, 2 INCH", "2\"", 100)
        
        # 파이프로 분류되지만 신뢰도가 낮아야 함
        assert result["confidence"] < 0.7
    
    def test_pipe_length_calculation(self):
        """파이프 길이 계산 테스트"""
        from app.services.pipe_classifier import classify_pipe
        
        result = classify_pipe("", "PIPE, SEAMLESS, A333-6, 6\", SCH40", "6\"", 6000)
        
        assert "length_mm" in result
        assert result["length_mm"] == 6000
        assert "purchase_length" in result


class TestFittingClassifier:
    """피팅 분류기 테스트"""
    
    def test_elbow_classification(self):
        """엘보우 분류 테스트"""
        from app.services.fitting_classifier import classify_fitting
        
        result = classify_fitting("", "ELBOW, 90DEG, A234-WPB, 4\", SCH40")
        
        assert result["category"] == "FITTING"
        assert result["subcategory"] == "ELBOW"
        assert result["angle"] == "90DEG"
        assert result["material_grade"] == "A234-WPB"
        assert result["confidence"] > 0.8
    
    def test_tee_classification(self):
        """티 분류 테스트"""
        from app.services.fitting_classifier import classify_fitting
        
        result = classify_fitting("", "TEE, EQUAL, A234-WPB, 6\", SCH40")
        
        assert result["category"] == "FITTING"
        assert result["subcategory"] == "TEE"
        assert result["fitting_type"] == "EQUAL"
        assert result["confidence"] > 0.8
    
    def test_reducer_classification(self):
        """리듀서 분류 테스트"""
        from app.services.fitting_classifier import classify_fitting
        
        result = classify_fitting("", "REDUCER, CONCENTRIC, A234-WPB, 8\"X6\", SCH40")
        
        assert result["category"] == "FITTING"
        assert result["subcategory"] == "REDUCER"
        assert result["fitting_type"] == "CONCENTRIC"
        assert "8\"X6\"" in result["size"]


class TestValveClassifier:
    """밸브 분류기 테스트"""
    
    def test_gate_valve_classification(self):
        """게이트 밸브 분류 테스트"""
        from app.services.valve_classifier import classify_valve
        
        result = classify_valve("", "VALVE, GATE, A216-WCB, 2\", 150LB")
        
        assert result["category"] == "VALVE"
        assert result["subcategory"] == "GATE"
        assert result["material_grade"] == "A216-WCB"
        assert result["pressure_rating"] == "150LB"
        assert result["confidence"] > 0.8
    
    def test_ball_valve_classification(self):
        """볼 밸브 분류 테스트"""
        from app.services.valve_classifier import classify_valve
        
        result = classify_valve("", "VALVE, BALL, A216-WCB, 4\", 300LB")
        
        assert result["category"] == "VALVE"
        assert result["subcategory"] == "BALL"
        assert result["pressure_rating"] == "300LB"
        assert result["confidence"] > 0.8
    
    def test_check_valve_classification(self):
        """체크 밸브 분류 테스트"""
        from app.services.valve_classifier import classify_valve
        
        result = classify_valve("", "VALVE, CHECK, SWING, A216-WCB, 3\", 150LB")
        
        assert result["category"] == "VALVE"
        assert result["subcategory"] == "CHECK"
        assert result["valve_type"] == "SWING"


class TestFlangeClassifier:
    """플랜지 분류기 테스트"""
    
    def test_weld_neck_flange_classification(self):
        """용접목 플랜지 분류 테스트"""
        from app.services.flange_classifier import classify_flange
        
        result = classify_flange("", "FLANGE, WELD NECK, A105, 3\", 150LB")
        
        assert result["category"] == "FLANGE"
        assert result["subcategory"] == "WELD NECK"
        assert result["material_grade"] == "A105"
        assert result["pressure_rating"] == "150LB"
        assert result["confidence"] > 0.8
    
    def test_slip_on_flange_classification(self):
        """슬립온 플랜지 분류 테스트"""
        from app.services.flange_classifier import classify_flange
        
        result = classify_flange("", "FLANGE, SLIP ON, A105, 4\", 300LB")
        
        assert result["category"] == "FLANGE"
        assert result["subcategory"] == "SLIP ON"
        assert result["pressure_rating"] == "300LB"
        assert result["confidence"] > 0.8
    
    def test_blind_flange_classification(self):
        """블라인드 플랜지 분류 테스트"""
        from app.services.flange_classifier import classify_flange
        
        result = classify_flange("", "FLANGE, BLIND, A105, 6\", 150LB")
        
        assert result["category"] == "FLANGE"
        assert result["subcategory"] == "BLIND"
        assert result["confidence"] > 0.8


class TestBoltClassifier:
    """볼트 분류기 테스트"""
    
    def test_hex_bolt_classification(self):
        """육각 볼트 분류 테스트"""
        from app.services.bolt_classifier import classify_bolt
        
        result = classify_bolt("", "BOLT, HEX HEAD, A193-B7, M16X50")
        
        assert result["category"] == "BOLT"
        assert result["subcategory"] == "HEX HEAD"
        assert result["material_grade"] == "A193-B7"
        assert result["size"] == "M16X50"
        assert result["confidence"] > 0.8
    
    def test_stud_bolt_classification(self):
        """스터드 볼트 분류 테스트"""
        from app.services.bolt_classifier import classify_bolt
        
        result = classify_bolt("", "STUD BOLT, A193-B7, M20X80")
        
        assert result["category"] == "BOLT"
        assert result["subcategory"] == "STUD"
        assert result["material_grade"] == "A193-B7"
        assert result["confidence"] > 0.8
    
    def test_nut_classification(self):
        """너트 분류 테스트"""
        from app.services.bolt_classifier import classify_bolt
        
        result = classify_bolt("", "NUT, HEX, A194-2H, M16")
        
        assert result["category"] == "BOLT"
        assert result["subcategory"] == "NUT"
        assert result["material_grade"] == "A194-2H"
        assert result["confidence"] > 0.8


class TestGasketClassifier:
    """가스켓 분류기 테스트"""
    
    def test_spiral_wound_gasket_classification(self):
        """스파이럴 와운드 가스켓 분류 테스트"""
        from app.services.gasket_classifier import classify_gasket
        
        result = classify_gasket("", "GASKET, SPIRAL WOUND, SS316+GRAPHITE, 4\", 150LB")
        
        assert result["category"] == "GASKET"
        assert result["subcategory"] == "SPIRAL WOUND"
        assert "SS316" in result["material_grade"]
        assert result["confidence"] > 0.8
    
    def test_rtj_gasket_classification(self):
        """RTJ 가스켓 분류 테스트"""
        from app.services.gasket_classifier import classify_gasket
        
        result = classify_gasket("", "GASKET, RTJ, SS316, 6\", 300LB")
        
        assert result["category"] == "GASKET"
        assert result["subcategory"] == "RTJ"
        assert result["material_grade"] == "SS316"
        assert result["confidence"] > 0.8
    
    def test_flat_gasket_classification(self):
        """플랫 가스켓 분류 테스트"""
        from app.services.gasket_classifier import classify_gasket
        
        result = classify_gasket("", "GASKET, FLAT, RUBBER, 2\", 150LB")
        
        assert result["category"] == "GASKET"
        assert result["subcategory"] == "FLAT"
        assert result["material_grade"] == "RUBBER"
        assert result["confidence"] > 0.8


class TestInstrumentClassifier:
    """계기 분류기 테스트"""
    
    def test_pressure_gauge_classification(self):
        """압력계 분류 테스트"""
        from app.services.instrument_classifier import classify_instrument
        
        result = classify_instrument("", "PRESSURE GAUGE, 0-10 BAR, 1/2\" NPT")
        
        assert result["category"] == "INSTRUMENT"
        assert result["subcategory"] == "PRESSURE GAUGE"
        assert "0-10 BAR" in result["range"]
        assert result["confidence"] > 0.8
    
    def test_temperature_gauge_classification(self):
        """온도계 분류 테스트"""
        from app.services.instrument_classifier import classify_instrument
        
        result = classify_instrument("", "TEMPERATURE GAUGE, 0-200°C, 1/2\" NPT")
        
        assert result["category"] == "INSTRUMENT"
        assert result["subcategory"] == "TEMPERATURE GAUGE"
        assert "0-200°C" in result["range"]
        assert result["confidence"] > 0.8
    
    def test_flow_meter_classification(self):
        """유량계 분류 테스트"""
        from app.services.instrument_classifier import classify_instrument
        
        result = classify_instrument("", "FLOW METER, ORIFICE, 4\", 150LB")
        
        assert result["category"] == "INSTRUMENT"
        assert result["subcategory"] == "FLOW METER"
        assert result["instrument_type"] == "ORIFICE"
        assert result["confidence"] > 0.8


class TestIntegratedClassifier:
    """통합 분류기 테스트"""
    
    def test_integrated_classification_pipe(self):
        """통합 분류기 파이프 테스트"""
        from app.services.integrated_classifier import classify_material_integrated
        
        result = classify_material_integrated("PIPE, SEAMLESS, A333-6, 6\", SCH40")
        
        assert result["category"] == "PIPE"
        assert result["confidence"] > 0.8
        assert "classification_details" in result
    
    def test_integrated_classification_valve(self):
        """통합 분류기 밸브 테스트"""
        from app.services.integrated_classifier import classify_material_integrated
        
        result = classify_material_integrated("VALVE, GATE, A216-WCB, 2\", 150LB")
        
        assert result["category"] == "VALVE"
        assert result["confidence"] > 0.8
    
    def test_exclusion_logic(self):
        """제외 로직 테스트"""
        from app.services.integrated_classifier import should_exclude_material
        
        # 제외되어야 하는 항목들
        assert should_exclude_material("INSULATION, MINERAL WOOL") is True
        assert should_exclude_material("PAINT, PRIMER") is True
        assert should_exclude_material("SUPPORT, STRUCTURAL") is True
        
        # 제외되지 않아야 하는 항목들
        assert should_exclude_material("PIPE, SEAMLESS, A333-6") is False
        assert should_exclude_material("VALVE, GATE, A216-WCB") is False
    
    def test_confidence_threshold(self):
        """신뢰도 임계값 테스트"""
        from app.services.integrated_classifier import classify_material_integrated
        
        # 모호한 설명으로 낮은 신뢰도 테스트
        result = classify_material_integrated("STEEL ITEM, UNKNOWN TYPE")
        
        # 신뢰도가 낮아야 함
        assert result["confidence"] < 0.5
        assert result["category"] in ["UNKNOWN", "EXCLUDE"]


class TestClassificationCaching:
    """분류 결과 캐싱 테스트"""
    
    @patch('app.services.integrated_classifier.tkmp_cache')
    def test_classification_cache_hit(self, mock_cache):
        """분류 결과 캐시 히트 테스트"""
        from app.services.integrated_classifier import classify_material_integrated
        
        # 캐시에서 결과 반환 설정
        cached_result = {
            "category": "PIPE",
            "confidence": 0.95,
            "cached": True
        }
        mock_cache.get_classification_result.return_value = cached_result
        
        result = classify_material_integrated("PIPE, SEAMLESS, A333-6, 6\", SCH40")
        
        assert result == cached_result
        mock_cache.get_classification_result.assert_called_once()
    
    @patch('app.services.integrated_classifier.tkmp_cache')
    def test_classification_cache_miss(self, mock_cache):
        """분류 결과 캐시 미스 테스트"""
        from app.services.integrated_classifier import classify_material_integrated
        
        # 캐시에서 None 반환 (캐시 미스)
        mock_cache.get_classification_result.return_value = None
        
        result = classify_material_integrated("PIPE, SEAMLESS, A333-6, 6\", SCH40")
        
        assert result["category"] == "PIPE"
        assert result["confidence"] > 0.8
        
        # 캐시 저장 호출 확인
        mock_cache.set_classification_result.assert_called_once()


@pytest.mark.performance
class TestClassificationPerformance:
    """분류 성능 테스트"""
    
    def test_classification_speed(self):
        """분류 속도 테스트"""
        import time
        from app.services.integrated_classifier import classify_material_integrated
        
        descriptions = [
            "PIPE, SEAMLESS, A333-6, 6\", SCH40",
            "VALVE, GATE, A216-WCB, 2\", 150LB",
            "FLANGE, WELD NECK, A105, 3\", 150LB",
            "ELBOW, 90DEG, A234-WPB, 4\", SCH40",
            "BOLT, HEX HEAD, A193-B7, M16X50"
        ]
        
        start_time = time.time()
        
        for desc in descriptions:
            result = classify_material_integrated(desc)
            assert result["category"] != "UNKNOWN"
        
        end_time = time.time()
        total_time = end_time - start_time
        
        # 5개 항목을 1초 이내에 분류해야 함
        assert total_time < 1.0
        
        # 평균 분류 시간이 100ms 이하여야 함
        avg_time = total_time / len(descriptions)
        assert avg_time < 0.1
    
    def test_batch_classification(self):
        """배치 분류 테스트"""
        from app.services.integrated_classifier import classify_material_integrated
        
        descriptions = [
            "PIPE, SEAMLESS, A333-6, 6\", SCH40",
            "VALVE, GATE, A216-WCB, 2\", 150LB",
            "FLANGE, WELD NECK, A105, 3\", 150LB"
        ] * 10  # 30개 항목
        
        results = []
        for desc in descriptions:
            result = classify_material_integrated(desc)
            results.append(result)
        
        # 모든 결과가 올바르게 분류되었는지 확인
        assert len(results) == 30
        
        # 각 타입별로 올바르게 분류되었는지 확인
        pipe_results = [r for r in results if r["category"] == "PIPE"]
        valve_results = [r for r in results if r["category"] == "VALVE"]
        flange_results = [r for r in results if r["category"] == "FLANGE"]
        
        assert len(pipe_results) == 10
        assert len(valve_results) == 10
        assert len(flange_results) == 10
