"""
날짜 및 스케줄 타입 판별 유틸리티

이 모듈은 날짜 문자열 파싱, 공휴일 판별, 평일/주말/휴일 구분 등
날짜 관련 모든 처리를 담당합니다. holidays 라이브러리를 활용하여
한국 공휴일(대체공휴일 포함)을 정확하게 판별합니다.

주요 기능:
    - 한글 요일 변환: datetime → "월", "화" 등
    - 날짜 파싱: 다양한 형식의 날짜 문자열 처리
    - 스케줄 타입 판별: weekday/weekend/holiday 구분
    - 공휴일 처리: 한국 법정공휴일 자동 인식
    - 타임테이블 연동: 시각표 조회용 타입 반환
    - 주박 로직 지원: 토요일 별도 구분 (saturday)

리팩토링 배경:
    ReportService의 날짜 처리 로직을 분리하여 독립적인 유틸리티로 구성.
    다른 서비스에서도 재사용 가능하도록 정적 메서드로 설계했습니다.

사용 예시:
    >>> from utils.date_utils import DateScheduleUtils
    >>> 
    >>> # 요일 변환
    >>> weekday = DateScheduleUtils.get_korean_weekday("2026.02.17")
    >>> print(weekday)
    화
    >>> 
    >>> # 스케줄 타입 판별
    >>> text = "2월 15일 일요일에 발생한 민원입니다"
    >>> date, schedule_type = DateScheduleUtils.parse_schedule_type(text, "2026-02-15")
    >>> print(f"{date}: {schedule_type}")
    2026-02-15: holiday
    >>> 
    >>> # 타임테이블용 타입
    >>> from datetime import date
    >>> target = date(2026, 2, 14)  # 토요일
    >>> diag_type = DateScheduleUtils.get_timetable_diag_type(target)
    >>> print(diag_type)
    weekend

의존성:
    - holidays: 한국 공휴일 데이터
    - datetime: 날짜/시간 처리
    - re: 정규식 패턴 매칭

작성자: KH.Choi
최종 수정: 2026-02-17
버전: 2.0 (ReportService에서 분리)
"""
import re
import holidays
from datetime import datetime


