import os
import sys
import hashlib
import requests
import time
import re
import pyfiglet
import webbrowser
import platform
from datetime import datetime, timezone
from colorama import Fore, Style
import subprocess
def typewriter_print(text, delay=0.03, color=Fore.WHITE):
    """Prints text one character at a time for typewriter effect."""
    for char in text:
        sys.stdout.write(color + char + Style.RESET_ALL)
        sys.stdout.flush()
        time.sleep(delay)
    print() 

def display_title():
    ascii_art = pyfiglet.figlet_format("Malware Sentinel", font="slant")
    for line in ascii_art.split("\n"):
        print(Fore.CYAN + line)
        time.sleep(0.05)
    typewriter_print("Author: cyb2rS2c", delay=0.05, color=Fore.RED)
    typewriter_print("Welcome to the file, hash, IP, and domain scanner.", delay=0.04, color=Fore.YELLOW)
    typewriter_print("This tool allows you to check files, hashes, IP addresses, and domains against VirusTotal.", delay=0.02, color=Fore.WHITE)
    time.sleep(0.5)

def list_and_get_the_file(file):  # Lists files and checks if the file exists
    if os.path.isabs(file):  # If the user provides a full path
        if os.path.exists(file):
            return file
        else:
            print(Fore.RED + "The file does not exist at the specified path.")
            return None
    else:  # Check in the current directory if a relative path is provided
        if file in os.listdir(os.path.abspath('.')):
            return os.path.abspath(file)
        else:
            print(Fore.RED + "File not found in the current directory.")
            return None

def calc_md5(file):  # Calculates MD5 checksum of the file
    hasher = hashlib.md5()
    with open(file, 'rb') as f:
        for chunk in iter(lambda: f.read(4096), b''):
            hasher.update(chunk)
        return hasher.hexdigest()

def if_is_valid_md5(file):  # Checks and returns MD5 checksum
    if os.path.exists(file):
        md5 = calc_md5(file)
        return md5
    else:
        print(Fore.RED + "File does not exist.")
        return None


# ========== INPUT VALIDATION ==========

def is_valid_ip(ip):
    """Check if input is a valid IPv4 or IPv6 address."""
    # IPv4
    ipv4_pattern = r"^\d{1,3}(\.\d{1,3}){3}$"
    # IPv6 (very simplified, enough for VirusTotal queries)
    ipv6_pattern = r"^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$"
    return re.match(ipv4_pattern, ip) is not None or re.match(ipv6_pattern, ip) is not None

def is_valid_hash(h):
    """Check if input looks like a valid MD5, SHA1, or SHA256 hash."""
    # MD5 = 32 chars, SHA1 = 40 chars, SHA256 = 64 chars
    return re.match(r"^[a-fA-F0-9]{32}$", h) or re.match(r"^[a-fA-F0-9]{40}$", h) or re.match(r"^[a-fA-F0-9]{64}$", h)

def is_valid_domain(domain: str) -> bool:
    """Basic domain validation (example.com, sub.domain.org, etc.)."""
    pattern = r"^(?!-)[A-Za-z0-9-]{1,63}(?<!-)\.[A-Za-z]{2,}$"
    return re.match(pattern, domain) is not None

