"""
스풀 관리 시스템
도면별 에리어 넘버와 스풀 넘버 관리
"""

import re
from typing import Dict, List, Optional, Tuple
from datetime import datetime

# ========== 스풀 넘버링 규칙 ==========
SPOOL_NUMBERING_RULES = {
    "AREA_NUMBER": {
        "pattern": r"#(\d{2})",  # #01, #02, #03...
        "format": "#{:02d}",     # 2자리 숫자
        "range": (1, 99),        # 01~99
        "description": "에리어 넘버"
    },
    "SPOOL_NUMBER": {
        "pattern": r"([A-Z]{1,2})",  # A, B, C... AA, AB...
        "format": "{}",
        "sequence": ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", 
                    "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
                    "U", "V", "W", "X", "Y", "Z", 
                    "AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ"],
        "description": "스풀 넘버"
    }
}

# ========== 프로젝트별 넘버링 설정 ==========
PROJECT_SPOOL_SETTINGS = {
    "DEFAULT": {
        "area_prefix": "#",
        "area_digits": 2,
        "spool_sequence": "ALPHABETIC",  # A, B, C...
        "separator": "-",
        "format": "{dwg_name}-{area}-{spool}"  # 1-IAR-3B1D0-0129-N-#01-A
    },
    "CUSTOM": {
        # 프로젝트별 커스텀 설정 가능
    }
}

class SpoolManager:
    """스풀 관리 클래스"""
    
    def __init__(self, project_id: int = None):
        self.project_id = project_id
        self.settings = PROJECT_SPOOL_SETTINGS["DEFAULT"]
    
    def parse_spool_identifier(self, spool_id: str) -> Dict:
        """기존 스풀 식별자 파싱"""
        
        # 패턴: DWG_NAME-AREA-SPOOL
        # 예: 1-IAR-3B1D0-0129-N-#01-A
        
        parts = spool_id.split("-")
        
        area_number = None
        spool_number = None
        dwg_base = None
        
        for i, part in enumerate(parts):
            # 에리어 넘버 찾기 (#01, #02...)
            if re.match(r"#\d{2}", part):
                area_number = part
                # 스풀 넘버는 다음 파트
                if i + 1 < len(parts):
                    spool_number = parts[i + 1]
                # 도면명은 에리어 넘버 앞까지
                dwg_base = "-".join(parts[:i])
                break
        
        return {
            "original_id": spool_id,
            "dwg_base": dwg_base,
            "area_number": area_number,
            "spool_number": spool_number,
            "is_valid": bool(area_number and spool_number),
            "parsed_parts": parts
        }
    
    def generate_spool_identifier(self, dwg_name: str, area_number: str, 
                                spool_number: str) -> str:
        """새로운 스풀 식별자 생성"""
        
        # 에리어 넘버 포맷 검증
        area_formatted = self.format_area_number(area_number)
        
        # 스풀 넘버 포맷 검증
        spool_formatted = self.format_spool_number(spool_number)
        
        # 조합
        return f"{dwg_name}-{area_formatted}-{spool_formatted}"
    
    def format_area_number(self, area_input: str) -> str:
        """에리어 넘버 포맷팅"""
        
        # 숫자만 추출
        numbers = re.findall(r'\d+', area_input)
        if numbers:
            area_num = int(numbers[0])
            if 1 <= area_num <= 99:
                return f"#{area_num:02d}"
        
        raise ValueError(f"유효하지 않은 에리어 넘버: {area_input}")
    
    def format_spool_number(self, spool_input: str) -> str:
        """스풀 넘버 포맷팅"""
        
        spool_clean = spool_input.upper().strip()
        
        # 유효한 스풀 넘버인지 확인
        if re.match(r'^[A-Z]{1,2}$', spool_clean):
            return spool_clean
        
        raise ValueError(f"유효하지 않은 스풀 넘버: {spool_input}")
    
    def get_next_spool_number(self, dwg_name: str, area_number: str, 
                            existing_spools: List[str] = None) -> str:
        """다음 사용 가능한 스풀 넘버 추천"""
        
        if not existing_spools:
            return "A"  # 첫 번째 스풀
        
        # 해당 도면+에리어의 기존 스풀들 파싱
        used_spools = set()
        area_formatted = self.format_area_number(area_number)
        
        for spool_id in existing_spools:
            parsed = self.parse_spool_identifier(spool_id)
            if (parsed["dwg_base"] == dwg_name and 
                parsed["area_number"] == area_formatted):
                used_spools.add(parsed["spool_number"])
        
        # 다음 사용 가능한 넘버 찾기
        sequence = SPOOL_NUMBERING_RULES["SPOOL_NUMBER"]["sequence"]
        for spool_num in sequence:
            if spool_num not in used_spools:
                return spool_num
        
        raise ValueError("사용 가능한 스풀 넘버가 없습니다")
    
    def validate_spool_identifier(self, spool_id: str) -> Dict:
        """스풀 식별자 유효성 검증"""
        
        parsed = self.parse_spool_identifier(spool_id)
        
        validation_result = {
            "is_valid": True,
            "errors": [],
            "warnings": [],
            "parsed": parsed
        }
        
        # 도면명 확인
        if not parsed["dwg_base"]:
            validation_result["is_valid"] = False
            validation_result["errors"].append("도면명이 없습니다")
        
        # 에리어 넘버 확인
        if not parsed["area_number"]:
            validation_result["is_valid"] = False
            validation_result["errors"].append("에리어 넘버가 없습니다")
        elif not re.match(r"#\d{2}", parsed["area_number"]):
            validation_result["is_valid"] = False
            validation_result["errors"].append("에리어 넘버 형식이 잘못되었습니다 (#01 형태)")
        
        # 스풀 넘버 확인
        if not parsed["spool_number"]:
            validation_result["is_valid"] = False
            validation_result["errors"].append("스풀 넘버가 없습니다")
        elif not re.match(r"^[A-Z]{1,2}$", parsed["spool_number"]):
            validation_result["is_valid"] = False
            validation_result["errors"].append("스풀 넘버 형식이 잘못되었습니다 (A, B, AA 형태)")
        
        return validation_result

