﻿import os
import json
import re
import logging
from datetime import datetime
from typing import List, Dict, Set, Tuple
from dataclasses import dataclass

@dataclass
class SmalltalkPattern:
    """스몰토크 패턴 데이터 클래스"""
    pattern: str
    category: str
    description: str
    enabled: bool = True

class SmalltalkPatternManager:
    """스몰토크 패턴을 효과적으로 관리하는 클래스"""
    
    def __init__(self, config_file: str = None):
        self.patterns: List[SmalltalkPattern] = []
        self.config_file = config_file or './config/smalltalk_patterns.json'
        self._load_default_patterns()
        self._load_from_config()
    
    def _load_default_patterns(self):
        """기본 스몰토크 패턴 로드"""
        default_patterns = [
            # 감사 표현
            SmalltalkPattern(r"^감사합니다.?$", "thanks", "감사 인사", True),
            SmalltalkPattern(r"^고맙습니다.?$", "thanks", "고마움 표현", True),
            SmalltalkPattern(r"^thank(s| you)?$", "thanks", "영어 감사", True),
            SmalltalkPattern(r"^고마워.?$", "thanks", "친근한 감사", True),
            SmalltalkPattern(r"^감사해.?$", "thanks", "감사 표현", True),
            
            # 긍정 응답
            SmalltalkPattern(r"^네$", "agreement", "긍정 응답", True),
            SmalltalkPattern(r"^넵$", "agreement", "긍정 응답 (줄임말)", True),
            SmalltalkPattern(r"^예$", "agreement", "긍정 응답", True),
            SmalltalkPattern(r"^ㅇㅋ$", "agreement", "긍정 응답 (이모티콘)", True),
            SmalltalkPattern(r"^ok$", "agreement", "영어 긍정", True),
            SmalltalkPattern(r"^okay$", "agreement", "영어 긍정", True),
            SmalltalkPattern(r"^알겠습니다.?$", "agreement", "이해 표시", True),
            SmalltalkPattern(r"^알겠어.?$", "agreement", "이해 표시 (친근)", True),
            
            # 인사말
            SmalltalkPattern(r"^안녕하세요.?$", "greeting", "기본 인사", True),
            SmalltalkPattern(r"^안녕.?$", "greeting", "친근한 인사", True),
            SmalltalkPattern(r"^hello$", "greeting", "영어 인사", True),
            SmalltalkPattern(r"^hi$", "greeting", "영어 인사 (간단)", True),
            SmalltalkPattern(r"^하이.?$", "greeting", "영어 인사 (한글)", True),
            
            # 작별 인사
            SmalltalkPattern(r"^bye$", "farewell", "영어 작별", True),
            SmalltalkPattern(r"^안녕히.?$", "farewell", "작별 인사", True),
            SmalltalkPattern(r"^다음에.?$", "farewell", "다음 만남 언급", True),
            
            # 격려/응원
            SmalltalkPattern(r"^수고.*$", "encouragement", "수고 표현", True),
            SmalltalkPattern(r"^고생.*$", "encouragement", "고생 표현", True),
            SmalltalkPattern(r"^화이팅.?$", "encouragement", "응원", True),
            SmalltalkPattern(r"^파이팅.?$", "encouragement", "응원", True),
            
            # 부정 응답
            SmalltalkPattern(r"^아니요.?$", "disagreement", "부정 응답", True),
            SmalltalkPattern(r"^아니.?$", "disagreement", "부정 응답 (친근)", True),
            SmalltalkPattern(r"^no$", "disagreement", "영어 부정", True),
            SmalltalkPattern(r"^아닙니다.?$", "disagreement", "정중한 부정", True),
            
            # 사과
            SmalltalkPattern(r"^죄송합니다.?$", "apology", "정중한 사과", True),
            SmalltalkPattern(r"^미안합니다.?$", "apology", "사과", True),
            SmalltalkPattern(r"^미안.?$", "apology", "친근한 사과", True),
            SmalltalkPattern(r"^sorry$", "apology", "영어 사과", True),
            
            # 확인/이해
            SmalltalkPattern(r"^알겠습니다.?$", "confirmation", "이해 확인", True),
            SmalltalkPattern(r"^이해했습니다.?$", "confirmation", "이해 확인", True),
            SmalltalkPattern(r"^네, 알겠습니다.?$", "confirmation", "긍정적 이해", True),
        ]
        
        self.patterns.extend(default_patterns)
        logging.info(f"기본 스몰토크 패턴 {len(default_patterns)}개 로드 완료")
    
    def _load_from_config(self):
        """설정 파일에서 패턴 로드"""
        if not os.path.exists(self.config_file):
            self._save_to_config()
            return
        
        try:
            with open(self.config_file, 'r', encoding='utf-8') as f:
                config_data = json.load(f)
            
            existing_patterns = {p.pattern: p for p in self.patterns}
            
            for pattern_data in config_data.get('patterns', []):
                pattern = SmalltalkPattern(**pattern_data)
                if pattern.pattern not in existing_patterns:
                    self.patterns.append(pattern)
                    logging.info(f"설정 파일에서 패턴 로드: {pattern.description}")
            
        except Exception as e:
            logging.warning(f"설정 파일 로드 실패: {e}")
    
    def _save_to_config(self):
        """현재 패턴을 설정 파일에 저장"""
        try:
            os.makedirs(os.path.dirname(self.config_file), exist_ok=True)
            
            config_data = {
                "patterns": [
                    {
                        "pattern": p.pattern,
                        "category": p.category,
                        "description": p.description,
                        "enabled": p.enabled
                    }
                    for p in self.patterns
                ],
                "last_updated": datetime.now().isoformat()
            }
            
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config_data, f, ensure_ascii=False, indent=2)
            
            logging.info(f"스몰토크 패턴 설정 저장 완료: {self.config_file}")
            
        except Exception as e:
            logging.error(f"설정 파일 저장 실패: {e}")
    
    def add_pattern(self, pattern: str, category: str, description: str, enabled: bool = True):
        """새 패턴 추가"""
        new_pattern = SmalltalkPattern(pattern, category, description, enabled)
        self.patterns.append(new_pattern)
        self._save_to_config()
        logging.info(f"새 패턴 추가: {description} ({pattern})")
    
    def remove_pattern(self, pattern: str):
        """패턴 제거"""
        self.patterns = [p for p in self.patterns if p.pattern != pattern]
        self._save_to_config()
        logging.info(f"패턴 제거: {pattern}")
    
    def toggle_pattern(self, pattern: str, enabled: bool):
        """패턴 활성화/비활성화"""
        for p in self.patterns:
            if p.pattern == pattern:
                p.enabled = enabled
                self._save_to_config()
                logging.info(f"패턴 {'활성화' if enabled else '비활성화'}: {pattern}")
                return True
        return False
    
    def get_patterns_by_category(self, category: str) -> List[SmalltalkPattern]:
        """카테고리별 패턴 조회"""
        return [p for p in self.patterns if p.category == category and p.enabled]
    
    def get_all_categories(self) -> Set[str]:
        """모든 카테고리 조회"""
        return set(p.category for p in self.patterns)
    
    def is_smalltalk(self, user_query: str) -> Tuple[bool, str]:
        """스몰토크 여부 판별 및 카테고리 반환"""
        query = user_query.strip().lower()
        
        for pattern in self.patterns:
            if not pattern.enabled:
                continue
                
            try:
                if re.match(pattern.pattern, query):
                    logging.debug(f"스몰토크 감지: '{user_query}' -> {pattern.category} ({pattern.description})")
                    return True, pattern.category
            except re.error as e:
                logging.warning(f"잘못된 정규식 패턴: {pattern.pattern} - {e}")
                continue
        
        return False, ""
    
    def get_statistics(self) -> Dict:
        """패턴 통계 정보 반환"""
        total_patterns = len(self.patterns)
        enabled_patterns = len([p for p in self.patterns if p.enabled])
        disabled_patterns = total_patterns - enabled_patterns
        
        category_stats = {}
        for pattern in self.patterns:
            if pattern.enabled:
                category_stats[pattern.category] = category_stats.get(pattern.category, 0) + 1
        
        return {
            "total_patterns": total_patterns,
            "enabled_patterns": enabled_patterns,
            "disabled_patterns": disabled_patterns,
            "categories": category_stats,
            "last_updated": datetime.now().isoformat()
        }

