"""
TAC Utility Helpers
General utility functions for file operations, validation, and common tasks
"""

import os
import re
import mimetypes
from pathlib import Path
from typing import Optional, Dict, Any, Tuple
from datetime import datetime

from utils.i18n import _


class FileHelper:
    """Helper functions for file operations"""
    
    @staticmethod
    def ensure_extension(filename: str, extension: str) -> str:
        """Ensure filename has the correct extension"""
        if not extension.startswith('.'):
            extension = '.' + extension
        
        if not filename.lower().endswith(extension.lower()):
            return filename + extension
        return filename
    
    @staticmethod
    def get_safe_filename(filename: str) -> str:
        """Convert filename to safe version (remove invalid characters)"""
        safe_chars = re.sub(r'[<>/\\|?*]', '_', filename)
        
        # Remove multiple spaces and underscores
        safe_chars = re.sub(r'[ _]+', '_', safe_chars)
        
        # Remove leading/trailing spaces and underscores
        safe_chars = safe_chars.strip(' _')
        
        # Ensure not empty
        if not safe_chars:
            safe_chars = "untitled"
        
        return safe_chars
    
    @staticmethod
    def get_file_size_human(file_path: Path) -> str:
        """Get human-readable file size"""
        try:
            size = file_path.stat().st_size
            for unit in ['B', 'KB', 'MB', 'GB']:
                if size < 1024.0:
                    return f"{size:.1f} {unit}"
                size /= 1024.0
            return f"{size:.1f} TB"
        except:
            return _("Desconhecido")
    
    @staticmethod
    def get_mime_type(file_path: Path) -> str:
        """Get MIME type of file"""
        mime_type, _ = mimetypes.guess_type(str(file_path))
        return mime_type or 'application/octet-stream'
    
    
    @staticmethod
    def create_backup_filename(original_path: Path, project_name: str) -> Path:
        """Create backup filename based on project name and timestamp."""
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")

        # Use project name (cleaned of invalid characters) instead of UUID
        safe_project_name = FileHelper.get_safe_filename(project_name)

        backup_name = f"{safe_project_name}_{timestamp}_backup{original_path.suffix}"
        # Return complete Path object, not just filename
        return original_path.parent / backup_name
    
    @staticmethod
    def find_available_filename(file_path: Path) -> Path:
        """Find available filename if file already exists"""
        if not file_path.exists():
            return file_path
        
        counter = 1
        while True:
            new_name = f"{file_path.stem}_{counter}{file_path.suffix}"
            new_path = file_path.parent / new_name
            if not new_path.exists():
                return new_path
            counter += 1


