import os
import zipfile
import time

def create_dummyvar(source_path, dest):

    # Extract basename from source file (without extension)
    base_name = os.path.splitext(os.path.basename(source_path))[0]

    # New path of new var in destination directory
    new_zip_path = os.path.join(dest, 'dummyvars', f'{base_name}.var')

    # Create dirs if not exist
    os.makedirs(os.path.dirname(new_zip_path), exist_ok=True)

    # Create new dummy var file
    with zipfile.ZipFile(new_zip_path, 'w') as dest_zip:
        # Open source var for extracting meta.json
        with zipfile.ZipFile(source_path, 'r') as source_zip:
            if 'meta.json' in source_zip.namelist():
                # Copy meta.json file to new dummy var file
                dest_zip.writestr('meta.json', source_zip.read('meta.json'))
            else:
                raise FileNotFoundError("File meta.json not found in var file.")

    return f'Dummyvar created on{new_zip_path}'


def unpack_files(source_dict: dict, vam_dir, dummy_dest, unzip_list, set_status, dummyvar=True):

    for file_name in unzip_list:
        found_source_path = source_dict.get(file_name+'.var')[0][0]

        if not found_source_path:
            set_status(f'{file_name} not found.')
            continue

        if dummyvar: set_status(create_dummyvar(found_source_path, dummy_dest))

        try:
            with zipfile.ZipFile(found_source_path, 'r') as zip_ref:
                # Extract only files from 'Custom' tree
                for member in zip_ref.namelist():
                    if 'Custom' in member:
                        # Convert var path to OS compatible
                        member_path = os.path.normpath(member)
                        # Construct full path in vam_dir
                        destination_path = os.path.join(vam_dir, os.path.dirname(member_path))
                        if not os.path.exists(destination_path):
                            os.makedirs(destination_path)

                        # Destination path
                        full_destination = os.path.join(destination_path, os.path.basename(member_path))
                        
                        # Skip file if exists and is more recent than var's
                        if os.path.exists(full_destination):
                            zip_info = zip_ref.getinfo(member)
                            zip_mtime = zip_info.date_time
                            existing_mtime = os.path.getmtime(full_destination)
                            
                            # Convert to timestamp for comparing
                            zip_timestamp = (zip_mtime[0], zip_mtime[1], zip_mtime[2])
                            existing_timestamp = time.gmtime(existing_mtime)[:3]
                            
                            if zip_timestamp <= existing_timestamp:
                                continue  # If file is same date or more recent, skip
                        
                        zip_ref.extract(member, vam_dir)
            
            set_status(f"{file_name} unpacked")
        except Exception as e:
            set_status(f"Error unpacking {file_name}: {str(e)}")
    
    set_status("Unpacking complete.")


def delete_dummyvar(file, dest) -> str:
    # Construct full path of .var file to delete
    var_file_path = os.path.join(dest, 'dummyvars', file)
    try:
        # Try deleting file
        if os.path.exists(var_file_path):
            os.remove(var_file_path)
            return f'Dummyvar {var_file_path} deleted'
        else:
            return f'Dummyvar {var_file_path} not found.'
    except Exception as e:
        return f'Could not delete dummyvar {var_file_path}: {e}'


def delete_unpacked_vars(pkgdict: dict, vam_dir: str, vam_addons: str, file_list: str, set_status, dummyvar=True):

    for filename in file_list:
        # Find file in pkgdict
        filename += '.var'
        if filename in pkgdict:
            locations = pkgdict[filename][0] # Only the list, not level

            if dummyvar: set_status(delete_dummyvar(filename, vam_addons))

            # Filter locations not containing 'dummyvars' in their path
            valid_locations = [loc for loc in locations if 'dummyvars' not in loc]

            if valid_locations:
                # Take first valid location
                zip_path = valid_locations[0]
                
                # Make sure file exists
                if os.path.exists(zip_path):

                    with zipfile.ZipFile(zip_path, 'r') as z:
                        # Get a list of all elements in /Custom tree
                        custom_files = [name for name in z.namelist() if name.startswith('Custom/')]
                        for file in reversed(custom_files):
                            # Construct full path in vam_dir
                            full_path = os.path.join(vam_dir, file)
                            if os.path.exists(full_path):
                                try:
                                    # If it is a file, delete it
                                    if os.path.isfile(full_path):
                                        os.remove(full_path)
                                        set_status(f'File deleted: {full_path}')
                                    
                                    # If it is an empty directory, try deleting
                                    elif os.path.isdir(full_path) and not os.listdir(full_path):
                                        os.rmdir(full_path)
                                        set_status(f'Empty directory deleted: {full_path}')
                                except Exception as e:
                                    set_status(f'Error deleting {full_path}: {e}')
                else:
                    set_status(f'File not found on previously scanned location: {zip_path}')
            else:
                set_status(f'Not found valid locations for {filename}.')
        else:
            set_status(f'{filename} not found in last refreshed list.')


def find_unpacked_vars(pkgdict: dict, vam_dir: str, dest: str, set_status, dummyvar=True) -> list:

    found_keys = []
    tags = ('Clothing', 'Hair', 'Assets') # To save some time scanning, only scan when those tags are (not) found
    set_status('Scanning files. Please wait, this could take some time...')    

    # Prepare the json counter
    total_files = len([zip_files for zip_files, data in pkgdict.items()]) #if data[1] == '3'])  # packages dict format:  'filename' : [ [filepath1, filepath2, ...], level ]
    set_status(f'Processing {total_files} files. Please wait...')

    # percent counter
    percent_t = total_files * 0.01
    percent = 0
    n = 0
    for key, (zip_files, level) in pkgdict.items():
        # Print package processing information
        n += 1
        if (n + 1) >= (percent + 1) * percent_t:
            percent += 1
            set_status(f'Processing packages... {percent}%')

        if level == 3:
            first_zip_file = zip_files[0]
            with zipfile.ZipFile(first_zip_file, 'r') as z:
                for tag in tags:
                    custom_path = f'Custom/{tag}'

                    # Verify Custom/tag path existence in var
                    if any(name.startswith('Saves') for name in z.namelist()):  # 'Saves' implies scenes and scenes will be not unpackable.
                        all_files_exist = False
                        break

                    # Verify Custom/tag path existence in var
                    if any(name.startswith(custom_path) for name in z.namelist()):  # code warning:  maybe try with 'Custom' to check files outside Clothing and Hair, if necessary
                        all_files_exist = True
                        
                        # Verify if all files on this path exist in vam_dir
                        for file_info in z.infolist():
                            if file_info.filename.startswith(custom_path):
                                relative_path = os.path.relpath(file_info.filename, 'Custom')
                                full_path_in_vam = os.path.join(vam_dir, 'Custom', relative_path)
                                
                                if not os.path.exists(full_path_in_vam):
                                    all_files_exist = False
                                    break
                        
                        if all_files_exist:
                            if dummyvar: create_dummyvar(first_zip_file, dest)  # code warning: I preferred not doing set_message with each return str. Interface messages slow down the whole process.
                            keyname, _ = key.rsplit('.',1)
                            found_keys.append(keyname)
    return found_keys

