import os
import shutil
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog
import re
from collections import defaultdict

# Initialize global variables
folder_path = ""
groups = {}
display_to_group_map = {}
pending_renames = {}  # Stores pending renames: {original_group_name: new_group_name}
pending_merges = []    # Stores pending merges: list of group_names to merge into new_group_name
rename_in_progress = False  # Flag to prevent multiple rename operations

def clean_filename(filename, redundant_words):
    """Clean filename according to specified rules (remove numbers, repeated words)."""
    # 1. Ignore text before and including '：'.
    filename = filename.split('：', 1)[-1]

    # 2. Remove file extension.
    filename = os.path.splitext(filename)[0]

    # 3. Replace delimiters with spaces, and transform to lowercase.
    words = filename.replace('_', ' ').lower().split()

    # Check if the entire filename is numeric
    if all(part.isdigit() for part in words):
        return ' '.join(words)

    # 4. Replace numeric groups with spaces
    words = [re.sub(r'\d+', ' ', word).strip() for word in words]

    # Flatten the words split further on spaces
    words = ' '.join(words).split()

    # 5. Remove redundant words/groups of characters.
    unique_words = [w for w in words if w not in redundant_words]

    # 6. Remove words that are less than 3 characters and ensure uniqueness across filename
    seen = set()
    cleaned_words = [word for word in unique_words if len(word) > 2 and not (word in seen or seen.add(word))]

    # Join cleaned words back into a string
    cleaned_filename = ' '.join(cleaned_words)

    # Use a placeholder for files that end up without significant content
    return cleaned_filename if cleaned_filename else "misc_files"

def find_redundant_words(files):
    """Identify groups of characters that appear in all filenames."""
    if not files:
        return []

    # Split filenames on '：' and take the relevant part
    processed_files = [file.split('：', 1)[-1].replace('_', ' ').lower().split() for file in files]

    # Find common words across all processed filenames
    common_words = set(processed_files[0])
    for file_words in processed_files[1:]:
        common_words.intersection_update(file_words)

    redundant_words = list(common_words)
    return redundant_words

def extract_sort_key(filename):
    """
    Extract numerical suffix from the filename for sorting.

    Args:
        filename (str): The filename.

    Returns:
        int: Numerical suffix for sorting.
    """
    # Extract part after 's_' and before file extension
    # Example: 'Ifrete_knit_s_13.jpg' -> 13
    match = re.search(r's_(\d+)', filename.lower())
    if match:
        return int(match.group(1))
    return 0  # Default if pattern not found

def prepare_groups(files, grouping_enabled):
    """Prepare groups of files by cleaned filenames or treat all as one group."""
    if not files:
        return {}

    if grouping_enabled:
        # Identify redundant words/groups of characters
        redundant_words = find_redundant_words(files)

        temp_groups = defaultdict(list)

        for file in files:
            cleaned_name = clean_filename(file, redundant_words)
            temp_groups[cleaned_name].append(file)

        # Sort files within each group based on numerical suffix
        for group in temp_groups:
            temp_groups[group].sort(key=extract_sort_key)

        return temp_groups
    else:
        # Treat all files as a single group named "All Files"
        return {"All Files": files}

def split_into_subgroups(files, file_num):
    """
    Split files into subgroups based on file_num and remaining files rule.

    Args:
        files (list): List of filenames.
        file_num (int): Number of files per subgroup.

    Returns:
        list: List of subgroups (each subgroup is a list of filenames).
    """
    subgroups = []
    total_files = len(files)
    index = 0

    while index < total_files:
        remaining = total_files - index
        # If remaining files are less than twice the file_num and more than file_num, group all remaining
        if remaining <= 2 * file_num and remaining > file_num:
            subgroups.append(files[index:])
            break
        else:
            subgroups.append(files[index:index + file_num])
            index += file_num

    return subgroups

def capitalize_folder_name(folder_name):
    """Capitalize folder name excluding certain short words."""
    short_words = {'of', 'is', 'a', 'an'}
    words = folder_name.split()
    capitalized = [word.capitalize() if word.lower() not in short_words else word for word in words]
    modified_name = ' '.join(capitalized)
    return modified_name

