import subprocess
import json
import logging
from typing import List, Dict, Any

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class VulnerabilityChecker:
    """
    A class to check dependencies for known vulnerabilities using multiple tools.
    """

    def __init__(self, requirements_file: str = "requirements.txt"):
        """
        Initializes the VulnerabilityChecker with the path to the requirements file.

        Args:
            requirements_file: The path to the requirements.txt file.
        """
        self.requirements_file = requirements_file
        self.vulnerabilities: List[Dict[str, Any]] = []

    def run_pip_audit(self) -> List[Dict[str, Any]]:
        """
        Runs pip-audit to check for vulnerabilities.

        Returns:
            A list of dictionaries, where each dictionary represents a vulnerability.
        """
        try:
            result = subprocess.run(
                ["pip-audit", "-r", self.requirements_file, "--format", "json"],
                capture_output=True,
                text=True,
                check=True,
            )
            vulnerabilities = json.loads(result.stdout)
            logging.info("pip-audit completed successfully.")
            return vulnerabilities
        except subprocess.CalledProcessError as e:
            logging.error(f"pip-audit failed: {e.stderr}")
            return []
        except json.JSONDecodeError as e:
            logging.error(f"Failed to decode pip-audit JSON output: {e}")
            return []
        except FileNotFoundError:
            logging.error("pip-audit is not installed. Please install it using 'pip install pip-audit'.")
            return []


    def run_safety(self) -> List[Dict[str, Any]]:
        """
        Runs safety to check for vulnerabilities.

        Returns:
            A list of dictionaries, where each dictionary represents a vulnerability.
        """
        try:
            result = subprocess.run(
                ["safety", "check", "--file", self.requirements_file, "--output", "json"],
                capture_output=True,
                text=True,
                check=True,
            )
            vulnerabilities = json.loads(result.stdout)
            logging.info("safety check completed successfully.")
            return vulnerabilities
        except subprocess.CalledProcessError as e:
            logging.error(f"safety check failed: {e.stderr}")
            return []
        except json.JSONDecodeError as e:
            logging.error(f"Failed to decode safety JSON output: {e}")
            return []
        except FileNotFoundError:
            logging.error("safety is not installed. Please install it using 'pip install safety'.")
            return []

    def generate_report(self) -> List[Dict[str, Any]]:
        """
        Generates a vulnerability report by combining results from different tools.

        Returns:
            A list of dictionaries, where each dictionary represents a vulnerability.
        """
        pip_audit_vulnerabilities = self.run_pip_audit()
        safety_vulnerabilities = self.run_safety()

        # Combine vulnerabilities and remove duplicates (if any)
        all_vulnerabilities = pip_audit_vulnerabilities + safety_vulnerabilities
        unique_vulnerabilities = []
        seen = set()

        for vulnerability in all_vulnerabilities:
            # Create a unique identifier for the vulnerability
            identifier = (
                vulnerability.get("package", "") +
                vulnerability.get("version", "") +
                vulnerability.get("vulnerability_id", "") +
                vulnerability.get("advisory", "")  # Use advisory for safety
            )

            if identifier not in seen:
                unique_vulnerabilities.append(vulnerability)
                seen.add(identifier)

        self.vulnerabilities = unique_vulnerabilities
        return self.vulnerabilities

    def print_report(self):
        """
        Prints the vulnerability report to the console.
        """
        report = self.generate_report()
        if not report:
            print("No vulnerabilities found.")
            return

        print("Vulnerability Report:")
        for vulnerability in report:
            print("-" * 40)
            for key, value in vulnerability.items():
                print(f"{key}: {value}")
            print("-" * 40)

if __name__ == "__main__":
    # Example usage:
    checker = VulnerabilityChecker()
    checker.print_report()