def classify_pipe_with_spool(dat_file: str, description: str, main_nom: str,
                           length: float = None, dwg_name: str = None,
                           area_number: str = None, spool_number: str = None) -> Dict:
    """파이프 분류 + 스풀 정보 통합"""
    
    # 기본 파이프 분류 (기존 함수 사용)
    from .pipe_classifier import classify_pipe
    pipe_result = classify_pipe(dat_file, description, main_nom, length)
    
    # 스풀 관리자 생성
    spool_manager = SpoolManager()
    
    # 스풀 정보 추가
    spool_info = {
        "dwg_name": dwg_name,
        "area_number": None,
        "spool_number": None,
        "spool_identifier": None,
        "manual_input_required": True,
        "validation": None
    }
    
    # 에리어/스풀 넘버가 제공된 경우
    if area_number and spool_number:
        try:
            area_formatted = spool_manager.format_area_number(area_number)
            spool_formatted = spool_manager.format_spool_number(spool_number)
            spool_identifier = spool_manager.generate_spool_identifier(
                dwg_name, area_formatted, spool_formatted
            )
            
            spool_info.update({
                "area_number": area_formatted,
                "spool_number": spool_formatted,
                "spool_identifier": spool_identifier,
                "manual_input_required": False,
                "validation": {"is_valid": True, "errors": []}
            })
            
        except ValueError as e:
            spool_info["validation"] = {
                "is_valid": False,
                "errors": [str(e)]
            }
    
    # 기존 결과에 스풀 정보 추가
    pipe_result["spool_info"] = spool_info
    
    return pipe_result

def group_pipes_by_spool(pipes_data: List[Dict]) -> Dict:
    """파이프들을 스풀별로 그룹핑"""
    
    spool_groups = {}
    
    for pipe in pipes_data:
        spool_info = pipe.get("spool_info", {})
        spool_id = spool_info.get("spool_identifier", "UNGROUPED")
        
        if spool_id not in spool_groups:
            spool_groups[spool_id] = {
                "spool_identifier": spool_id,
                "dwg_name": spool_info.get("dwg_name"),
                "area_number": spool_info.get("area_number"),
                "spool_number": spool_info.get("spool_number"),
                "pipes": [],
                "total_length": 0,
                "pipe_count": 0
            }
        
        spool_groups[spool_id]["pipes"].append(pipe)
        spool_groups[spool_id]["pipe_count"] += 1
        
        # 길이 합계
        pipe_length = pipe.get("cutting_dimensions", {}).get("length_mm", 0)
        if pipe_length:
            spool_groups[spool_id]["total_length"] += pipe_length
    
    return spool_groups