def show_folder_contents(event=None):
    """Display files or subfolders in the selected group (Preview)."""
    try:
        selection = folder_listbox.curselection()
        if not selection:
            content_listbox.delete(0, tk.END)
            return

        folder_display_name = folder_listbox.get(selection[0])
        original_group_name = display_to_group_map.get(folder_display_name, folder_display_name)

        # Clear previous contents
        content_listbox.delete(0, tk.END)

        # Get the list of files in the selected group, considering pending operations
        files_in_group = groups.get(original_group_name, [])

        # Apply pending renames or merges for preview
        preview_files = files_in_group.copy()
        if original_group_name in pending_renames:
            new_group_name = pending_renames[original_group_name]

        if not preview_files:
            content_listbox.insert(tk.END, "No files in this group.")
            return

        if group_files_var.get() and enable_grouping_var.get():
            file_num_str = file_number_var.get().strip()
            if file_num_str:
                try:
                    file_num = int(file_num_str)
                    if file_num <= 0:
                        raise ValueError
                except ValueError:
                    messagebox.showerror("Invalid Input", "Please enter a valid positive integer for file grouping.")
                    content_listbox.delete(0, tk.END)  # Clear contents if invalid input
                    return
                # Calculate subgroups based on the file_num
                subgroups = split_into_subgroups(preview_files, file_num)

                for idx, subgroup in enumerate(subgroups, 1):
                    # Update subfolder naming to include a hyphen separator
                    subfolder_display_name = f"{folder_display_name} - {idx}"
                    content_listbox.insert(tk.END, f"{subfolder_display_name}:")
                    for file in subgroup:
                        content_listbox.insert(tk.END, f"  - {file}")
            else:
                # If file_num is empty, just display the grouped files without further subgroups
                for file in preview_files:
                    content_listbox.insert(tk.END, file)
        elif group_files_var.get() and not enable_grouping_var.get():
            file_num_str = file_number_var.get().strip()
            if file_num_str:
                try:
                    file_num = int(file_num_str)
                    if file_num <= 0:
                        raise ValueError
                except ValueError:
                    messagebox.showerror("Invalid Input", "Please enter a valid positive integer for file grouping.")
                    content_listbox.delete(0, tk.END)  # Clear contents if invalid input
                    return
                # Calculate subgroups based on the file_num
                subgroups = split_into_subgroups(preview_files, file_num)

                for idx, subgroup in enumerate(subgroups, 1):
                    # Use parent folder name as the base for subfolder naming
                    subfolder_display_name = f"{parent_name_var.get().strip()} - {idx}"
                    content_listbox.insert(tk.END, f"{subfolder_display_name}:")
                    for file in subgroup:
                        content_listbox.insert(tk.END, f"  - {file}")
            else:
                # If file_num is empty, just display all files without subgroups
                for file in preview_files:
                    content_listbox.insert(tk.END, file)
        else:
            for file in preview_files:
                content_listbox.insert(tk.END, file)
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred while displaying folder contents:\n{str(e)}")

def load_directory():
    """Load the selected directory, prepare groups, and update the displayed folders."""
    global folder_path, groups, pending_renames, pending_merges
    folder_path = filedialog.askdirectory(title="Select the folder containing your files")
    if not folder_path:
        return
    parent_folder_name = os.path.basename(folder_path)
    parent_name_var.set(parent_folder_name)
    try:
        # Only consider files, ignore subdirectories
        files = [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))]
        groups = prepare_groups(files, enable_grouping_var.get())
        # Reset any pending operations
        pending_renames.clear()
        pending_merges.clear()
        update_displayed_folders()
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred while loading the directory:\n{str(e)}")

def apply_options(*args):
    """Apply the selected options and update the preview."""
    if not folder_path:
        return  # Do nothing if no directory is loaded
    try:
        load_directory_preview()
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred while applying options:\n{str(e)}")

def load_directory_preview():
    """Load the directory and update the display based on the current settings without moving files."""
    global groups
    try:
        # Only consider files, ignore subdirectories
        files = [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))]
        groups = prepare_groups(files, enable_grouping_var.get())
        update_displayed_folders()
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred while updating the preview:\n{str(e)}")

