import os, pwd, re, pandas as pd, requests, shutil
from PIL import Image
import urllib
import socks, socket, glob

PURPLE =  '\033[35;40m'
BOLD_PURPLE = '\033[35;40;1m'
ORANGE = '\033[33;40;1m'
RED = '\033[31;40m'
BOLD_RED = '\033[31;40;1m'
RESET = '\033[m'


#### Checking Functions to validate that links are legit ####

def CheckUrl(url):
	"""
	Checks if URL is actually reachable via Tor
	"""
	proxies = {
		'http': 'socks5h://127.0.0.1:9050',
		'https': 'socks5h://127.0.0.1:9050'
	}
	try:
		status = requests.get(url,proxies=proxies, timeout=5).status_code
		#print('[+]',url,status)
		if status != 502:
			#print(url,"✔️")
			return True
		else:
			#print(url,"❌")
			return False
	except requests.ConnectionError as e:
		#print(url,"❌")
		return False
	except requests.exceptions.ReadTimeout as e:
		#print(url,"❌")
		return False

#### PROTECTIONS AGAINST MALICIOUS CSV INPUTS ####

def IsBannerValid(path: str) -> bool:
	"""
	Checks if the banner.png file has the correct dimensions (240x60)
	"""
    #print('[+] checking image size')
	try:
		im = Image.open(path)
	except Exception as e:
		return False
    #im = Image.open("favicon.png")
	width, height = im.size
	#print('width =',width, 'height=',height)
	if width != 240 or height != 60:
		#print('[-] Banner doesnt have the correct size (240x60)')
		return False
	else:
		#print('[+] Banner has the correct size (240x60)')
		return True


def IsOnionValid(url: str)-> bool:
    """
    Checks if the domain(param) is a valid onion domain and return True else False.
    """
        # check if the characters are only [a-zA-Z0-9.] with maximum 128 chars max?
                # check that it is only url.onion or subdomain.url.onion,
                        #  if OK return True
        #if not : return False
    try:
        pattern = re.compile("^[A-Za-z0-9.]+(\.onion)?$")
        url = url.strip().removesuffix('/')
        if url.startswith('http://'):
            #print('URL starts with http')
            # Removes the http://
            domain = url.split('/')[2]
            if pattern.fullmatch(domain) is not None:
                if len(domain.split('.')) > 3:
                    n_subdomians = len(domain.split('.'))
                    # Checks if there is more than 1 subdomain. "subdomain.url.onion" only
                    #print(f"This domain have more than one subdomain. There are {n_subdomians} subdomains")
                    return False
                else:
                    if len(domain) < 62:
                        #print("Domain length is less than 62.")
                        return False
                    return True
            elif pattern.fullmatch(domain) is None:
                #print("Domain contains invalid character.")
                #print(domain)
                return False
            else:
                #print("Domain not valid")
                return False
        else:
			#TODO : edit the url to make sure it has http:// at the beginning, in case if it's missing? (problem is that it only returns true or false)
            #print("URL doesn't start http")
            if pattern.fullmatch(url) is not None:
                if len(url.split('.')) > 3:
                    n_subdomians = len(url.split('.'))
                    # Checks if there is more than 1 subdomain. "subdomain.url.onion" only
                    #print(f"This domain have more than one subdomain. There are {n_subdomians - 1} subdomains")
                    return False
                else:
                    if len(url) < 62:
                        #print("Domain length is less than 62.")
                        return False
                    return True
            elif pattern.fullmatch(url) is None:
                #print("Domain contains invalid character.")
                #print(url)
                return False
            else:
                #print("Domain not valid")
                return False
    except Exception as e:
        print(f"Error: {e}")

def IsUrlValid(url:str)->bool:
        """
        Check if url is valid both dark net end clearnet.
        """
        # check if the characters are only [a-zA-Z0-9.:/] with maximum 128 chars max?
                # check that it is only http(s)://wordA.wordB or http(s)://WordC.WordB.WordC, (onion or not), clearnet is fine too (double check if those are fine!)
                        #  if OK return True
        #if not : return False
        pattern  = re.compile("^[A-Za-z0-9:/.-]+$")
        url = str(url)
        if len(url) < 4:
                #print("Status: Got more than one character or nothing.")
                return False
        if url.endswith('.onion'):
                return IsOnionValid(url)
        else:
                if not url.__contains__('.'):
                        #print("No (DOT) in clearnet url")
                        return False
                if pattern.fullmatch(url) is None:
                        #print('Url contains invalid chars')
                        return False
                return True

