"""
Translation Validator for DS_L10N
번역 검증 시스템
"""
import re
from typing import List, Dict, Tuple, Optional
from dataclasses import dataclass
from enum import Enum


class ValidationLevel(Enum):
    """검증 레벨"""
    ERROR = 'ERROR'      # 치명적 오류
    WARNING = 'WARNING'  # 경고
    INFO = 'INFO'        # 정보


@dataclass
class ValidationIssue:
    """검증 이슈"""
    level: ValidationLevel
    msgctxt: str
    lang: str
    category: str
    message: str
    original: str
    translation: str

    def __str__(self):
        icon = {
            ValidationLevel.ERROR: '❌',
            ValidationLevel.WARNING: '⚠️',
            ValidationLevel.INFO: 'ℹ️'
        }[self.level]

        return (f"{icon} [{self.level.value}] {self.lang}: {self.msgctxt}\n"
                f"   분류: {self.category}\n"
                f"   문제: {self.message}\n"
                f"   원문: {self.original}\n"
                f"   번역: {self.translation}")


class TranslationValidator:
    """번역 검증기"""

    def __init__(self, config: dict):
        self.config = config
        self.validation_config = config.get('validation', {})

        # 변수 패턴 컴파일
        self.variable_pattern = re.compile(r'\{[A-Za-z0-9_]+\}')

        # 리치 텍스트 태그 패턴
        self.tag_patterns = config.get('rich_text', {}).get('tag_patterns', [])

    def validate_entry(self, msgctxt: str, original: str, translation: str, lang: str) -> List[ValidationIssue]:
        """단일 항목 검증"""
        issues = []

        # 빈 번역 확인
        if self.validation_config.get('check_empty_translations', True):
            if not translation or not translation.strip():
                issues.append(ValidationIssue(
                    level=ValidationLevel.WARNING,
                    msgctxt=msgctxt,
                    lang=lang,
                    category='빈 번역',
                    message='번역문이 비어있습니다',
                    original=original,
                    translation=translation
                ))
                return issues  # 빈 번역이면 다른 검증 건너뛰기

        # 변수 일치 확인
        if self.validation_config.get('check_variables', True):
            var_issues = self._check_variables(msgctxt, original, translation, lang)
            issues.extend(var_issues)

        # 리치 텍스트 태그 확인
        if self.validation_config.get('check_rich_text_tags', True):
            tag_issues = self._check_rich_text_tags(msgctxt, original, translation, lang)
            issues.extend(tag_issues)

        # 줄바꿈 확인
        if self.validation_config.get('check_newlines', True):
            newline_issues = self._check_newlines(msgctxt, original, translation, lang)
            issues.extend(newline_issues)

        # 최대 길이 확인
        max_length = self.validation_config.get('max_length_warning', 200)
        if len(translation) > max_length:
            issues.append(ValidationIssue(
                level=ValidationLevel.INFO,
                msgctxt=msgctxt,
                lang=lang,
                category='길이 초과',
                message=f'번역문이 {max_length}자를 초과합니다 (현재: {len(translation)}자)',
                original=original,
                translation=translation
            ))

        return issues

    def _check_variables(self, msgctxt: str, original: str, translation: str, lang: str) -> List[ValidationIssue]:
        """변수 일치 확인"""
        issues = []

        orig_vars = set(self.variable_pattern.findall(original))
        trans_vars = set(self.variable_pattern.findall(translation))

        # 누락된 변수
        missing_vars = orig_vars - trans_vars
        if missing_vars:
            issues.append(ValidationIssue(
                level=ValidationLevel.ERROR,
                msgctxt=msgctxt,
                lang=lang,
                category='변수 누락',
                message=f'누락된 변수: {", ".join(sorted(missing_vars))}',
                original=original,
                translation=translation
            ))

        # 추가된 변수
        extra_vars = trans_vars - orig_vars
        if extra_vars:
            issues.append(ValidationIssue(
                level=ValidationLevel.WARNING,
                msgctxt=msgctxt,
                lang=lang,
                category='추가 변수',
                message=f'원문에 없는 변수: {", ".join(sorted(extra_vars))}',
                original=original,
                translation=translation
            ))

        return issues

    def _check_rich_text_tags(self, msgctxt: str, original: str, translation: str, lang: str) -> List[ValidationIssue]:
        """리치 텍스트 태그 일치 확인"""
        issues = []

        # 여는 태그와 닫는 태그 개수 확인
        for tag in self.tag_patterns:
            if tag == '</>':
                continue  # 닫는 태그는 별도 처리

            orig_count = original.count(tag)
            trans_count = translation.count(tag)

            if orig_count != trans_count:
                issues.append(ValidationIssue(
                    level=ValidationLevel.ERROR,
                    msgctxt=msgctxt,
                    lang=lang,
                    category='태그 불일치',
                    message=f'태그 {tag} 개수 불일치 (원문: {orig_count}, 번역: {trans_count})',
                    original=original,
                    translation=translation
                ))

        # 닫는 태그 </> 개수 확인
        orig_close = original.count('</>')
        trans_close = translation.count('</>')

        if orig_close != trans_close:
            issues.append(ValidationIssue(
                level=ValidationLevel.ERROR,
                msgctxt=msgctxt,
                lang=lang,
                category='태그 불일치',
                message=f'닫는 태그 </> 개수 불일치 (원문: {orig_close}, 번역: {trans_close})',
                original=original,
                translation=translation
            ))

        return issues

    def _check_newlines(self, msgctxt: str, original: str, translation: str, lang: str) -> List[ValidationIssue]:
        """줄바꿈 문자 확인"""
        issues = []

        # 실제 escape sequence (\r\n, \n, \r) 개수 확인
        # 주의: '\r\n'은 실제 CR+LF 문자 (2바이트), '\\r\\n'은 리터럴 문자열 (4바이트)
        orig_crlf = original.count('\r\n')
        trans_crlf = translation.count('\r\n')

        orig_lf = original.count('\n') - orig_crlf  # \r\n에 포함된 \n 제외
        trans_lf = translation.count('\n') - trans_crlf

        orig_cr = original.count('\r') - orig_crlf  # \r\n에 포함된 \r 제외
        trans_cr = translation.count('\r') - trans_crlf

        if orig_crlf != trans_crlf or orig_lf != trans_lf or orig_cr != trans_cr:
            issues.append(ValidationIssue(
                level=ValidationLevel.WARNING,
                msgctxt=msgctxt,
                lang=lang,
                category='줄바꿈 불일치',
                message=f'줄바꿈 문자 개수 불일치 (원문: \\r\\n={orig_crlf}, \\n={orig_lf}, \\r={orig_cr} / '
                        f'번역: \\r\\n={trans_crlf}, \\n={trans_lf}, \\r={trans_cr})',
                original=original,
                translation=translation
            ))

        return issues

    def validate_batch(self, entries: List[Dict]) -> Tuple[List[ValidationIssue], Dict[str, int]]:
        """
        여러 항목 일괄 검증

        Args:
            entries: [{'msgctxt': ..., 'msgid': ..., 'lang': ..., 'msgstr': ...}, ...]

        Returns:
            (issues, stats)
        """
        all_issues = []

        for entry in entries:
            msgctxt = entry.get('msgctxt', '')
            original = entry.get('msgid', '')
            translation = entry.get('msgstr', '')
            lang = entry.get('lang', '')

            issues = self.validate_entry(msgctxt, original, translation, lang)
            all_issues.extend(issues)

        # 통계 생성
        stats = {
            'total': len(entries),
            'errors': sum(1 for issue in all_issues if issue.level == ValidationLevel.ERROR),
            'warnings': sum(1 for issue in all_issues if issue.level == ValidationLevel.WARNING),
            'info': sum(1 for issue in all_issues if issue.level == ValidationLevel.INFO),
            'passed': len(entries) - len(set(issue.msgctxt for issue in all_issues if issue.level == ValidationLevel.ERROR))
        }

        return all_issues, stats

    def print_validation_report(self, issues: List[ValidationIssue], stats: Dict[str, int], logger):
        """검증 리포트 출력"""
        logger.section('🔍 번역 검증 결과')

        if not issues:
            logger.success('✅ 모든 검증 통과!')
            logger.stats(**stats)
            return

        # 레벨별로 그룹화
        errors = [i for i in issues if i.level == ValidationLevel.ERROR]
        warnings = [i for i in issues if i.level == ValidationLevel.WARNING]
        infos = [i for i in issues if i.level == ValidationLevel.INFO]

        # 오류 출력
        if errors:
            logger.error(f'\n❌ 오류 ({len(errors)}건):')
            for issue in errors[:10]:  # 최대 10개만 출력
                logger.error(f'\n{issue}')
            if len(errors) > 10:
                logger.error(f'\n... 외 {len(errors) - 10}건 더 있음')

        # 경고 출력
        if warnings:
            logger.warning(f'\n⚠️  경고 ({len(warnings)}건):')
            for issue in warnings[:10]:  # 최대 10개만 출력
                logger.warning(f'\n{issue}')
            if len(warnings) > 10:
                logger.warning(f'\n... 외 {len(warnings) - 10}건 더 있음')

        # 정보 출력
        if infos:
            logger.info(f'\nℹ️  정보 ({len(infos)}건):')
            for issue in infos[:5]:  # 최대 5개만 출력
                logger.info(f'\n{issue}')
            if len(infos) > 5:
                logger.info(f'\n... 외 {len(infos) - 5}건 더 있음')

        # 통계 출력
        logger.separator()
        logger.stats(**stats)

        if errors:
            logger.error(f'\n검증 실패: {stats["errors"]}개의 오류가 발견되었습니다.')
        else:
            logger.success(f'\n검증 완료: {stats["passed"]}건 통과 (경고 {stats["warnings"]}건)')