def update_displayed_folders():
    """Update the folder_listbox based on current groups and selected options."""
    global display_to_group_map
    parent_prefix = parent_name_var.get().strip()
    add_prefix = prefix_var.get()
    capitalize_names = capitalize_var.get()

    folder_listbox.delete(0, tk.END)
    display_to_group_map.clear()
    for folder_name in sorted(groups.keys()):
        # Determine the display folder name based on current settings and pending renames
        display_name = folder_name
        if folder_name in pending_renames:
            display_name = pending_renames[folder_name]

        if enable_grouping_var.get():
            # When grouping is enabled
            if folder_name != "All Files":
                if capitalize_names:
                    modified_folder_name = capitalize_folder_name(display_name)
                else:
                    modified_folder_name = display_name

                if add_prefix:
                    if modified_folder_name:
                        # Prefix is added after capitalization
                        modified_folder_name = f"{parent_prefix} - {modified_folder_name}"
                    else:
                        # If group folder name is empty, only prefix
                        modified_folder_name = parent_prefix
                # else, no prefix added
            else:
                # When grouping is enabled but all files are under "All Files"
                # Treat similarly to grouping disabled
                modified_folder_name = parent_prefix
        else:
            # When grouping is disabled
            if add_prefix:
                # Prefix is used as the base name for subfolders
                modified_folder_name = parent_prefix
            else:
                # No prefix; since grouping is disabled, "All Files" is treated as the base
                modified_folder_name = parent_prefix

        folder_listbox.insert(tk.END, modified_folder_name)
        display_to_group_map[modified_folder_name] = folder_name

    # Automatically select the first folder and show its contents
    if folder_listbox.size() > 0:
        folder_listbox.select_set(0)
        show_folder_contents()