def IsStatusValid(status: str)-> bool:
        """
        Checks if status contains only [v,x,❌,✔️]. Verbose only if False is returned
        """
        pattern = ['y','n','✔️','❌','','nan']
        status = str(status)
        status.strip()
        #print('[+] STATUS = ',status.splitlines())
        if len(status) > 4:
                #print("Status: Got more than one character or nothing.")
                return False
        elif (status not in pattern):
                #print("Status: Got an invalid character it must be either y, n, ✔️, or ❌ ")
                return False

        return True


def IsScoreValid(score:str)->bool:
        """
        Check the Score is only "^[0-9.,]+$" with 8 max chars.
        """
        # check if the characters are only [a-zA-Z0-9.,' ] with maximum 256 chars max
                #(careful with the ' and , make sure you test if it fucks the csv up or else)
                #  if OK return True
        #if not : return False
        pattern = re.compile("^[0-9.,]+$")
        score = str(score)
        score.strip()
        #pattern = ['','nan']
        if score in ['','nan']:
            #Score can be empty when initially added
            return True
        if pattern.fullmatch(score) is None:
                # empty description is fine as it's optional
                return False
        elif len(score) > 8:
                #print("score is greater than 8 chars")
                return False
        # empty score is fine
        return True


def IsDescriptionValid(desc:str)->bool:
        """
        Check the categories are only [a-zA-Z0-9.' ] with 256 max chars.
        """
        # check if the characters are only [a-zA-Z0-9.,' ] with maximum 256 chars max
                #(careful with the ' and , make sure you test if it fucks the csv up or else)
                #  if OK return True
        #if not : return False
        if desc == "":
                # empty description is fine as it's optional
                return True
        pattern = re.compile("^[A-Za-z0-9-.,' \"]+$")
        desc = str(desc)
        desc.strip()
        if pattern.fullmatch(desc) is None:
                return False
        if desc == "DEFAULT":
                return False
        elif len(desc) > 256:
                #print("desc is greater than 256 chars")
                return False
        return True

def IsCategoryValid(categories: list)-> bool:
        """
        Check the categories are only [a-zA-Z0-9 ] with 64 max chars.
        """
        # check if the characters are only [a-zA-Z0-9 ] with maximum 64 chars max
                #(careful with the ' and , make sure you test if it fucks the csv up or else)
                #  if OK return True
        #if not : return False
        pattern = re.compile("^[A-Za-z0-9 ]+$")
        for category in categories:
                category.strip()
                if pattern.fullmatch(category) is None:
                        #print('Got an empty list or invalid chars')
                        return False
                elif len(category) > 64:
                        #print('Category is too long')
                        return False
                else:
                       return True

def IsNameValid(name: str)->bool:
        """
        Check the parameter name only contains [a-zA-Z0-9 ] and is 64 chars long.
        """
        # check if the characters are only [a-zA-Z0-9 ] with maximum 64 chars max
                #(careful with the ' and , make sure you test if it fucks the csv up or else)
                #  if OK return True
        #if not : return False
        pattern = re.compile("^[A-Za-z0-9 ]+$")
        name = name.strip()
        if (pattern.fullmatch(name) is None):
                #print("Got an invalid character or nothing")
                return False
        elif len(name) > 64:
                #print(f'Got a name length greater than 64. {len(name)}')
                return False
        return True



#def print_colors(s:str, bold=False, is_error = False, default=False):
def print_colors(*args, bold=False, is_error=False, default=False, highlight=False):
    """
    Helper function to print with colors
    """
    for s in args:
        if is_error:
                print(f"{RED}{s}{RESET}",end='')
        elif highlight:
                print(f"{ORANGE}{s}{RESET}",end='')
        elif bold:
                print(f"{BOLD_PURPLE}{s}{RESET}",end='')
        elif is_error and bold:
                print(f"{BOLD_RED}{s}{RESET}",end='')
        elif default:
                print(f'{s}',end='')
        else:
                print(f"{PURPLE}{s}{RESET}",end='')
        if s is args[-1]:
                print()
			
        
