"""
통합 자재 분류 시스템
메모리에 정의된 키워드 우선순위 체계를 적용
"""

import re
from typing import Dict, List, Optional, Tuple
from .fitting_classifier import classify_fitting
from .classifier_constants import (
    LEVEL1_TYPE_KEYWORDS,
    LEVEL2_SUBTYPE_KEYWORDS,
    LEVEL3_CONNECTION_KEYWORDS,
    LEVEL3_PRESSURE_KEYWORDS,
    LEVEL4_MATERIAL_KEYWORDS,
    GENERIC_MATERIALS
)

def classify_material_integrated(description: str, main_nom: str = "", 
                                red_nom: str = "", length: float = None) -> Dict:
    """
    통합 자재 분류 함수
    
    Args:
        description: 자재 설명
        main_nom: 주 사이즈
        red_nom: 축소 사이즈 (플랜지/피팅용)
        length: 길이 (파이프용)
    
    Returns:
        분류 결과 딕셔너리
    """
    
    desc_upper = description.upper()
    
    # 최우선: SPECIAL 키워드 확인 (도면 업로드가 필요한 특수 자재)
    # SPECIAL이 포함된 경우 (단, SPECIFICATION은 제외)
    if 'SPECIAL' in desc_upper and 'SPECIFICATION' not in desc_upper:
        return {
            "category": "SPECIAL",
            "confidence": 1.0,
            "evidence": ["SPECIAL_KEYWORD"],
            "classification_level": "LEVEL0_SPECIAL",
            "reason": "SPECIAL 키워드 발견"
        }
    
    # 스페셜 관련 한글 키워드
    if '스페셜' in desc_upper or 'SPL' in desc_upper:
        return {
            "category": "SPECIAL",
            "confidence": 1.0,
            "evidence": ["SPECIAL_KEYWORD"],
            "classification_level": "LEVEL0_SPECIAL",
            "reason": "스페셜 키워드 발견"
        }
    
    
    # VALVE 카테고리 우선 확인 (SIGHT GLASS, STRAINER)
    if ('SIGHT GLASS' in desc_upper or 'STRAINER' in desc_upper or 
        '사이트글라스' in desc_upper or '스트레이너' in desc_upper):
        return {
            "category": "VALVE",
            "confidence": 1.0,
            "evidence": ["VALVE_SPECIAL_KEYWORD"],
            "classification_level": "LEVEL0_VALVE",
            "reason": "SIGHT GLASS 또는 STRAINER 키워드 발견"
        }
    
    # SUPPORT 카테고리 우선 확인 (BOLT 카테고리보다 먼저)
    # U-BOLT, CLAMP, URETHANE BLOCK 등
    if ('U-BOLT' in desc_upper or 'U BOLT' in desc_upper or '유볼트' in desc_upper or
        'URETHANE BLOCK' in desc_upper or 'BLOCK SHOE' in desc_upper or '우레탄' in desc_upper or
        'CLAMP' in desc_upper or '클램프' in desc_upper or 'PIPE CLAMP' in desc_upper):
        return {
            "category": "SUPPORT",
            "confidence": 1.0,
            "evidence": ["SUPPORT_SYSTEM_KEYWORD"],
            "classification_level": "LEVEL0_SUPPORT",
            "reason": "SUPPORT 시스템 키워드 발견"
        }
        
    # [신규] Swagelok 스타일 파트 넘버 패턴 확인
    # 예: SS-400-1-4, SS-810-6, B-400-9, SS-1610-P
    swagelok_pattern = r'\b(SS|S|B|A|M)-([0-9]{3,4}|[0-9]+M[0-9]*)-([0-9A-Z])'
    if re.search(swagelok_pattern, desc_upper):
        return {
            "category": "TUBE_FITTING",
            "confidence": 0.98,
            "evidence": ["SWAGELOK_PART_NO"],
            "classification_level": "LEVEL0_PARTNO",
            "reason": "Swagelok 스타일 파트넘버 감지"
        }
    
    # 쉼표로 구분된 각 부분을 별도로 체크 (예: "NIPPLE, SMLS, SCH 80")
    desc_parts = [part.strip() for part in desc_upper.split(',')]
    
    # 1단계: Level 1 키워드로 타입 식별
    detected_types = []
    
    # 특별 우선순위: REDUCING FLANGE 먼저 확인 (강화된 로직)
    reducing_flange_patterns = [
        "REDUCING FLANGE", "RED FLANGE", "REDUCER FLANGE", 
        "REDUCING FLG", "RED FLG", "REDUCER FLG"
    ]
    
    # FLANGE와 REDUCING/RED/REDUCER가 함께 있는 경우도 확인
    has_flange = any(flange_word in desc_upper for flange_word in ["FLANGE", "FLG"])
    has_reducing = any(red_word in desc_upper for red_word in ["REDUCING", "RED", "REDUCER"])
    
    # 직접 패턴 매칭 또는 FLANGE + REDUCING 조합
    reducing_flange_detected = False
    for pattern in reducing_flange_patterns:
        if pattern in desc_upper:
            detected_types.append(("FLANGE", "REDUCING FLANGE"))
            reducing_flange_detected = True
            break
    
    # FLANGE와 REDUCING이 모두 있으면 REDUCING FLANGE로 분류
    if not reducing_flange_detected and has_flange and has_reducing:
        detected_types.append(("FLANGE", "REDUCING FLANGE"))
        reducing_flange_detected = True
    
    # REDUCING FLANGE가 감지되지 않은 경우에만 일반 키워드 검사
    if not reducing_flange_detected:
        for material_type, keywords in LEVEL1_TYPE_KEYWORDS.items():
            type_found = False
            # 긴 키워드부터 확인 (FLANGE BOLT가 FLANGE보다 먼저 매칭되도록)
            sorted_keywords = sorted(keywords, key=len, reverse=True)
            for keyword in sorted_keywords:
                # [강화된 로직] 짧은 키워드나 중의적 키워드에 대한 엄격한 검사
                is_strict_match = True
                
                # 1. "PL" 키워드 검사 (PLATE)
                if keyword == "PL":
                    # 단독 단어이거나 숫자 뒤에 붙는 경우만 허용 (예: 10PL, 10 PL)
                    # COUPLING, NIPPLE, PLUG 등에 포함된 PL은 제외
                    pl_pattern = r'(\b|\d)PL\b'
                    if not re.search(pl_pattern, desc_upper):
                        is_strict_match = False
                
                # 2. "ANGLE" 키워드 검사 (STRUCTURAL)
                elif keyword == "ANGLE" or keyword == "앵글":
                    # VALVE와 함께 쓰이면 제외 (ANGLE VALVE)
                    if "VALVE" in desc_upper or "밸브" in desc_upper:
                        is_strict_match = False
                        
                # 3. "UNION" 키워드 검사 (FITTING)
                elif keyword == "UNION":
                    # 계장용인지 파이프용인지 구분은 fitting_classifier에서 하되,
                    # 여기서는 일단 FITTING으로 잡히도록 둠.
                    pass
                
                # 4. "BEAM" 키워드 검사 (STRUCTURAL)
                elif keyword == "BEAM":
                     # "BEAM CLAMP" 같은 경우 SUPPORT로 가야 함 (SUPPORT가 우선순위 높으므로 괜찮음)
                     pass

                if not is_strict_match:
                    continue

                # 전체 문자열에서 찾기
                if keyword in desc_upper:
                    detected_types.append((material_type, keyword))
                    type_found = True
                    break
                # 각 부분에서도 정확히 매칭되는지 확인
                for part in desc_parts:
                    if keyword == part or keyword in part:
                        detected_types.append((material_type, keyword))
                        type_found = True
                        break
                if type_found:
                    break
    
    # 2단계: 복수 타입 감지 시 Level 2로 구체화
    if len(detected_types) > 1:
        # Level 2 키워드로 우선순위 결정
        for material_type, subtype_dict in LEVEL2_SUBTYPE_KEYWORDS.items():
            for subtype, keywords in subtype_dict.items():
                for keyword in keywords:
                    if keyword in desc_upper:
                        return {
                            "category": material_type,
                            "confidence": 0.95,
                            "evidence": [f"L1_KEYWORD: {detected_types}", f"L2_KEYWORD: {keyword}"],
                            "classification_level": "LEVEL2"
                        }
        
        # Level 2 키워드가 없으면 우선순위로 결정
        # BOLT > SUPPORT > FITTING > VALVE > FLANGE > PIPE (볼트 우선, 더 구체적인 것 우선)
        type_priority = ["BOLT", "SUPPORT", "FITTING", "VALVE", "FLANGE", "PIPE", "GASKET", "INSTRUMENT"]
        for priority_type in type_priority:
            for detected_type, keyword in detected_types:
                if detected_type == priority_type:
                    return {
                        "category": priority_type,
                        "confidence": 0.85,
                        "evidence": [f"L1_MULTI_TYPE: {detected_types}", f"PRIORITY: {priority_type}"],
                        "classification_level": "LEVEL1_PRIORITY"
                    }
    
    # 3단계: 단일 타입 확정 또는 Level 3/4로 판단
    if len(detected_types) == 1:
        material_type = detected_types[0][0]
        
        # FITTING으로 분류된 경우 상세 분류기 호출
        if material_type == "FITTING":
            try:
                detailed_result = classify_fitting("", description, main_nom, red_nom, length)
                # 상세 분류 결과가 있으면 사용, 없으면 기본 FITTING 반환
                if detailed_result and detailed_result.get("category"):
                    return detailed_result
            except Exception as e:
                # 상세 분류 실패 시 기본 FITTING으로 처리
                pass
        
        return {
            "category": material_type,
            "confidence": 0.9,
            "evidence": [f"L1_KEYWORD: {detected_types[0][1]}"],
            "classification_level": "LEVEL1"
        }
    
    # 4단계: Level 1 없으면 재질 기반 분류
    if not detected_types:
        # 전용 재질 확인
        for material_type, materials in LEVEL4_MATERIAL_KEYWORDS.items():
            for material in materials:
                if material in desc_upper:
                    # 볼트 재질(A193, A194)은 다른 키워드가 있는지 확인
                    if material_type == "BOLT":
                        # 다른 타입 키워드가 있으면 볼트로 분류하지 않음
                        other_type_found = False
                        for other_type, keywords in LEVEL1_TYPE_KEYWORDS.items():
                            if other_type != "BOLT":
                                for keyword in keywords:
                                    if keyword in desc_upper:
                                        other_type_found = True
                                        break
                                if other_type_found:
                                    break
                        
                        if other_type_found:
                            continue  # 볼트로 분류하지 않음
                    
                    # FITTING으로 분류된 경우 상세 분류기 호출
                    if material_type == "FITTING":
                        try:
                            detailed_result = classify_fitting("", description, main_nom, red_nom, length)
                            if detailed_result and detailed_result.get("category"):
                                return detailed_result
                        except Exception as e:
                            pass
                    
                    return {
                        "category": material_type,
                        "confidence": 0.35,  # 재질만으로 분류 시 낮은 신뢰도
                        "evidence": [f"L4_MATERIAL: {material}"],
                        "classification_level": "LEVEL4"
                    }
        
        # 범용 재질 확인
        for material, priority_types in GENERIC_MATERIALS.items():
            if material in desc_upper:
                # 우선순위에 따라 타입 결정
                material_type = priority_types[0]  # 첫 번째 우선순위
                
                # FITTING으로 분류된 경우 상세 분류기 호출
                if material_type == "FITTING":
                    try:
                        detailed_result = classify_fitting("", description, main_nom, red_nom, length)
                        if detailed_result and detailed_result.get("category"):
                            return detailed_result
                    except Exception as e:
                        pass
                
                return {
                    "category": material_type,
                    "confidence": 0.3,
                    "evidence": [f"GENERIC_MATERIAL: {material}"],
                    "classification_level": "LEVEL4_GENERIC"
                }
    
    # 분류 실패
    return {
        "category": "UNCLASSIFIED",
        "confidence": 0.0,
        "evidence": ["NO_CLASSIFICATION_POSSIBLE"],
        "classification_level": "NONE"
    }

def should_exclude_material(description: str) -> bool:
    """
    제외 대상 자재인지 확인
    """
    exclude_keywords = [
        "DUMMY", "RESERVED", "SPARE", "DELETED", "CANCELED",
        "더미", "예비", "삭제", "취소", "예약"
    ]
    
    desc_upper = description.upper()
    return any(keyword in desc_upper for keyword in exclude_keywords)