def execute_sorting():
    """Execute the sorting: move files into organized folders and subfolders based on selected options."""
    if not folder_path or not groups:
        messagebox.showerror("Error", "No directory loaded or no files grouped. Please load a directory first.")
        return

    try:
        parent_prefix = parent_name_var.get().strip()
        add_prefix = prefix_var.get()
        group_files = group_files_var.get()
        capitalize_names = capitalize_var.get()
        grouping_enabled = enable_grouping_var.get()
        file_num_str = file_number_var.get().strip()

        # Determine file_num only if group_files is enabled and file_num_str is not empty
        if group_files and file_num_str:
            try:
                file_num = int(file_num_str)
                if file_num <= 0:
                    raise ValueError
            except ValueError:
                messagebox.showerror("Invalid Input", "Please enter a valid positive integer for file grouping.")
                return
        else:
            file_num = None  # No grouping by file number

        # Apply pending renames
        for original_group, new_group in pending_renames.items():
            if original_group not in groups:
                continue
            # Update the group name
            groups[new_group] = groups.pop(original_group)

        # Clear pending renames after applying
        pending_renames.clear()

        # Apply pending merges
        for merge_operation in pending_merges:
            group_names = merge_operation['groups']
            new_group_name = merge_operation['new_group']

            if new_group_name in groups:
                # Append to existing group
                merged_files = groups[new_group_name]
            else:
                # Create new group
                merged_files = []
                groups[new_group_name] = merged_files

            for group_name in group_names:
                if group_name not in groups:
                    continue
                merged_files.extend(groups[group_name])
                del groups[group_name]

        # Clear pending merges after applying
        pending_merges.clear()

        for folder_display_name, group_name in display_to_group_map.items():
            files = groups.get(group_name, [])

            if grouping_enabled and group_name != "All Files":
                # Grouping Enabled and multiple groups
                if capitalize_names:
                    base_folder_name = capitalize_folder_name(group_name)
                else:
                    base_folder_name = group_name

                if add_prefix:
                    if base_folder_name:
                        # Prefix is added after capitalization
                        modified_folder_name = f"{parent_prefix} - {base_folder_name}"
                    else:
                        # If group folder name is empty, only prefix
                        modified_folder_name = parent_prefix
                else:
                    modified_folder_name = base_folder_name

                new_folder_path = os.path.join(folder_path, modified_folder_name)

                # Prevent creating a folder with the same name as the parent folder
                if os.path.abspath(new_folder_path) == os.path.abspath(folder_path):
                    messagebox.showerror("Error", f"Cannot create a folder with the same name as the parent folder: {modified_folder_name}")
                    continue

                os.makedirs(new_folder_path, exist_ok=True)

                if group_files and file_num:
                    subgroups = split_into_subgroups(files, file_num)
                    for idx, subgroup in enumerate(subgroups, 1):
                        subfolder_name = f"{modified_folder_name} - {idx}"
                        subfolder_path = os.path.join(new_folder_path, subfolder_name)
                        os.makedirs(subfolder_path, exist_ok=True)
                        for file in subgroup:
                            src = os.path.join(folder_path, file)
                            dest = os.path.join(subfolder_path, file)
                            shutil.move(src, dest)
                else:
                    for file in files:
                        src = os.path.join(folder_path, file)
                        dest = os.path.join(new_folder_path, file)
                        shutil.move(src, dest)

            elif not grouping_enabled and group_name == "All Files":
                # Grouping Disabled: Create subfolders based on file_num directly in the parent directory
                if group_files and file_num:
                    subgroups = split_into_subgroups(files, file_num)
                    for idx, subgroup in enumerate(subgroups, 1):
                        subfolder_name = f"{parent_prefix} - {idx}"
                        subfolder_path = os.path.join(folder_path, subfolder_name)

                        # Prevent creating a folder with the same name as the parent folder
                        if os.path.abspath(subfolder_path) == os.path.abspath(folder_path):
                            messagebox.showerror("Error", f"Cannot create a subfolder with the same name as the parent folder: {subfolder_name}")
                            continue

                        os.makedirs(subfolder_path, exist_ok=True)
                        for file in subgroup:
                            src = os.path.join(folder_path, file)
                            dest = os.path.join(subfolder_path, file)
                            shutil.move(src, dest)
                elif not group_files:
                    # If grouping is disabled and file grouping is not enabled,
                    # and all files are already in the parent folder, do nothing
                    pass
            else:
                # Edge Case: grouping_enabled but only "All Files" group exists
                # Treat it as grouping disabled
                if group_files and file_num:
                    subgroups = split_into_subgroups(files, file_num)
                    for idx, subgroup in enumerate(subgroups, 1):
                        subfolder_name = f"{parent_prefix} - {idx}"
                        subfolder_path = os.path.join(folder_path, subfolder_name)

                        # Prevent creating a folder with the same name as the parent folder
                        if os.path.abspath(subfolder_path) == os.path.abspath(folder_path):
                            messagebox.showerror("Error", f"Cannot create a subfolder with the same name as the parent folder: {subfolder_name}")
                            continue

                        os.makedirs(subfolder_path, exist_ok=True)
                        for file in subgroup:
                            src = os.path.join(folder_path, file)
                            dest = os.path.join(subfolder_path, file)
                            shutil.move(src, dest)
                elif not group_files:
                    # Move all files into a single subfolder named with parent prefix
                    subfolder_name = f"{parent_prefix}"
                    subfolder_path = os.path.join(folder_path, subfolder_name)

                    # Prevent creating a folder with the same name as the parent folder
                    if os.path.abspath(subfolder_path) == os.path.abspath(folder_path):
                        # If the subfolder name is the same as the parent folder, skip creation
                        pass
                    else:
                        os.makedirs(subfolder_path, exist_ok=True)
                        for file in files:
                            src = os.path.join(folder_path, file)
                            dest = os.path.join(subfolder_path, file)
                            shutil.move(src, dest)

        messagebox.showinfo("Success", "Files sorted and organized successfully!")
        load_directory()  # Reload to reflect changes without opening the folder
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred during sorting:\n{str(e)}")

# ---------------------------- New Functions ----------------------------