class DateScheduleUtils:
    """
    날짜 및 스케줄 타입 판별 유틸리티
    
    모든 메서드가 정적 메서드로 구성되어 있어 인스턴스 생성 없이 사용 가능합니다.
    날짜 문자열 파싱, 공휴일 판별, 스케줄 타입 분류 등의 기능을 제공합니다.
    
    스케줄 타입 분류 기준:
        - holiday: 법정공휴일 또는 일요일
        - weekend: 토요일 (공휴일 아님)
        - weekday: 평일 (월~금)
        - saturday: 주박 로직 전용 (토요일 별도 구분)
    
    주요 메서드:
        get_korean_weekday: 날짜 → 한글 요일 변환
        parse_schedule_type: 텍스트에서 날짜 추출 및 타입 판별
        get_timetable_diag_type: 타임테이블 조회용 타입 반환
        get_stabling_diag_type: 주박 로직용 상세 타입 반환
    
    공휴일 처리:
        holidays.KR()을 사용하여 다음을 자동 인식합니다:
        - 법정공휴일 (신정, 설날, 추석, 어린이날 등)
        - 대체공휴일
        - 임시공휴일
    
    날짜 파싱 패턴:
        - YYYY.MM.DD, YYYY-MM-DD, YYYY/MM/DD
        - MM.DD, MM-DD, MM/DD (연도 생략 시 문서 날짜 기준)
        - 유효하지 않은 날짜 (예: 2월 30일) 자동 필터링
    
    사용 시나리오:
        1. 보고서 생성 시 문서 날짜의 요일 표시
        2. 시각표 조회 시 평일/주말 다이어그램 선택
        3. 주박지 입출고 추적 시 토요일 별도 처리
        4. VOC 발생 날짜 기반 스케줄 타입 자동 판별
    
    예시:
        >>> # 정적 메서드 직접 호출
        >>> DateScheduleUtils.get_korean_weekday("2026-02-17")
        '화'
        >>> 
        >>> # 공휴일 판별
        >>> from datetime import date
        >>> target = date(2026, 1, 1)  # 신정
        >>> DateScheduleUtils.get_timetable_diag_type(target)
        'holiday'
    """
    
    @staticmethod
    def get_korean_weekday(date_str):
        """
        날짜 문자열에서 요일을 한글로 반환
        
        Args:
            date_str (str): 'YYYY.MM.DD' 또는 'YYYY-MM-DD' 형식
            
        Returns:
            str: '월', '화' 등의 요일 문자열
        """
        try:
            clean_date = date_str.strip().replace('-', '.').rstrip('.')
            dt = datetime.strptime(clean_date, "%Y.%m.%d")
            return "월화수목금토일"[dt.weekday()]
        except Exception:
            return ""
    
    @staticmethod
    def parse_schedule_type(full_text, doc_date_str):
        """
        텍스트에서 날짜를 추출하고 평일/주말/휴일 판별
        
        Args:
            full_text (str): 본문 텍스트
            doc_date_str (str): 문서 등록일 (연도 참조용)
            
        Returns:
            tuple: (datetime.date, schedule_type)
                   schedule_type: 'weekday', 'weekend', 'holiday'
        """
        # 1. 기준 연도 추출
        default_year = 2026
        if doc_date_str:
            y_match = re.search(r"(20[2-6]\d)", str(doc_date_str))
            if y_match:
                default_year = int(y_match.group(1))
        
        # 2. 본문에서 날짜 패턴 검색
        date_pattern = r"(?:(20[2-6]\d)[-/.])?(\d{1,2})[-/.](\d{1,2})"
        matches = re.finditer(date_pattern, full_text)
        
        target_date = None
        
        for match in matches:
            y_txt, m_txt, d_txt = match.groups()
            year = int(y_txt) if y_txt else default_year
            month = int(m_txt)
            day = int(d_txt)
            
            try:
                candidate_date = datetime(year, month, day)
                target_date = candidate_date
                break
            except ValueError:
                continue
        
        # 3. 날짜를 못 찾았으면 doc_date 또는 오늘 사용
        if not target_date:
            target_date = datetime.today()
            if doc_date_str:
                try:
                    dt = datetime.strptime(str(doc_date_str)[:10], "%Y-%m-%d")
                    target_date = dt.date()
                except:
                    pass
        
        # 4. 스케줄 타입 판별
        kr_holidays = holidays.KR(years=target_date.year)
        weekday_idx = target_date.weekday()
        
        if target_date in kr_holidays or weekday_idx == 6:
            final_type = "holiday"
        elif weekday_idx == 5:
            final_type = "weekend"
        else:
            final_type = "weekday"
        
        return target_date, final_type
    
    @staticmethod
    def get_timetable_diag_type(target_date):
        """
        타임테이블 조회용 타입 반환
        
        Args:
            target_date (datetime.date): 대상 날짜
            
        Returns:
            str: 'weekday', 'weekend', 'holiday'
        """
        kr_holidays = holidays.KR(years=target_date.year)
        if target_date in kr_holidays or target_date.weekday() == 6:
            return 'holiday'
        elif target_date.weekday() == 5:
            return 'weekend'
        else:
            return 'weekday'
    
    @staticmethod
    def get_stabling_diag_type(target_date):
        """
        주박 로직용 상세 타입 반환 (토요일 구분)
        
        Args:
            target_date (datetime.date): 대상 날짜
            
        Returns:
            str: 'weekday', 'saturday', 'holiday'
        """
        kr_holidays = holidays.KR(years=target_date.year)
        if target_date in kr_holidays or target_date.weekday() == 6:
            return 'holiday'
        elif target_date.weekday() == 5:
            return 'saturday'
        else:
            return 'weekday'
