"""
Sensitive file analyzer implementation
"""

import os
import re
from typing import List
from datetime import datetime
from diona.project.storage import ProjectStorage
from .models import SensitiveFinding, FileAnalysisResult, BatchAnalysisResult


class FileAnalyzer:
    """
    Configuration file analyzer for detecting plaintext passwords
    """
    
    def __init__(self):
        """Initialize the file analyzer"""
        self.storage = ProjectStorage()
        
    def analyze_files(self, file_paths: List[str]) -> BatchAnalysisResult:
        """
        Analyze configuration files for sensitive information
        
        Args:
            file_paths: List of file paths to analyze
            
        Returns:
            Batch analysis result
        """
        results: List[FileAnalysisResult] = []
        
        for file_path in file_paths:
            if not os.path.exists(file_path):
                result = FileAnalysisResult(
                    file_path=file_path,
                    findings=[],
                    success=False,
                    error_message="File does not exist"
                )
                results.append(result)
                continue
                
            try:
                findings = self._analyze_single_file(file_path)
                result = FileAnalysisResult(
                    file_path=file_path,
                    findings=findings,
                    success=True
                )
                results.append(result)
            except Exception as e:
                result = FileAnalysisResult(
                    file_path=file_path,
                    findings=[],
                    success=False,
                    error_message=str(e)
                )
                results.append(result)
                
        # Save results
        if results:
            self._save_results(results)
            
        return BatchAnalysisResult(
            results=results,
            total_files=len(file_paths)
        )
    
    def _analyze_single_file(self, file_path: str) -> List[SensitiveFinding]:
        """
        Analyze a single file for sensitive information
        
        Args:
            file_path: Path to the file to analyze
            
        Returns:
            List of findings for the file
        """
        findings: List[SensitiveFinding] = []
        
        try:
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                content = f.read()
                
            # Password-related keywords (case-insensitive)
            password_keywords = [
                "password", "passwd", "pwd", "secret", "api_key", "apikey",
                "access_key", "secret_key", "auth_token", "bearer_token",
                "connection_string", "db_password", "database_password",
                "mysql_password", "redis_password", "postgres_password",
                "mongodb_password", "sql_password"
            ]
            
            lines = content.split('\n')
            
            for line_number, line in enumerate(lines, 1):
                line = line.strip()
                
                for keyword in password_keywords:
                    # Case-insensitive search for keyword
                    if re.search(rf'\b{keyword}\b', line, re.IGNORECASE):
                        
                        # Check if it's an assignment statement
                        if '=' in line or ':' in line:
                            # Extract the value part (sanitized)
                            if '=' in line:
                                parts = line.split('=', 1)
                                key_part = parts[0].strip()
                                value_part = parts[1].strip() if len(parts) > 1 else ""
                            else:
                                parts = line.split(':', 1)
                                key_part = parts[0].strip()
                                value_part = parts[1].strip() if len(parts) > 1 else ""
                            
                            # Determine password type based on context
                            password_type = self._infer_password_type(keyword, line)
                            
                            # Find column position
                            keyword_pos = line.lower().find(keyword.lower())
                            
                            # Sanitize the line
                            sanitized_line = self._sanitize_line(line)
                            
                            finding = SensitiveFinding(
                                file_path=file_path,
                                line_number=line_number,
                                column=keyword_pos + 1,
                                keyword=keyword,
                                key_part=key_part,
                                value_length=len(value_part),
                                password_type=password_type,
                                file_type=self._determine_file_type(file_path),
                                sanitized_line=sanitized_line
                            )
                            
                            findings.append(finding)
                            
        except Exception as e:
            raise Exception(f"Error reading file {file_path}: {e}")
            
        return findings
    
    def _infer_password_type(self, keyword: str, line: str) -> str:
        """
        Infer the type of password based on context
        
        Args:
            keyword: The keyword found
            line: The line containing the keyword
            
        Returns:
            Inferred password type
        """
        line_lower = line.lower()
        
        # Database types
        if "mysql" in line_lower or "mariadb" in line_lower:
            return "mysql"
        elif "postgres" in line_lower or "postgresql" in line_lower:
            return "postgresql"
        elif "redis" in line_lower:
            return "redis"
        elif "mongodb" in line_lower or "mongo" in line_lower:
            return "mongodb"
        elif "sql" in line_lower and "server" in line_lower:
            return "sqlserver"
        elif "oracle" in line_lower:
            return "oracle"
        
        # API/Service types
        elif "aws" in line_lower:
            return "aws"
        elif "azure" in line_lower:
            return "azure"
        elif "google" in line_lower or "gcp" in line_lower:
            return "gcp"
        elif "api" in keyword.lower():
            return "api"
        elif "token" in keyword.lower():
            return "token"
        
        # General types
        elif "db" in keyword.lower() or "database" in keyword.lower():
            return "database"
        elif "connection" in keyword.lower():
            return "connection_string"
        
        return "generic"
    
    def _determine_file_type(self, file_path: str) -> str:
        """
        Determine the type of configuration file
        
        Args:
            file_path: Path to the file
            
        Returns:
            File type identifier
        """
        filename = os.path.basename(file_path).lower()
        
        if filename.endswith('.json'):
            return "json"
        elif filename.endswith('.yml') or filename.endswith('.yaml'):
            return "yaml"
        elif filename.endswith('.xml'):
            return "xml"
        elif filename.endswith('.ini') or filename.endswith('.cfg') or filename.endswith('.conf'):
            return "ini"
        elif filename.endswith('.properties'):
            return "properties"
        elif filename.endswith('.env') or filename == '.env':
            return "env"
        elif filename.endswith('.config'):
            return "dotnet_config"
        elif filename == '.gitconfig':
            return "git_config"
        elif filename == 'credentials' and '.aws' in file_path:
            return "aws_credentials"
        else:
            return "unknown"
    
    def _sanitize_line(self, line: str) -> str:
        """
        Sanitize a line to hide actual password values
        
        Args:
            line: Original line
            
        Returns:
            Sanitized line
        """
        # Replace password values with [REDACTED]
        sanitized = re.sub(
            r'(password|passwd|pwd|secret|api_key|apikey|access_key|secret_key|auth_token|bearer_token)\s*[=:]\s*[^\s\n]+',
            r'\1 = [REDACTED]',
            line,
            flags=re.IGNORECASE
        )
        
        return sanitized
    
    def _save_results(self, results: List[FileAnalysisResult]) -> bool:
        """
        Save analysis results to storage using ProjectStorage
        
        Args:
            results: List of file analysis results to save
            
        Returns:
            True if save successful, False otherwise
        """
        try:
            import json
            from datetime import datetime
            
            # Convert results to serializable format
            serializable_results = []
            for result in results:
                result_dict = {
                    "file_path": result.file_path,
                    "success": result.success,
                    "error_message": result.error_message,
                    "timestamp": result.timestamp.isoformat() if result.timestamp else None,
                    "findings": [
                        {
                            "line_number": finding.line_number,
                            "column": finding.column,
                            "keyword": finding.keyword,
                            "key_part": finding.key_part,
                            "value_length": finding.value_length,
                            "password_type": finding.password_type,
                            "file_type": finding.file_type,
                            "sanitized_line": finding.sanitized_line
                        }
                        for finding in result.findings
                    ]
                }
                serializable_results.append(result_dict)
            
            # Create result data
            result_data = {
                "timestamp": datetime.now().isoformat(),
                "total_files": len(results),
                "successful_files": sum(1 for r in results if r.success),
                "total_findings": sum(len(r.findings) for r in results if r.success),
                "results": serializable_results
            }
            
            # Use ProjectStorage to save the file
            filename = f"sensitive_file_analysis_{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/sensitivefile", filename, content, storage_type="project")
            return success
            
        except Exception as e:
            print(f"Error saving file analysis results: {e}")
            return False