class TextHelper:
    """Helper functions for text processing"""
    
    @staticmethod
    def count_words(text: str) -> int:
        """Count words in text"""
        if not text:
            return 0
        return len(text.split())
    
    @staticmethod
    def count_characters(text: str, include_spaces: bool = True) -> int:
        """Count characters in text"""
        if not text:
            return 0
        return len(text) if include_spaces else len(text.replace(' ', ''))
    
    @staticmethod
    def count_sentences(text: str) -> int:
        """Count sentences in text (basic implementation)"""
        if not text:
            return 0
        # Simple sentence counting based on sentence-ending punctuation
        sentences = re.split(r'[.!?]+', text)
        return len([s for s in sentences if s.strip()])
    
    @staticmethod
    def count_paragraphs(text: str) -> int:
        """Count paragraphs in text"""
        if not text:
            return 0
        paragraphs = text.split('\n\n')
        return len([p for p in paragraphs if p.strip()])
    
    @staticmethod
    def extract_first_sentence(text: str) -> str:
        """Extract first sentence from text"""
        if not text:
            return ""
        
        match = re.search(r'^[^.!?]*[.!?]', text.strip())
        if match:
            return match.group(0).strip()
        
        # If no sentence ending found, return first 100 characters
        return text.strip()[:100] + ('...' if len(text.strip()) > 100 else '')
    
    @staticmethod
    def truncate_text(text: str, max_length: int = 100, suffix: str = '...') -> str:
        """Truncate text to specified length"""
        if not text or len(text) <= max_length:
            return text
        
        # Try to break at word boundary
        if ' ' in text[:max_length]:
            truncated = text[:max_length].rsplit(' ', 1)[0]
        else:
            truncated = text[:max_length]
        
        return truncated + suffix
    
    @staticmethod
    def clean_text(text: str) -> str:
        """Clean text by removing extra whitespace and normalizing"""
        if not text:
            return ""
        
        # Replace multiple spaces with single space
        cleaned = re.sub(r'\s+', ' ', text)
        
        # Remove leading/trailing whitespace
        cleaned = cleaned.strip()
        
        return cleaned
    
    @staticmethod
    def format_reading_time(word_count: int, words_per_minute: int = 200) -> str:
        """Calculate estimated reading time"""
        if word_count == 0:
            return _("0 minutos")
        
        minutes = word_count / words_per_minute
        
        if minutes < 1:
            return _("< 1 minuto")
        elif minutes < 60:
            minute_count = int(minutes)
            if minute_count == 1:
                return _("1 minuto")
            else:
                return _("{} minutos").format(minute_count)
        else:
            hours = int(minutes // 60)
            mins = int(minutes % 60)
            return _("{}h {}m").format(hours, mins)


class ValidationHelper:
    """Helper functions for validation"""
    
    @staticmethod
    def is_valid_filename(filename: str) -> bool:
        """Check if filename is valid"""
        if not filename or filename.strip() == '':
            return False
        
        # Check for invalid characters
        invalid_chars = '<>:"/\\|*'
        if any(char in filename for char in invalid_chars):
            return False
        
        # Check for reserved names (Windows)
        reserved_names = [
            'CON', 'PRN', 'AUX', 'NUL',
            'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',
            'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9'
        ]
        
        name_without_ext = Path(filename).stem.upper()
        if name_without_ext in reserved_names:
            return False
        
        return True
    
    @staticmethod
    def is_valid_project_name(name: str) -> Tuple[bool, str]:
        """Validate project name and return (is_valid, error_message)"""
        if not name or name.strip() == '':
            return False, _("Nome do projeto não pode ser vazio")
        
        name = name.strip()
        
        if len(name) < 2:
            return False, _("Nome do projeto deve ter pelo menos 2 caracteres")
        
        if len(name) > 100:
            return False, _("Nome do projeto não pode exceder 100 caracteres")
        
        if not ValidationHelper.is_valid_filename(name):
            return False, _("Nome do projeto contém caracteres inválidos")
        
        return True, ""
    
    @staticmethod
    def is_valid_email(email: str) -> bool:
        """Basic email validation"""
        if not email:
            return False
        
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        return bool(re.match(pattern, email))
    
    @staticmethod
    def validate_path(path: str) -> Tuple[bool, str]:
        """Validate file/directory path"""
        if not path:
            return False, _("Caminho não pode ser vazio")
        
        try:
            path_obj = Path(path)
            
            # Check if parent directory exists (for file paths)
            if not path_obj.parent.exists():
                return False, _("Diretório pai não existe")
            
            # Check if path is too long (Windows has 260 char limit)
            if len(str(path_obj.resolve())) > 250:
                return False, _("Caminho muito longo")
            
            return True, ""
            
        except Exception as e:
            return False, _("Caminho inválido: {}").format(str(e))


class FormatHelper:
    """Helper functions for formatting"""
    
    @staticmethod
    def format_paragraph_count(count: int) -> str:
        """Format paragraph count with proper pluralization"""
        if count == 1:
            return _("1 parágrafo")
        else:
            return _("{count} parágrafos").format(count=count)
    
    @staticmethod
    def format_word_count(count: int) -> str:
        """Format word count with proper pluralization"""
        if count == 1:
            return _("1 palavra")
        else:
            return _("{count} palavras").format(count=count)
    
    @staticmethod
    def format_project_stats(words: int, paragraphs: int) -> str:
        """Format complete project statistics"""
        word_text = FormatHelper.format_word_count(words)
        paragraph_text = FormatHelper.format_paragraph_count(paragraphs)
        return f"{word_text} • {paragraph_text}"
    
    @staticmethod
    def format_datetime(dt: datetime, format_type: str = 'default') -> str:
        """Format datetime for display"""
        if format_type == 'short':
            return dt.strftime('%d/%m/%Y')
        elif format_type == 'long':
            return dt.strftime('%d/%m/%Y %H:%M')
        elif format_type == 'time':
            return dt.strftime('%H:%M')
        elif format_type == 'iso':
            return dt.isoformat()
        else:  # default
            return dt.strftime('%d/%m/%Y %H:%M')
            
    @staticmethod
    def format_file_size(size_bytes: int) -> str:
        """Format file size in human-readable format"""
        if size_bytes == 0:
            return "0 B"
        
        for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
            if size_bytes < 1024.0:
                return f"{size_bytes:.1f} {unit}"
            size_bytes /= 1024.0
        
        return f"{size_bytes:.1f} PB"
    
    @staticmethod
    def format_statistics(stats: Dict[str, Any]) -> Dict[str, str]:
        """Format statistics for display"""
        formatted = {}
        
        for key, value in stats.items():
            if key.endswith('_count'):
                formatted[key] = f"{value:,}"
            elif key == 'total_words':
                formatted[key] = _("{:,} palavras").format(value)
            elif key == 'total_characters':
                formatted[key] = _("{:,} caracteres").format(value)
            elif isinstance(value, dict):
                # Handle nested dictionaries
                formatted[key] = {k: str(v) for k, v in value.items()}
            else:
                formatted[key] = str(value)
        
        return formatted


class DebugHelper:
    """Helper functions for debugging and logging"""
    
    @staticmethod
    def print_object_info(obj: Any, name: str = "Object") -> None:
        """Print detailed information about an object"""
        print(f"\n=== {name} " + _("Info") + " ===")
        print(_("Tipo: {}").format(type(obj).__name__))
        print(_("Módulo: {}").format(type(obj).__module__))
        
        if hasattr(obj, '__dict__'):
            print(_("Atributos:"))
            for attr, value in obj.__dict__.items():
                print(f"  {attr}: {type(value).__name__} = {repr(value)[:100]}")
        
        print(_("Métodos:"))
        methods = [method for method in dir(obj) if callable(getattr(obj, method)) and not method.startswith('_')]
        for method in methods[:10]:  # Limit to first 10 methods
            print(f"  {method}()")
        
        if len(methods) > 10:
            print(_("  ... e mais {} métodos").format(len(methods) - 10))
        
        print("=" * (len(name) + len(_("Info")) + 4))
    
    @staticmethod
    def log_performance(func_name: str, start_time: datetime, end_time: datetime) -> None:
        """Log performance information"""
        duration = (end_time - start_time).total_seconds()
        print(_("Performance: {} levou {:.3f} segundos").format(func_name, duration))
