import os
import re

# Function for getting a dictionary with all valid packges in a directory. To be called with 'level' values 1 (installed), 2 (available), 3 (external). It associates given level only to new dictionary entries.
def add_var_paths(level, source_path, packages: dict, badnames):
    # Find all files (with optional extension) in a directory tree and return their paths
    for root, _, files in os.walk(source_path):
        for file in files:
            # get only vars
            if str(file).endswith('.var'):
                fullpath = os.path.join(root, file)
                # check valid var file format
                if re.match(r'^[^\.]+\.[^\.]+\.\d+\.var$', file):
                    if file not in packages:  # if new, define a empty list as value for dictionary entry 'file', and set level
                        packages[file] = [[],level] # index [0] list, index [1] level
                    packages[file][0].append(fullpath) # new or not, append to list, not touching level
                else: 
                    badnames.append(fullpath)


def find_in_all_packages(name, packages: dict, set_status):
        base_name, version = name.rsplit('.', 1)
        # For dependencies requiring exact version
        if version.isdigit():
            if name + '.var' in packages:
                return name + '.var'

        # Find .var files in the dictionary, matching base name
        matching_keys = [(key, int(key.rstrip('.var').rsplit('.',1)[1])) for key, (paths, level) in packages.items() if key.startswith(base_name+'.')] 
        # Get the highest version available
        if matching_keys:
            latest_key = max(matching_keys, key=lambda x: x[1])[0]
        else:
            return None

        # For dependencies requiring latest version, go on
        if version == 'latest':
            pass
        # For dependencies requiring minimum version, check with latest var file
        elif version.startswith('min'):
            min_version_str = version[3:]
            if not min_version_str.isdigit():
                set_status(f"Min version '{min_version_str}' is not valid for '{name}'.")
                return None
            min_version = int(min_version_str)
            # Check if latest key meets minimum version requirement
            if not int(latest_key.rstrip('.var').rsplit('.',1)[1]) >= min_version:
                set_status(f"No files found for '{name}' (min {min_version}).")
                return None
        else:
            set_status(f"Version '{version}' not recognized for '{name}'.")
            return None
        return latest_key


# Find var names from file_name_list tuple in packages dictionary, returns full_path_list tuple (path, level)
def find_var_paths(name_list:list, packages:dict, set_status) -> list:
    # self.set_status("Finding packages meeting deps' requirements...")
    full_path_list = []
    for name in name_list:
        var_name=find_in_all_packages(name, packages, set_status)
        if var_name:
            # Append the path corresponding to var name
            full_path_list.append([packages.get(var_name)[0][0], packages.get(var_name)[1]])
    return full_path_list


def find_var_names(name_list:list, packages:dict, set_status) -> list:
    # self.set_status("Finding packages meeting deps' requirements...")
    var_list = []
    for name in name_list:
        var_name=find_in_all_packages(name, packages, set_status)
        if var_name:
            # Append the path corresponding to var name
            var_list.append(var_name.rstrip('.var'))
    return var_list


"""
# AppPackages class
class PackagesCollection():
    def __init__(self):
        self.packages= {}
        self.bad_ones = []

    def reset(self):
        self.packages= {}
        self.bad_ones = []

    # def get(self):
        # return self.packages
    
    def add_path(self, level, source_path):
        # Find all files (with optional extension) in a directory tree and return their paths
        for root, _, files in os.walk(source_path):
            for file in files:
                # get only vars
                if str(file).endswith('.var'):
                    fullpath = os.path.join(root, file)
                    # check valid var file format
                    if re.match(r'^[^\.]+\.[^\.]+\.\d+\.var$', file):
                        if file not in self.packages:  # if new, define a empty list as value for dictionary entry 'file', and set level
                            self.packages[file] = [[],level] # index [0] list, index [1] level
                        self.packages[file][0].append(fullpath) # new or not, append to list, not touching level
                    else: 
                        self.bad_ones.append(fullpath)

    def get_bad_ones(self):
        return self.bad_ones
    
    def get_dupes(self) -> dict:
        # Iterates for duplicate filenames in and between two lists.
        # Returns a filtered list with duplicates by name
        dupes = {}
        # Check for duplicate filenames in dir
        for filename, paths in self.packages.items():
            if len(paths[0]) > 1: # and paths[1] < 3: # level 1 or 2  not needed if dedupe before level 3 scan
                dupes[filename] = (paths[0])
        return dupes

    def get_key(self, name):
            base_name, version = name.rsplit('.', 1)
            # For dependencies requiring exact version
            if version.isdigit():
                if name + '.var' in self.packages:
                    return name + '.var'

            # Find .var files in the dictionary, matching base name
            matching_keys = [key for key, (paths, level) in self.packages.items() if key.startswith(base_name+'.')] 
            print(matching_keys)
            if matching_keys:
                latest_key = max(matching_keys)

            # For dependencies requiring latest version, use latest var file
            if version == 'latest':
                if not matching_keys:
                    self.set_status(f"No files found for '{name}' (latest).")
                    return None

            # For dependencies requiring minimum version, check with latest var file
            elif version.startswith('min'):
                min_version_str = version[3:]
                if not min_version_str.isdigit():
                    self.set_status(f"Min version '{min_version_str}' is not valid for '{name}'.")
                    return None
                min_version = int(min_version_str)
                # Check if latest key meets minimum version requirement
                if not int(latest_key.rstrip('.var').rsplit('.',1)[1]) >= min_version:
                    self.set_status(f"No files found for '{name}' (min {min_version}).")
                    return None
            else:
                self.set_status(f"Version '{version}' not recognized for '{name}'.")
            return latest_key + '.var'
"""