def rename_selected_folder():
    """Rename the selected folder directly in the listbox."""
    global rename_in_progress
    selected_indices = folder_listbox.curselection()
    if len(selected_indices) != 1:
        messagebox.showinfo("Rename Folder", "Please select exactly one folder to rename.")
        return

    if rename_in_progress:
        messagebox.showinfo("Rename in Progress", "Please complete the current rename operation before starting a new one.")
        return

    rename_in_progress = True

    index = selected_indices[0]
    old_display_name = folder_listbox.get(index)
    original_group_name = display_to_group_map.get(old_display_name, old_display_name)

    # Create an Entry widget overlaying the listbox item
    entry = tk.Entry(frame, width=40)
    entry.insert(0, old_display_name)
    entry.select_range(0, tk.END)
    entry.focus()

    # Get the coordinates of the selected item
    bbox = folder_listbox.bbox(index)
    if bbox:
        entry.place(x=folder_listbox.winfo_x() + bbox[0], y=folder_listbox.winfo_y() + bbox[1], width=bbox[2], height=bbox[3])

    def on_enter(event=None):
        global rename_in_progress
        new_display_name = entry.get().strip()
        if not new_display_name:
            messagebox.showerror("Invalid Name", "Folder name cannot be empty.")
            rename_in_progress = False
            entry.destroy()
            root.unbind("<Button-1>")
            return
        if new_display_name in display_to_group_map and new_display_name != old_display_name:
            messagebox.showerror("Duplicate Name", "A folder with this name already exists.")
            rename_in_progress = False
            entry.destroy()
            root.unbind("<Button-1>")
            return

        # Register the pending rename
        pending_renames[original_group_name] = new_display_name

        # Update the listbox to reflect the pending rename
        folder_listbox.delete(index)
        folder_listbox.insert(index, new_display_name)
        display_to_group_map[new_display_name] = original_group_name
        del display_to_group_map[old_display_name]

        entry.destroy()
        rename_in_progress = False

        # Unbind the <Button-1> event
        root.unbind("<Button-1>")

        # Update the preview to reflect the rename
        show_folder_contents()

    # Bind Enter key to submit the rename
    entry.bind("<Return>", on_enter)

    # Bind clicking anywhere else to submit the rename
    def on_click_anywhere(event):
        widget = event.widget
        if widget != entry:
            on_enter()

    root.bind("<Button-1>", on_click_anywhere)

    # Ensure that clicking outside destroys the entry widget
    def on_focus_out(event):
        on_enter()

    entry.bind("<FocusOut>", on_focus_out)

def merge_selected_folders():
    """Merge the selected folders into a single folder."""
    selected_indices = folder_listbox.curselection()
    if len(selected_indices) < 2:
        messagebox.showinfo("Merge Folders", "Please select two or more folders to merge.")
        return

    selected_display_names = [folder_listbox.get(i) for i in selected_indices]
    selected_group_names = [display_to_group_map.get(name, name) for name in selected_display_names]

    # Suggest the first selected folder's name as default
    default_new_folder_name = selected_display_names[0]
    new_folder_name = simpledialog.askstring("Merge Folders", "Enter the name for the merged folder:", initialvalue=default_new_folder_name)
    if not new_folder_name:
        messagebox.showerror("Invalid Name", "Folder name cannot be empty.")
        return

    # Allow using a name that's among the selected groups being merged
    if (new_folder_name in display_to_group_map and
        display_to_group_map[new_folder_name] not in selected_group_names and
        new_folder_name not in [merge['new_group'] for merge in pending_merges]):
        messagebox.showerror("Duplicate Name", "A folder with this name already exists.")
        return

    # Ensure new_folder_name does not conflict with existing pending merges
    for merge_op in pending_merges:
        if new_folder_name == merge_op['new_group']:
            messagebox.showerror("Duplicate Name", "A pending merge to this name already exists.")
            return

    # Register the pending merge
    pending_merges.append({'groups': selected_group_names, 'new_group': new_folder_name})

    # Update the listbox to reflect the pending merge
    # Remove merged folders from display
    for i in reversed(selected_indices):
        display_name = folder_listbox.get(i)
        folder_listbox.delete(i)
        del display_to_group_map[display_name]

    # Add the new merged folder to the display list
    folder_listbox.insert(tk.END, new_folder_name)
    display_to_group_map[new_folder_name] = new_folder_name

    # Update the preview to reflect the merge
    show_folder_contents()

def create_context_menu(event):
    """Create and display a context menu for the folder listbox."""
    try:
        context_menu = tk.Menu(root, tearoff=0)
        context_menu.add_command(label="Rename", command=rename_selected_folder)

        # Check if multiple selections exist for merging
        selected_indices = folder_listbox.curselection()
        if len(selected_indices) > 1:
            context_menu.add_command(label="Merge Selected Folders", command=merge_selected_folders)
        context_menu.post(event.x_root, event.y_root)
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred while creating the context menu:\n{str(e)}")

# ---------------------------- GUI Setup ----------------------------

# GUI Setup
root = tk.Tk()
root.title("File Sorter")
root.geometry("900x600")  # Increased window size for better layout

frame = tk.Frame(root)
frame.pack(pady=20, padx=20, fill=tk.BOTH, expand=True)

