import os
import re
import json
import glob
import shutil
import subprocess
import hashlib
from datetime import datetime
from concurrent.futures import ThreadPoolExecutor, as_completed
from .utils.os_detection import detect_os, detect_pm
from .utils.package_manager import list_packages, get_package_info
from .utils.downloader import download_source
from .utils.hash_calculator import calculate_file_hash
from .utils.swhid_calculator import calculate_swhid

class Scanner:
    def __init__(self, threads=4, output_dir="ossa_reports", temp_dir="/tmp/ossa_temp"):
        self.output_dir = output_dir
        self.temp_dir = temp_dir
        self.os_type = detect_os()
        self.pm_type = detect_pm()
        self.threads = threads
        os.makedirs(self.temp_dir, exist_ok=True)

    def process_package(self, package):
        try:
            print(f"Processing package: {package}")
            package_info = get_package_info(self.pm_type, package, self.temp_dir)
            source_files = download_source(self.pm_type, package, self.temp_dir)
            print(package, package_info)
            self.save_package_report(package, package_info, source_files)
        except Exception as e:
            print(f"Error processing package {package}: {e}")

    def scan_packages(self):
        """
        Scans all packages in the repository and processes them in parallel.
        """
        print(f"Detected Package Manager: {self.pm_type}")
        print("Listing available packages...")
        packages = list_packages(self.pm_type)
        with ThreadPoolExecutor(max_workers=self.threads) as executor:
            # Submit tasks for parallel processing
            future_to_package = {
                executor.submit(self.process_package, package): package
                for package in packages
            }

            for future in as_completed(future_to_package):
                package = future_to_package[future]
                try:
                    future.result()
                except Exception as e:
                    print(f"Exception occurred for package {package}: {e}")

    def save_package_report(self, package, package_info, source_files):
        # Generate report filename
        purl_name = package_info.get("name")
        purl_version = package_info.get("version")
        pkg_type = "deb" if self.pm_type == "apt" else "rpm" if self.pm_type == "yum" else self.pm_type
        os_type =  self.os_type
        date_str = datetime.now().strftime("%Y%m%d")
        report_filename = f"ossa-{date_str}-{hash(purl_name) % 10000}-{purl_name}.json"
        report_path = os.path.join(self.output_dir, report_filename)

        if package_info.get("version") != "*":
            affected_versions = ["*.*", package_info.get("version")]
        else:
            affected_versions = ["*.*"]

        artifacts = []
        for source_file in source_files:
            artifact = {}

            # Clean up the artifact name
            artifact_name = os.path.basename(source_file)
            if "--" in artifact_name:
                artifact_name = artifact_name.split("--")[-1]
            artifact['url'] = "file://" + artifact_name

            file_hash = calculate_file_hash(source_file)
            artifact['hashes'] = file_hash

            # Extract source code directory in temp_dir
            # Only required if calculating SWHID
            source_dir = os.path.join(self.temp_dir, package)
            os.makedirs(source_dir, exist_ok=True)
            swhid = calculate_swhid(source_dir, source_file)
            artifact['swhid'] = swhid

            artifacts.append(artifact)

        # Create the report content
        report = {
            "id": f"OSSA-{date_str}-{hash(purl_name) % 10000}",
            "version": "1.0.0",
            "severity": package_info.get("severity", []),
            "description": package_info.get("rason", []),
            "title": f"Advisory for {purl_name}",
            "package_name": purl_name,
            "publisher": "Generated by OSSA Collector",
            "last_updated": datetime.now().isoformat(),
            "approvals": [{"consumption": True, "externalization": True}],
            "description": package_info.get("summary", []),
            "purls": [f"pkg:{pkg_type}/{os_type}/{purl_name}@{purl_version}"],
            "regex": [f"^pkg:{pkg_type}/{os_type}/{purl_name}.*"],
            "affected_versions": affected_versions,
            "artifacts": artifacts,
            "licenses": package_info.get("licenses", []),
            "aliases": package_info.get("aliases", []),
            "references": package_info.get("references", [])
        }

        # Save the report to the output directory
        with open(report_path, "w") as f:
            json.dump(report, f, indent=4)
        print(f"Report saved: {report_path}")