# ===============================
# 부적절한 질문 필터링 클래스
# ===============================
@dataclass
class InappropriatePattern:
    """부적절한 질문 패턴 데이터 클래스"""
    pattern: str
    category: str
    description: str
    severity: str  # 'low', 'medium', 'high'
    enabled: bool = True

class InappropriateQuestionFilter:
    """부적절한 질문을 필터링하는 클래스"""
    
    def __init__(self, config_file: str = None):
        self.patterns: List[InappropriatePattern] = []
        self.config_file = config_file or './config/inappropriate_patterns.json'
        self._load_default_patterns()
        self._load_from_config()
    
    def _load_default_patterns(self):
        """기본 부적절한 질문 패턴 로드"""
        default_patterns = [
            # 정치적/민감한 주제
            InappropriatePattern(r".*미국.*잡아가.*", "political", "미국 관련 부적절한 표현", "high", True),
            InappropriatePattern(r".*정치.*", "political", "정치 관련 질문", "medium", True),
            InappropriatePattern(r".*대통령.*", "political", "대통령 관련 질문", "medium", True),
            InappropriatePattern(r".*정부.*비판.*", "political", "정부 비판", "high", True),
            InappropriatePattern(r".*선거.*", "political", "선거 관련", "medium", True),
            
            # 역사적 왜곡/부적절한 표현
            InappropriatePattern(r".*왜.*잡아가.*", "historical", "역사 왜곡 표현", "high", True),
            InappropriatePattern(r".*일본.*침략.*", "historical", "일본 관련 민감 표현", "medium", True),
            InappropriatePattern(r".*전쟁.*범죄.*", "historical", "전쟁 범죄 관련", "high", True),
            
            # 개인정보/사생활 침해
            InappropriatePattern(r".*개인정보.*", "privacy", "개인정보 관련", "high", True),
            InappropriatePattern(r".*사생활.*", "privacy", "사생활 관련", "medium", True),
            InappropriatePattern(r".*주민등록번호.*", "privacy", "주민등록번호", "high", True),
            
            # 폭력/위험한 내용
            InappropriatePattern(r".*폭력.*", "violence", "폭력 관련", "high", True),
            InappropriatePattern(r".*살인.*", "violence", "살인 관련", "high", True),
            InappropriatePattern(r".*자살.*", "violence", "자살 관련", "high", True),
            InappropriatePattern(r".*테러.*", "violence", "테러 관련", "high", True),
            
            # 성인/부적절한 내용
            InappropriatePattern(r".*성.*", "adult", "성 관련", "high", True),
            InappropriatePattern(r".*야동.*", "adult", "야동 관련", "high", True),
            InappropriatePattern(r".*포르노.*", "adult", "포르노 관련", "high", True),
            
            # 종교/민족 차별
            InappropriatePattern(r".*종교.*비판.*", "discrimination", "종교 비판", "medium", True),
            InappropriatePattern(r".*민족.*차별.*", "discrimination", "민족 차별", "high", True),
            InappropriatePattern(r".*인종.*차별.*", "discrimination", "인종 차별", "high", True),
            
            # 불법/부정한 행위
            InappropriatePattern(r".*해킹.*", "illegal", "해킹 관련", "high", True),
            InappropriatePattern(r".*불법.*", "illegal", "불법 관련", "high", True),
            InappropriatePattern(r".*도박.*", "illegal", "도박 관련", "medium", True),
            InappropriatePattern(r".*마약.*", "illegal", "마약 관련", "high", True),
            
            # 비즈니스와 무관한 질문
            InappropriatePattern(r".*게임.*", "unrelated", "게임 관련", "low", True),
            InappropriatePattern(r".*연예인.*", "unrelated", "연예인 관련", "low", True),
            InappropriatePattern(r".*스포츠.*", "unrelated", "스포츠 관련", "low", True),
            InappropriatePattern(r".*요리.*", "unrelated", "요리 관련", "low", True),
            InappropriatePattern(r".*여행.*", "unrelated", "여행 관련", "low", True),
        ]
        
        self.patterns.extend(default_patterns)
        logging.info(f"기본 부적절한 질문 패턴 {len(default_patterns)}개 로드 완료")
    
    def _load_from_config(self):
        """설정 파일에서 패턴 로드"""
        if not os.path.exists(self.config_file):
            self._save_to_config()
            return
        
        try:
            with open(self.config_file, 'r', encoding='utf-8') as f:
                config_data = json.load(f)
            
            existing_patterns = {p.pattern: p for p in self.patterns}
            
            for pattern_data in config_data.get('patterns', []):
                pattern = InappropriatePattern(**pattern_data)
                if pattern.pattern not in existing_patterns:
                    self.patterns.append(pattern)
                    logging.info(f"설정 파일에서 부적절한 패턴 로드: {pattern.description}")
            
        except Exception as e:
            logging.warning(f"부적절한 패턴 설정 파일 로드 실패: {e}")
    
    def _save_to_config(self):
        """현재 패턴을 설정 파일에 저장"""
        try:
            os.makedirs(os.path.dirname(self.config_file), exist_ok=True)
            
            config_data = {
                "patterns": [
                    {
                        "pattern": p.pattern,
                        "category": p.category,
                        "description": p.description,
                        "severity": p.severity,
                        "enabled": p.enabled
                    }
                    for p in self.patterns
                ],
                "last_updated": datetime.now().isoformat()
            }
            
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config_data, f, ensure_ascii=False, indent=2)
            
            logging.info(f"부적절한 질문 패턴 설정 저장 완료: {self.config_file}")
            
        except Exception as e:
            logging.error(f"부적절한 패턴 설정 파일 저장 실패: {e}")
    
    def is_inappropriate(self, user_query: str) -> Tuple[bool, str, str]:
        """부적절한 질문 여부 판별 및 카테고리, 심각도 반환"""
        query = user_query.strip().lower()
        
        for pattern in self.patterns:
            if not pattern.enabled:
                continue
                
            try:
                if re.search(pattern.pattern, query):
                    logging.warning(f"부적절한 질문 감지: '{user_query}' -> {pattern.category} ({pattern.severity})")
                    return True, pattern.category, pattern.severity
            except re.error as e:
                logging.warning(f"잘못된 정규식 패턴: {pattern.pattern} - {e}")
                continue
        
        return False, "", ""
    
    def get_appropriate_response(self, category: str, severity: str) -> str:
        """부적절한 질문에 대한 적절한 응답 생성"""
        responses = {
            "political": "죄송합니다. 정치적 주제에 대해서는 답변을 드리기 어렵습니다. MLink 서비스와 관련된 질문을 해주시면 도움을 드릴 수 있습니다.",
            "historical": "죄송합니다. 역사적 주제에 대해서는 정확한 답변을 드리기 어렵습니다. MLink 사용법이나 기능에 대해 질문해주시면 도움을 드릴 수 있습니다.",
            "privacy": "개인정보 보호를 위해 해당 주제에 대해서는 답변을 드리지 않습니다. MLink 서비스 관련 질문을 해주세요.",
            "violence": "폭력이나 위험한 내용에 대해서는 답변을 드리지 않습니다. MLink 사용에 도움이 되는 질문을 해주세요.",
            "adult": "부적절한 내용에 대해서는 답변을 드리지 않습니다. MLink 서비스와 관련된 질문을 해주세요.",
            "discrimination": "차별이나 편견을 조장하는 내용에 대해서는 답변을 드리지 않습니다. MLink 사용법에 대해 질문해주세요.",
            "illegal": "불법적인 행위에 대해서는 답변을 드리지 않습니다. MLink 서비스 이용에 도움이 되는 질문을 해주세요.",
            "unrelated": "죄송합니다. MLink 서비스와 관련 없는 주제에 대해서는 답변을 드리기 어렵습니다. MLink 사용법이나 기능에 대해 질문해주시면 도움을 드릴 수 있습니다."
        }
        
        base_response = responses.get(category, "죄송합니다. 해당 주제에 대해서는 답변을 드리기 어렵습니다. MLink 서비스와 관련된 질문을 해주세요.")
        
        if severity == "high":
            return base_response + " 더 이상 유사한 질문을 하시면 대화를 종료할 수 있습니다."
        
        return base_response
    
# ===============================
# Smalltalk 전역 인스턴스 관리
# ===============================
_smalltalk_instance = None

def _get_smalltalk_instance() -> SmalltalkPatternManager:
    global _smalltalk_instance
    if _smalltalk_instance is None:
        _smalltalk_instance = SmalltalkPatternManager()
    return _smalltalk_instance

def is_smalltalk_question(user_query: str) -> Tuple[bool, str]:
    """스몰토크 여부 판별 (편의 함수)"""
    return _get_smalltalk_instance().is_smalltalk(user_query)    