# Function to provide dynamic recommendations based on VirusTotal's analysis
def give_recommendations(analysis_stats, total_votes, item_type):
    malicious = analysis_stats.get('malicious', 0)
    suspicious = analysis_stats.get('suspicious', 0)
    harmless = analysis_stats.get('harmless', 0)
    undetected = analysis_stats.get('undetected', 0)

    # Malicious Item
    if malicious > 0:
        print(Fore.RED + "Recommendation: This item is flagged as malicious.")
        print(Fore.RED + "Do not trust the item. Run a full system scan immediately.")
        if item_type == "file":
            print(Fore.YELLOW + "You can use Microsoft's MRT (Malicious Software Removal Tool) on Windows.")
            print(Fore.GREEN + "On Linux, use ClamAV for a full scan.")
        elif item_type in ["ip", "domain"]:
            print(Fore.GREEN + "Ensure your network is secure. Investigate the source of the IP or domain.")

    # Suspicious Item
    elif suspicious > 0:
        print(Fore.YELLOW + "Recommendation: This item is suspicious.")
        print(Fore.YELLOW + "Further analysis is recommended. Use a different antivirus tool or inspect manually.")
        print(Fore.GREEN + "Consider running a scan with MRT or ClamAV.")

    # Harmless Item
    elif harmless > 0:
        print(Fore.GREEN + "Recommendation: This item is considered harmless by antivirus engines.")
        print(Fore.GREEN + "You can trust this item, but proceed with caution. There’s always a small chance of misclassification.")

    # Undetected Item
    elif undetected > 0:
        print(Fore.YELLOW + "Recommendation: This item has not been detected by most antivirus engines.")
        print(Fore.YELLOW + "Although not flagged, it is still not fully analyzed.")
        print(Fore.RED + "Run a full system scan immediately to ensure no threat.")
    
    # If no data or unclassified
    else:
        print(Fore.RED + "Recommendation: Unable to classify this item.")
        print(Fore.YELLOW + "Consider uploading the item to other antivirus platforms for a second opinion.")
        print(Fore.GREEN + "In the meantime, perform a manual scan on your system.")

# Function to make the API request and return the response data
def request_page(url, api_key, item_type):
    headers = {"x-apikey": api_key}
    
    try:
        response = requests.get(url, headers=headers)
        
        if response.status_code == 200:
            print(Fore.GREEN + "GET request successful.")
            return response.json()
        
        elif response.status_code == 404:
            print(Fore.RED + "Error: Item not found in VirusTotal's database.")
            print(Fore.YELLOW + "This item might not have been uploaded before or it's not indexed yet.")
            print(Fore.CYAN + "Recommendation: Consider uploading the item manually to VirusTotal.")
            print(Fore.GREEN + "You can scan the item locally with antivirus tools.")
            print(Fore.CYAN + "Please visit VirusTotal: https://www.virustotal.com/")
            return None
        
        else:
            print(Fore.RED + f"GET request failed with status code: {response.status_code}")
            return None

    except requests.RequestException as e:
        print(Fore.RED + f"An error occurred: {e}")
        return None


def open_virus_total_gui(item_id, item_type):
    """Opens the VirusTotal page for the file, hash, IP, or domain."""

    # Construct the VirusTotal URL
    if item_type in ["file", "hash"]:
        url = f"https://www.virustotal.com/gui/file/{item_id}"
    elif item_type == "ip":
        url = f"https://www.virustotal.com/gui/ip-address/{item_id}"
    elif item_type == "domain":
        url = f"https://www.virustotal.com/gui/domain/{item_id}"
    else:
        print(Fore.RED + "Invalid item type.")
        return

    print(Fore.GREEN + f"Opening the following URL: {url}")

    # Detect OS and open browser accordingly
    os_name = platform.system()
    if os_name == "Linux":
        try:
            # Try to use Firefox on Linux
            firefox = webbrowser.get("firefox")
            firefox.open(url)
        except webbrowser.Error:
            print(Fore.RED + "Firefox not found. Opening with default browser instead.")
            webbrowser.open(url)
    elif os_name == "Windows":
        webbrowser.open(url)  # Default on Windows
    else:
        print(Fore.YELLOW + f"Unrecognized OS ({os_name}). Using default browser.")
        webbrowser.open(url)