# Parent Folder Name
parent_name_label = tk.Label(frame, text="Parent Folder Name:")
parent_name_label.grid(row=0, column=0, padx=10, sticky='e')

parent_name_var = tk.StringVar()
parent_name_entry = tk.Entry(frame, width=30, textvariable=parent_name_var)
parent_name_entry.grid(row=0, column=1, padx=10, sticky='w')
parent_name_var.trace_add('write', lambda *args: apply_options())

# Add Prefix Checkbox
prefix_var = tk.IntVar()
prefix_check = tk.Checkbutton(frame, text="Add Parent Name Prefix", variable=prefix_var, command=apply_options)
prefix_check.grid(row=1, column=0, columnspan=4, pady=5, sticky='w')

# Group Files Checkbox and Entry
group_files_var = tk.IntVar()
group_files_check = tk.Checkbutton(frame, text="Group by file number:", variable=group_files_var, command=apply_options)
group_files_check.grid(row=2, column=0, sticky='e')

file_number_label = tk.Label(frame, text="Files per subfolder:")
file_number_label.grid(row=2, column=2, padx=10, sticky='e')

file_number_var = tk.StringVar(value="30")  # Default for file grouping
file_number_entry = tk.Entry(frame, width=5, textvariable=file_number_var)
file_number_entry.grid(row=2, column=3, sticky='w', padx=(0,10))
file_number_var.trace_add('write', lambda *args: apply_options())

# Capitalize Names Checkbox
capitalize_var = tk.IntVar()
capitalize_check = tk.Checkbutton(frame, text="Capitalize Folder Names", variable=capitalize_var, command=apply_options)
capitalize_check.grid(row=3, column=0, columnspan=4, pady=5, sticky='w')

# Folder Listbox (Preview) Header with New Checkbox
folder_listbox_header_frame = tk.Frame(frame)
folder_listbox_header_frame.grid(row=4, column=0, columnspan=4, sticky='w', pady=(10,0))

enable_grouping_var = tk.IntVar(value=1)  # New variable for grouping toggle
enable_grouping_check = tk.Checkbutton(
    folder_listbox_header_frame,
    text="Enable Folder Grouping",
    variable=enable_grouping_var,
    command=apply_options
)
enable_grouping_check.pack(side='left')

folder_listbox_label = tk.Label(folder_listbox_header_frame, text="Grouped Folders (Preview):")
folder_listbox_label.pack(side='left', padx=(10,0))

# Updated Listbox with multiple selection and double-click enabled
folder_listbox = tk.Listbox(frame, width=40, height=15, exportselection=False, selectmode=tk.EXTENDED)
folder_listbox.grid(row=5, column=0, columnspan=2, pady=5, sticky='nsew')
folder_listbox.bind("<<ListboxSelect>>", show_folder_contents)
folder_listbox.bind("<Double-Button-1>", lambda event: rename_selected_folder())  # Double-click to rename

# Bind right-click for context menu
folder_listbox.bind("<Button-3>", create_context_menu)  # Right-click on Windows
folder_listbox.bind("<Button-2>", create_context_menu)  # Right-click on macOS

# Make the Listbox expand with the window
frame.grid_rowconfigure(5, weight=1)
frame.grid_columnconfigure(1, weight=1)

# Content Listbox (Preview)
content_listbox_label = tk.Label(frame, text="Folder Contents (Preview):")
content_listbox_label.grid(row=4, column=2, columnspan=2, pady=(10,0))

content_listbox = tk.Listbox(frame, width=40, height=15, exportselection=False)
content_listbox.grid(row=5, column=2, columnspan=2, pady=5, sticky='nsew')

# Make the Content Listbox expand with the window
frame.grid_columnconfigure(3, weight=1)

# Browse and Execute Buttons
browse_button = tk.Button(frame, text="Browse Directory", command=load_directory)
browse_button.grid(row=6, column=0, pady=10, sticky='w')

execute_button = tk.Button(frame, text="Execute Sorting", command=execute_sorting)
execute_button.grid(row=6, column=3, pady=10, sticky='e')

root.mainloop()

When I merge all the folder into one using the default name, which is first on the folder list, only previous content from this folder is shown.  When any of the checkbox option is selected, all the merged folders will reappear. Please help me fix it.