"""
Sink Detection Module
"""

import re
from pathlib import Path
from typing import List, Dict

from ..utils.logger import log_progress
from ..utils.fs import save_json

class SinkDetector:
    """Detect potential security sinks in JavaScript"""
    
    def __init__(self, output_dir: Path):
        self.output_dir = output_dir
        
        # Define sink patterns with risk levels
        self.sink_patterns = {
            'dom_sinks': {
                'risk': 'high',
                'patterns': [
                    r'\.innerHTML\s*=',
                    r'\.outerHTML\s*=',
                    r'document\.write\s*\(',
                    r'document\.writeln\s*\(',
                    r'\.insertAdjacentHTML\s*\('
                ]
            },
            'eval_sinks': {
                'risk': 'critical',
                'patterns': [
                    r'eval\s*\(',
                    r'Function\s*\(',
                    r'setTimeout\s*\([^,]*[\'"][^\'",]*\+[^\'",]*[\'"]',
                    r'setInterval\s*\([^,]*[\'"][^\'",]*\+[^\'",]*[\'"]'
                ]
            },
            'url_sinks': {
                'risk': 'medium',
                'patterns': [
                    r'location\.href\s*=',
                    r'location\.replace\s*\(',
                    r'location\.assign\s*\(',
                    r'window\.open\s*\(',
                    r'history\.pushState\s*\(',
                    r'history\.replaceState\s*\('
                ]
            },
            'storage_sinks': {
                'risk': 'low',
                'patterns': [
                    r'localStorage\.setItem\s*\(',
                    r'sessionStorage\.setItem\s*\(',
                    r'document\.cookie\s*='
                ]
            }
        }
    
    def detect_sinks_in_content(self, content: str, filename: str) -> List[Dict]:
        """Detect sinks in JavaScript content"""
        sinks = []
        
        for sink_type, config in self.sink_patterns.items():
            risk_level = config['risk']
            patterns = config['patterns']
            
            for pattern_str in patterns:
                try:
                    pattern = re.compile(pattern_str, re.IGNORECASE | re.MULTILINE)
                    
                    for match in pattern.finditer(content):
                        line_num = content[:match.start()].count('\n') + 1
                        
                        sink = {
                            'type': sink_type,
                            'pattern': pattern_str,
                            'match': match.group(0),
                            'line': line_num,
                            'risk': risk_level,
                            'filename': filename,
                            'context': self.get_context(content, match.start())
                        }
                        
                        sinks.append(sink)
                        
                except re.error as e:
                    log_progress(f"Warning: Invalid sink pattern '{pattern_str}' - {e}")
        
        return sinks
    
    def get_context(self, content: str, position: int, context_length: int = 100) -> str:
        """Get context around a sink"""
        start = max(0, position - context_length)
        end = min(len(content), position + context_length)
        
        context = content[start:end]
        return re.sub(r'\s+', ' ', context).strip()
    
    def detect_sinks(self, js_files: List[Dict]) -> List[Dict]:
        """Detect sinks in JavaScript files"""
        log_progress("Running sink detection")
        
        all_sinks = []
        
        for js_file in js_files:
            if js_file.get('status') != 'success' or not js_file.get('filepath'):
                continue
            
            try:
                with open(js_file['filepath'], 'r', encoding='utf-8', errors='ignore') as f:
                    content = f.read()
                
                filename = Path(js_file['filepath']).name
                sinks = self.detect_sinks_in_content(content, filename)
                all_sinks.extend(sinks)
                
            except Exception as e:
                log_progress(f"Warning: Could not analyze {js_file['filepath']} for sinks - {e}")
        
        # Save results
        save_json(all_sinks, self.output_dir / "sinks_results.json")
        
        # Count by risk level
        risk_counts = {}
        for sink in all_sinks:
            risk = sink['risk']
            risk_counts[risk] = risk_counts.get(risk, 0) + 1
        
        log_progress(f"Found {len(all_sinks)} potential sinks: {risk_counts}")
        
        return all_sinks