def print_analysis_results(analysis_stats, total_votes, item_id, item_type, data):
    print(Fore.CYAN + "\nLast Analysis Stats:")
    print(Fore.RED + f"Malicious: {analysis_stats.get('malicious', 0)}")
    print(Fore.YELLOW + f"Suspicious: {analysis_stats.get('suspicious', 0)}")
    print(Fore.GREEN + f"Harmless: {analysis_stats.get('harmless', 0)}")
    print(Fore.MAGENTA + f"Undetected: {analysis_stats.get('undetected', 0)}")

    print(Fore.CYAN + "\nTotal Votes:")
    print(Fore.GREEN + f"Harmless Votes: {total_votes.get('harmless', 0)}")
    print(Fore.RED + f"Malicious Votes: {total_votes.get('malicious', 0)}")

    attributes = data.get("data", {}).get("attributes", {})

    # ================== Domain Info ==================
    if item_type == "domain":
        print(Fore.CYAN + "\n=== Domain Info ===")
        print(Fore.WHITE + f"Domain ID: {data.get('data', {}).get('id')}")
        print(Fore.WHITE + f"TLD: {attributes.get('tld')}")
        print(Fore.WHITE + f"Registrar: {attributes.get('registrar')}")
        print(Fore.WHITE + f"Reputation: {attributes.get('reputation')}")

        # Dates
        for key, label in [("creation_date", "Creation"), 
                           ("expiration_date", "Expiration"), 
                           ("last_modification_date", "Last Modification")]:
            ts = attributes.get(key)
            if ts:
                print(Fore.CYAN + f"{label} Date: {datetime.fromtimestamp(ts, tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S')}")

        # Popularity ranks
        ranks = attributes.get("popularity_ranks", {})
        if ranks:
            print(Fore.CYAN + "\nPopularity Ranks:")
            for engine, info in ranks.items():
                rank = info.get("rank", "N/A")
                ts = info.get("timestamp")
                ts_str = datetime.fromtimestamp(ts, tz=timezone.utc).strftime("%Y-%m-%d") if ts else "N/A"
                print(Fore.WHITE + f"{engine}: Rank={rank}, Timestamp={ts_str}")

        # Last DNS records
        dns_records = attributes.get("last_dns_records", [])
        if dns_records:
            print(Fore.CYAN + "\nLast DNS Records:")
            for record in dns_records:
                print(Fore.WHITE + f"{record.get('type')}: {record.get('value')} (TTL: {record.get('ttl')})")

    # ================== File / Hash Info ==================
    if item_type in ["file", "hash"]:
        print(Fore.CYAN + "\n=== File / Hash Info ===")
        print(Fore.WHITE + f"Name: {attributes.get('meaningful_name')}")
        print(Fore.WHITE + f"Size: {attributes.get('size')} bytes")
        print(Fore.WHITE + f"Type: {attributes.get('type_description')} ({attributes.get('type_extension')})")
        print(Fore.WHITE + f"MD5: {attributes.get('md5')}")
        print(Fore.WHITE + f"SHA1: {attributes.get('sha1')}")
        print(Fore.WHITE + f"SHA256: {attributes.get('sha256')}")
        print(Fore.WHITE + f"ssdeep: {attributes.get('ssdeep')}")
        print(Fore.WHITE + f"TLSH: {attributes.get('tlsh')}")
        print(Fore.WHITE + f"Magic: {attributes.get('magic')}")

    # ================== IP Info ==================
    if item_type == "ip":
        print(Fore.CYAN + "\n=== IP Address Info ===")
        print(Fore.WHITE + f"IP: {data.get('data', {}).get('id')}")
        print(Fore.WHITE + f"Network: {attributes.get('network')}")
        print(Fore.WHITE + f"ASN: {attributes.get('asn')}")
        print(Fore.WHITE + f"AS Owner: {attributes.get('as_owner')}")
        print(Fore.WHITE + f"Continent: {attributes.get('continent')}")
        print(Fore.WHITE + f"Country: {attributes.get('country')}")
        print(Fore.WHITE + f"Regional Internet Registry: {attributes.get('regional_internet_registry')}")
        print(Fore.WHITE + f"Reputation: {attributes.get('reputation')}")
        print(Fore.WHITE + f"RDAP URL: {attributes.get('rdap', {}).get('links', [{}])[0].get('href', 'N/A')}")

        # Crowdsourced Context
        crowdsourced = attributes.get("crowdsourced_context", [])
        if crowdsourced:
            print(Fore.CYAN + "\nCrowdsourced Context:")
            for ctx in crowdsourced:
                ts = datetime.fromtimestamp(ctx.get("timestamp"), tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
                print(Fore.WHITE + f"[{ts}] {ctx.get('title')} | Severity: {ctx.get('severity')} | Source: {ctx.get('source')}")
                print(Fore.WHITE + f"Details: {ctx.get('details')}")

        # WHOIS / RDAP summary
        if "whois" in attributes:
            print(Fore.CYAN + "\nWHOIS / RDAP Info:")
            print(Fore.WHITE + attributes.get("whois"))

        # Last HTTPS Certificate info
        if "last_https_certificate" in attributes:
            cert = attributes["last_https_certificate"]
            validity = cert.get("validity", {})
            print(Fore.CYAN + "\nLast HTTPS Certificate:")
            print(Fore.WHITE + f"Subject CN: {cert.get('subject', {}).get('CN')}")
            print(Fore.WHITE + f"Issuer: {cert.get('issuer', {}).get('O')}, CN: {cert.get('issuer', {}).get('CN')}")
            print(Fore.WHITE + f"Valid From: {validity.get('not_before')} To: {validity.get('not_after')}")
            print(Fore.WHITE + f"Thumbprint (SHA256): {cert.get('thumbprint_sha256')}")

    # ================== First Submission Date ==================
    first_submission_date = attributes.get("first_submission_date")
    if first_submission_date:
        first_submission_date_readable = datetime.fromtimestamp(
            first_submission_date, tz=timezone.utc
        ).strftime("%Y-%m-%d %H:%M:%S")
        print(Fore.CYAN + f"\nFirst Submission Date: {first_submission_date_readable}")
    else:
        events = attributes.get("rdap", {}).get("events", [])
        if events:
            first_event = min(events, key=lambda x: x.get("event_date", "9999"))
            print(Fore.CYAN + f"\nFirst Known Event: {first_event.get('event_date')} (RDAP)")
        else:
            print(Fore.YELLOW + "\nFirst Submission Date: Not available for this type of item.")


    # ================== Malicious Status ==================
    malicious = analysis_stats.get("malicious", 0)
    if malicious > 0:
        print(Fore.RED + f"\nItem flagged as malicious. Opening VirusTotal page in 10 seconds...")
        time.sleep(10)
        open_virus_total_gui(item_id, item_type)
    else:
        print(Fore.GREEN + f"\nThe item {item_id} ({item_type}) is not flagged as malicious.")


    # ================== Local Virusscanner  ==================

        
        
def beep():
        os.system('play -nq -t alsa synth 0.1 sine 440')

def clamScan_1D(file):
    try:
        check_OS_Execute(file)
        if not os.path.exists(file):
            print(f"Error: The file or directory '{file}' does not exist.")
        else:  
            print(Fore.YELLOW + "Please wait for the scanner to finish ...")
            Scan_Result = subprocess.run(['clamscan','-r','--remove=yes',file],capture_output=True,text=True)
            print(Fore.MAGENTA + "Results:", Scan_Result.stdout)
            print("Errors", Scan_Result.stderr)

            if Scan_Result.returncode == 0:
                print("\N{grinning face}")
                print(Fore.GREEN + "NO threats detected")
            elif Scan_Result.returncode ==1:
                print(Fore.RED + "Virus found!")
                print(Fore.GREEN + f"{file} was deleted.")
                beep()
            else:
                print(f"Error occurred, {Scan_Result.returncode}")
    except subprocess.CalledProcessError as e:
        print(f"An error occurred while scanning: {e}")
        print("STDOUT:", e.stdout)
        print("STDERR:", e.stderr)
        

def run_scan_and_remove(file_path):
    # Path to mrt.ps1 in the same folder as this Python script
    script_dir = os.path.dirname(os.path.abspath(__file__))
    ps_script = os.path.join(script_dir, "mrt.ps1")

    # Dot-source the script to load the function, then call it
    command = f'''
    . "{ps_script}"
    Run_Scan -filePath "{file_path}"
    '''

    completed = subprocess.run(
        ["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", command],
        capture_output=True,
        text=True
    )

    if completed.returncode == 0:
        print(Fore.GREEN + "Microsoft Defender Antivirus Results:\n")
        print(Fore.MAGENTA + completed.stdout.strip())
    else:
        print("Error:\n", completed.stderr.strip())
    
def check_OS_Execute(file):
    os_name = platform.system()
    if os_name == "Linux":
        clamScan_1D(file)
    elif os_name == "macOS":
        clamScan_1D(file)
    elif os_name == "Windows":
        run_scan_and_remove(file)
    else:
        print(f"{Fore.RED + os_name} is not supported yet.")
