"""
Base class for security checks.
"""

import abc
from typing import Dict, List, Optional, Any, Tuple

from vulnerability_checker.models import VulnerabilityIssue, CheckResult, CheckStatus


class BaseCheck(abc.ABC):
    """
    Base class for all security checks.
    """
    
    name: str = "base-check"
    description: str = "Base check"
    
    # List of directories to exclude from checking
    DEFAULT_EXCLUDE_DIRS = {
        ".git", 
        ".venv", 
        "venv", 
        "env", 
        "__pycache__",
        ".idea",
        ".vscode"
    }
    
    def __init__(self, config: Optional[Dict[str, Any]] = None):
        """
        Check initialization.
        
        Args:
            config: Check configuration
        """
        self.config = config or {}
        self.issues: List[VulnerabilityIssue] = []
        
        # Adding additional exclusions from configuration
        self.exclude_dirs = self.DEFAULT_EXCLUDE_DIRS.copy()
        if config and "exclude_patterns" in config:
            for pattern in config["exclude_patterns"]:
                if pattern.endswith("/*"):
                    self.exclude_dirs.add(pattern[:-2])
                else:
                    self.exclude_dirs.add(pattern)
    
    @abc.abstractmethod
    def run(self, target_path: str, **kwargs) -> Tuple[CheckResult, List[VulnerabilityIssue]]:
        """
        Run check.
        
        Args:
            target_path: Path to directory or file for checking
            **kwargs: Additional parameters
            
        Returns:
            Tuple[CheckResult, List[VulnerabilityIssue]]: Check result and list of found vulnerabilities
        """
        raise NotImplementedError()
    
    def add_issue(
        self,
        issue_type: str,
        severity: str,
        description: str,
        file_path: str,
        line_number: int,
        code_snippet: str = "",
        confidence: str = "MEDIUM",
        cwe_id: Optional[str] = None,
        owasp_category: Optional[str] = None,
        remediation: Optional[str] = None,
    ) -> VulnerabilityIssue:
        """
        Add vulnerability.
        
        Args:
            issue_type: Vulnerability type
            severity: Severity level
            description: Vulnerability description
            file_path: File path
            line_number: Line number
            code_snippet: Code fragment
            confidence: Detection confidence level
            cwe_id: CWE identifier
            owasp_category: OWASP category
            remediation: Remediation recommendations
            
        Returns:
            VulnerabilityIssue: Vulnerability object
        """
        issue = VulnerabilityIssue(
            issue_type=issue_type,
            severity=severity,
            description=description,
            file_path=file_path,
            line_number=line_number,
            code_snippet=code_snippet,
            confidence=confidence,
            cwe_id=cwe_id,
            owasp_category=owasp_category,
            remediation=remediation,
            check_name=self.name,
        )
        self.issues.append(issue)
        return issue
    
    def create_result(self, status: CheckStatus, message: Optional[str] = None) -> CheckResult:
        """
        Create check result.
        
        Args:
            status: Check status
            message: Message
            
        Returns:
            CheckResult: Check result
        """
        return CheckResult(
            status=status,
            issues_count=len(self.issues),
            message=message,
        )
        
    def should_exclude_path(self, path: str) -> bool:
        """
        Check if path should be excluded from checking.
        
        Args:
            path: Path to check
            
        Returns:
            bool: True if path should be excluded
        """
        path = str(path)
        for exclude in self.exclude_dirs:
            if exclude in path:
                return True
        return False 