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

def clean_filename(filename, redundant_words):
    """Clean filename according to specified rules (remove numbers, repeated words)."""
    filename = filename.split('：', 1)[-1]
    filename = os.path.splitext(filename)[0]
    words = filename.replace('_', ' ').lower().split()
    if all(part.isdigit() for part in words):
        return ' '.join(words)
    words = [re.sub(r'\d+', ' ', word).strip() for word in words]
    words = ' '.join(words).split()
    unique_words = [w for w in words if w not in redundant_words]
    seen = set()
    cleaned_words = [
        word for word in unique_words
        if len(word) > 2 and not (word in seen or seen.add(word))
    ]
    cleaned_filename = ' '.join(cleaned_words)
    return cleaned_filename if cleaned_filename else "misc_files"

def find_redundant_words(files):
    if not files:
        return []
    common_words = set(files[0].replace('_', ' ').lower().split())
    for file in files[1:]:
        common_words.intersection_update(file.replace('_', ' ').lower().split())
    return list(common_words)

def prepare_groups(files):
    if not files:
        return {}
    sample_filenames = [file.split('：', 1)[-1] for file in files if '：' in file]
    redundant_words = find_redundant_words(sample_filenames)
    groups = defaultdict(list)
    for file in files:
        cleaned_name = clean_filename(file, redundant_words)
        groups[cleaned_name].append(file)
    return groups

def show_folder_contents(event=None):
    """Display files in the selected folder."""
    selection = folder_listbox.curselection()
    if not selection:
        return

    folder_name = folder_listbox.get(selection[0])
    
    parent_prefix = parent_name_entry.get().strip()
    add_prefix = prefix_var.get()
    group_files = group_files_var.get()
    capitalize_names = capitalize_var.get()

    # Modify folder name according to options.
    if add_prefix:
        folder_name = f"{parent_prefix} - {folder_name}"
    if capitalize_names:
        folder_name = ' '.join(
            [word.capitalize() if word.lower() not in {'of', 'is', 'a', 'an'} else word
             for word in folder_name.split()]
        )

    content_listbox.delete(0, tk.END)

    folder_path_full = os.path.join(folder_path, folder_name)
    if os.path.exists(folder_path_full):
        if group_files:
            subfolders = [f for f in os.listdir(folder_path_full) if os.path.isdir(os.path.join(folder_path_full, f))]
            for subfolder in subfolders:
                content_listbox.insert(tk.END, f"Subfolder: {subfolder}")
                subfolder_path = os.path.join(folder_path_full, subfolder)
                subfolder_files = os.listdir(subfolder_path)
                for file in subfolder_files:
                    content_listbox.insert(tk.END, f"  - {file}")
        else:
            files = os.listdir(folder_path_full)
            for file in files:
                content_listbox.insert(tk.END, file)

def load_directory():
    global folder_path
    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_entry.delete(0, tk.END)
    parent_name_entry.insert(0, parent_folder_name)
    try:
        files = os.listdir(folder_path)
        global groups
        groups = prepare_groups(files)
        update_displayed_folders()
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred: {str(e)}")

def apply_options():
    update_displayed_folders()
    show_folder_contents()

def update_displayed_folders():
    parent_prefix = parent_name_entry.get().strip()
    add_prefix = prefix_var.get()
    capitalize_names = capitalize_var.get()
    
    folder_listbox.delete(0, tk.END)
    for folder_name in groups.keys():
        if add_prefix:
            folder_name = f"{parent_prefix} - {folder_name}"
        if capitalize_names:
            folder_name = ' '.join(
                [word.capitalize() if word.lower() not in {'of', 'is', 'a', 'an'} else word
                 for word in folder_name.split()]
            )
        folder_listbox.insert(tk.END, folder_name)

def execute_sorting():
    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_entry.get().strip()
        add_prefix = prefix_var.get()
        group_files = group_files_var.get()
        capitalize_names = capitalize_var.get()
        file_number = int(file_number_entry.get()) if group_files else None
        
        for folder_name, files in groups.items():
            modified_folder_name = folder_name
            if add_prefix:
                modified_folder_name = f"{parent_prefix} - {modified_folder_name}"
            if capitalize_names:
                modified_folder_name = ' '.join(
                    [word.capitalize() if word.lower() not in {'of', 'is', 'a', 'an'} else word
                     for word in modified_folder_name.split()]
                )

            new_folder_path = os.path.join(folder_path, modified_folder_name)
            os.makedirs(new_folder_path, exist_ok=True)
            
            if group_files and file_number:
                index = 0
                for idx, file in enumerate(files):
                    subfolder_index = idx // file_number
                    if idx + file_number >= len(files) and subfolder_index > 0:
                        subfolder_index = 0
                    subfolder_path = os.path.join(new_folder_path, str(subfolder_index + 1))
                    os.makedirs(subfolder_path, exist_ok=True)
                    shutil.move(os.path.join(folder_path, file), os.path.join(subfolder_path, file))
            else:
                for file in files:
                    shutil.move(os.path.join(folder_path, file), os.path.join(new_folder_path, file))

        messagebox.showinfo("Success", "Files sorted and organized successfully!")
        update_displayed_folders()
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred: {str(e)}")

root = tk.Tk()
root.title("File Sorter")

frame = tk.Frame(root)
frame.pack(pady=20, padx=20)

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

parent_name_entry = tk.Entry(frame, width=30)
parent_name_entry.grid(row=0, column=1, padx=10)

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=2, pady=5)

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)

file_number_entry = tk.Entry(frame, width=5)
file_number_entry.insert(0, "5")  # Default for file grouping
file_number_entry.grid(row=2, column=1, sticky='w')

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=2, pady=5)

folder_listbox = tk.Listbox(frame, width=40, height=15)
folder_listbox.grid(row=4, column=0, columnspan=2, pady=5)

content_listbox = tk.Listbox(frame, width=40, height=15)
content_listbox.grid(row=4, column=2, columnspan=2, pady=5)

folder_listbox.bind("<<ListboxSelect>>", show_folder_contents)

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

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

root.mainloop()

I am not able to display the content of the folder when folder is selected from the folder Listbox.