"""
Sensitive Information Detection and Masking Service

Detects and masks Korean phone numbers, addresses, and other PII in dealer descriptions.
"""

import re
from typing import List, Tuple, Dict


# Korean phone number patterns
PHONE_PATTERNS = [
    r'01[0-9]-?\d{3,4}-?\d{4}',  # Mobile: 010-1234-5678, 0101234567
    r'02-?\d{3,4}-?\d{4}',       # Seoul: 02-123-4567
    r'0[3-6][0-9]-?\d{3,4}-?\d{4}',  # Regional: 031-123-4567
    r'070-?\d{3,4}-?\d{4}',      # Internet phone: 070-1234-5678
    r'1[0-9]{2,3}-?\d{4}',       # Service numbers: 1588-1234
    r'\d{2,4}[-.)]\s*\d{3,4}[-.)]\s*\d{4}',  # Various formats with separators
]

# Korean address patterns
ADDRESS_PATTERNS = [
    r'[가-힣]+시\s+[가-힣]+구',       # 서울시 강남구
    r'[가-힣]+도\s+[가-힣]+시',       # 경기도 성남시
    r'[가-힣]+시\s+[가-힣]+동',       # 서울시 역삼동
    r'[가-힣]+구\s+[가-힣]+동',       # 강남구 역삼동
    r'[가-힣]+로\s*\d+',              # 테헤란로 123
    r'[가-힣]+길\s*\d+',              # 역삼길 45
    r'\d+번지',                        # 123번지
    r'[가-힣]+빌딩',                   # XX빌딩
    r'[가-힣]+타워',                   # XX타워
    r'[가-힣]+센터',                   # XX센터
]

# Other sensitive patterns
OTHER_PATTERNS = [
    r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',  # Email
    r'카[카톡|톡]\s*:?\s*[a-zA-Z0-9가-힣]+',  # 카톡 ID
    r'카카오톡?\s*:?\s*[a-zA-Z0-9가-힣]+',   # 카카오톡 ID
]


def detect_sensitive_info(text: str) -> Dict[str, List[Tuple[int, int, str]]]:
    """
    Detect sensitive information in text.

    Returns:
        Dict with categories as keys and list of (start, end, matched_text) tuples as values.
    """
    if not text:
        return {"phones": [], "addresses": [], "others": []}

    result = {
        "phones": [],
        "addresses": [],
        "others": []
    }

    # Detect phone numbers
    for pattern in PHONE_PATTERNS:
        for match in re.finditer(pattern, text):
            result["phones"].append((match.start(), match.end(), match.group()))

    # Detect addresses
    for pattern in ADDRESS_PATTERNS:
        for match in re.finditer(pattern, text):
            result["addresses"].append((match.start(), match.end(), match.group()))

    # Detect other sensitive info
    for pattern in OTHER_PATTERNS:
        for match in re.finditer(pattern, text):
            result["others"].append((match.start(), match.end(), match.group()))

    # Remove duplicates and sort by position
    for category in result:
        result[category] = sorted(set(result[category]), key=lambda x: x[0])

    return result


def mask_sensitive_info(text: str, mask_char: str = "*") -> str:
    """
    Mask all detected sensitive information in text.

    Args:
        text: Original text
        mask_char: Character to use for masking (default: *)

    Returns:
        Text with sensitive info masked
    """
    if not text:
        return text

    detected = detect_sensitive_info(text)

    # Collect all ranges to mask
    ranges = []
    for category in detected.values():
        for start, end, _ in category:
            ranges.append((start, end))

    # Merge overlapping ranges
    ranges = sorted(ranges)
    merged = []
    for start, end in ranges:
        if merged and start <= merged[-1][1]:
            merged[-1] = (merged[-1][0], max(merged[-1][1], end))
        else:
            merged.append((start, end))

    # Apply masking (reverse order to preserve positions)
    result = text
    for start, end in reversed(merged):
        original = result[start:end]
        # Keep first and last char, mask the middle
        if len(original) > 4:
            masked = original[:2] + mask_char * (len(original) - 4) + original[-2:]
        else:
            masked = mask_char * len(original)
        result = result[:start] + masked + result[end:]

    return result


def highlight_sensitive_info(text: str) -> str:
    """
    Add HTML highlighting to detected sensitive information.
    Used for admin preview.

    Returns:
        HTML string with sensitive info wrapped in <mark> tags
    """
    if not text:
        return text

    detected = detect_sensitive_info(text)

    # Collect all ranges with their categories
    ranges = []
    for category, items in detected.items():
        for start, end, matched in items:
            ranges.append((start, end, matched, category))

    # Sort by position (reverse for replacement)
    ranges = sorted(ranges, key=lambda x: x[0], reverse=True)

    result = text
    for start, end, matched, category in ranges:
        color = {
            "phones": "#fee2e2",      # red-100
            "addresses": "#fef3c7",   # amber-100
            "others": "#dbeafe"       # blue-100
        }.get(category, "#e5e7eb")

        result = (
            result[:start] +
            f'<mark style="background-color: {color}; padding: 0 2px;">{matched}</mark>' +
            result[end:]
        )

    return result


def has_sensitive_info(text: str) -> bool:
    """Check if text contains any sensitive information."""
    if not text:
        return False
    detected = detect_sensitive_info(text)
    return any(len(items) > 0 for items in detected.values())


def get_sensitivity_summary(text: str) -> Dict[str, int]:
    """Get count of each type of sensitive info detected."""
    if not text:
        return {"phones": 0, "addresses": 0, "others": 0, "total": 0}

    detected = detect_sensitive_info(text)
    counts = {k: len(v) for k, v in detected.items()}
    counts["total"] = sum(counts.values())
    return counts
