"""
Clipboard monitor implementation
"""

import time
import hashlib
import re
from typing import List
from datetime import datetime
from diona.system.sensitive.core.info_store import InfoStore
from diona.system.sensitive.runcontext.models import ContextInfo
from diona.project.storage import ProjectStorage
from .models import ClipboardContent, SensitiveDataMatch, ClipboardEntry, ClipboardMonitoringResult


class ClipboardMonitor:
    """
    Windows clipboard monitor implementation
    """
    
    def __init__(self):
        """Initialize the clipboard monitor"""
        self.info_store = InfoStore()
        self.storage = ProjectStorage()
        self.context_info: ContextInfo = None
        
    def _check_permissions(self) -> bool:
        """
        Check if the current context has sufficient permissions
        
        Returns:
            True if permissions are sufficient, False otherwise
        """
        if not self.context_info:
            self.info_store.initialize()
            self.context_info = self.info_store._context_info
            
        if not self.context_info:
            return False
            
        # For testing purposes, allow execution even if not on Windows
        # In production, this should check for Windows context
        return True
    
    def monitor_clipboard(self, duration: int = 60, interval: float = 1.0) -> ClipboardMonitoringResult:
        """
        Monitor clipboard for specified duration
        
        Args:
            duration: Monitoring duration in seconds
            interval: Check interval in seconds
            
        Returns:
            Clipboard monitoring result
        """
        if not self._check_permissions():
            return ClipboardMonitoringResult(
                success=False,
                entries=[],
                duration=duration,
                interval=interval,
                error_message="Insufficient permissions for clipboard monitoring"
            )
            
        entries: List[ClipboardEntry] = []
        last_content_hash = ""
        start_time = time.time()
        
        print(f"Monitoring clipboard for {duration} seconds...")
        
        while time.time() - start_time < duration:
            try:
                current_content = self._get_current_content()
                
                if current_content and current_content.has_text and current_content.text:
                    content_hash = hashlib.md5(current_content.text.encode('utf-8')).hexdigest()
                    
                    if content_hash != last_content_hash:
                        # Check for sensitive data
                        sensitive_data = self._detect_sensitive_data(current_content.text)
                        
                        entry = ClipboardEntry(
                            content=current_content,
                            sensitive_data=sensitive_data,
                            has_sensitive_data=len(sensitive_data) > 0
                        )
                        
                        entries.append(entry)
                        last_content_hash = content_hash
                        
                        if sensitive_data:
                            print(f"Sensitive data detected: {[match.match_type for match in sensitive_data]}")
                            
            except Exception as e:
                print(f"Error reading clipboard: {e}")
                
            time.sleep(interval)
            
        # Save results
        if entries:
            self._save_results(entries, duration, interval)
            
        return ClipboardMonitoringResult(
            success=True,
            entries=entries,
            duration=duration,
            interval=interval
        )
    
    def _get_current_content(self) -> ClipboardContent:
        """
        Get current clipboard content
        
        Returns:
            Current clipboard content
        """
        try:
            import win32clipboard
            
            content = ClipboardContent(
                timestamp=datetime.now(),
                has_text=False,
                has_image=False,
                has_files=False
            )
            
            win32clipboard.OpenClipboard()
            
            # Check for text content
            if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_UNICODETEXT):
                try:
                    text = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
                    if text:
                        content.text = text
                        content.has_text = True
                except:
                    pass
                    
            # Check for text content (ASCII)
            if not content.has_text and win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_TEXT):
                try:
                    text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
                    if text:
                        content.text = text
                        content.has_text = True
                except:
                    pass
                    
            # Check for file drops
            if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_HDROP):
                try:
                    files = win32clipboard.GetClipboardData(win32clipboard.CF_HDROP)
                    content.has_files = True
                    content.file_count = len(files) if files else 0
                except:
                    pass
                    
            # Check for images
            if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_BITMAP):
                content.has_image = True
                
            win32clipboard.CloseClipboard()
            
            return content
            
        except ImportError:
            print("pywin32 module not available")
            return ClipboardContent(timestamp=datetime.now())
        except Exception as e:
            print(f"Error accessing clipboard: {e}")
            return ClipboardContent(timestamp=datetime.now())
    
    def _detect_sensitive_data(self, text: str) -> List[SensitiveDataMatch]:
        """
        Detect sensitive data patterns in text
        
        Args:
            text: Text to analyze
            
        Returns:
            List of detected sensitive data patterns
        """
        if not text:
            return []
            
        sensitive_matches: List[SensitiveDataMatch] = []
        
        # Define detection patterns
        patterns = {
            "email": r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b",
            "phone": r"\b\d{3}[-.\s]?\d{3}[-.\s]?\d{4}\b",
            "credit_card": r"\b(?:\d{4}[- ]?){3}\d{4}\b",
            "ssn": r"\b\d{3}[-]?\d{2}[-]?\d{4}\b",
            "api_key": r"\b(?:api[_-]?key|apikey|secret[_-]?key)\s*[=:]\s*[\w-]{20,}\b",
            "password": r"\b(?:password|passwd|pwd)\s*[=:]\s*\S+\b",
            "private_key": r"-----BEGIN (?:RSA |EC )?PRIVATE KEY-----",
            "aws_key": r"\b(?:AKIA|ABIA|ACCA)[A-Z0-9]{16}\b",
            "bearer_token": r"\bBearer\s+[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\b"
        }
        
        for pattern_name, pattern in patterns.items():
            matches = re.findall(pattern, text, re.IGNORECASE)
            
            if matches:
                # Sanitize the sample (don't expose actual sensitive data)
                sample = matches[0]
                if pattern_name in ["api_key", "aws_key", "bearer_token", "private_key"]:
                    sample = "[REDACTED]"
                elif pattern_name == "password":
                    # Extract just the key part, not the value
                    if "=" in sample or ":" in sample:
                        sample = sample.split("=")[0] if "=" in sample else sample.split(":")[0]
                
                match = SensitiveDataMatch(
                    match_type=pattern_name,
                    count=len(matches),
                    sample=sample
                )
                sensitive_matches.append(match)
                
        return sensitive_matches
    
    def _save_results(self, entries: List[ClipboardEntry], duration: int, interval: float) -> bool:
        """
        Save monitoring results to storage using ProjectStorage
        
        Args:
            entries: List of clipboard entries to save
            duration: Monitoring duration
            interval: Check interval
            
        Returns:
            True if save successful, False otherwise
        """
        try:
            import json
            from datetime import datetime
            
            # Convert entries to serializable format
            serializable_entries = []
            for entry in entries:
                entry_dict = {
                    "timestamp": entry.content.timestamp.isoformat(),
                    "has_text": entry.content.has_text,
                    "has_image": entry.content.has_image,
                    "has_files": entry.content.has_files,
                    "file_count": entry.content.file_count,
                    "image_size": entry.content.image_size,
                    "has_sensitive_data": entry.has_sensitive_data,
                    "sensitive_data": [
                        {
                            "match_type": match.match_type,
                            "count": match.count,
                            "sample": match.sample
                        }
                        for match in entry.sensitive_data
                    ]
                }
                
                # Only include text if it's not too long and doesn't contain sensitive data
                if entry.content.text and len(entry.content.text) < 1000 and not entry.has_sensitive_data:
                    entry_dict["text_preview"] = entry.content.text[:200] + "..." if len(entry.content.text) > 200 else entry.content.text
                
                serializable_entries.append(entry_dict)
            
            # Create result data
            result_data = {
                "timestamp": datetime.now().isoformat(),
                "duration": duration,
                "interval": interval,
                "entry_count": len(entries),
                "sensitive_entry_count": sum(1 for entry in entries if entry.has_sensitive_data),
                "entries": serializable_entries
            }
            
            # Use ProjectStorage to save the file
            filename = f"clipboard_monitoring_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
            content = json.dumps(result_data, indent=2, ensure_ascii=False)
            
            success = self.storage.write("windows/clipboard", filename, content, storage_type="project")
            return success
            
        except Exception as e:
            print(f"Error saving clipboard results: {e}")
            return False