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)."""
    # 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()
    
    # 4. Remove redundant words/groups of characters.
    unique_words = [w for w in words if w not in redundant_words]
    
    # 5. Remove words that are numeric or less than 3 characters, and remove duplicates
    seen = set()
    cleaned_words = [word for word in unique_words if len(word) > 2 and not any(c.isdigit() for c in word) 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 []
    
    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):
    """Prepare groups of files by cleaned filenames."""
    if not files:
        return {}
    
    # Identify redundant words/groups of characters
    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):
    """Display files in the selected folder."""
    selection = folder_listbox.curselection()
    if not selection:
        return

    folder_name = folder_listbox.get(selection[0])
    files = groups.get(folder_name, [])

    content_listbox.delete(0, tk.END)
    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
    
    try:
        files = os.listdir(folder_path)
        global groups
        groups = prepare_groups(files)
        
        folder_listbox.delete(0, tk.END)
        for folder_name in groups.keys():
            folder_listbox.insert(tk.END, folder_name)
        
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred: {str(e)}")


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:
        for folder_name, files in groups.items():
            new_folder_path = os.path.join(folder_path, folder_name)
            os.makedirs(new_folder_path, exist_ok=True)
            for file in files:
                shutil.move(os.path.join(folder_path, file), os.path.join(new_folder_path, file))

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


# Create a simple GUI
root = tk.Tk()
root.title("File Sorter")

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

folder_listbox = tk.Listbox(frame, width=40, height=20)
folder_listbox.grid(row=0, column=0, padx=10)

content_listbox = tk.Listbox(frame, width=40, height=20)
content_listbox.grid(row=0, column=1, padx=10)

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

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

sort_button = tk.Button(frame, text="Sort and Preview Names", command=load_directory)
sort_button.grid(row=1, column=1, pady=10)

execute_button = tk.Button(frame, text="Execute Sorting", command=execute_sorting)
execute_button.grid(row=2, column=0, columnspan=2, pady=10)

root.mainloop()
What is the procedure order for cleaning the file name?