import os
import subprocess
import json
import customtkinter as ctk
from tkinter import filedialog, messagebox

ctk.set_appearance_mode("System")
ctk.set_default_color_theme("blue")
# Initialize global variables
game_folder = None

# Create the customtkinter window
app = ctk.CTk()
app.title("Firefly HDiff Tool")
app.geometry("335x470")
app.resizable(False, False)
current_dir = os.path.dirname(os.path.abspath(__file__))
app.iconbitmap(os.path.join(current_dir, 'image.ico'))
app.grid_columnconfigure((0), weight=1)

# Set appearance mode and theme


# Main frame for better organization
main_frame = ctk.CTkFrame(app)
main_frame.pack(fill=ctk.BOTH, expand=True)

# Folder selection button with modern style
folder_button = ctk.CTkButton(main_frame, text="Select Game Folder", command=lambda: select_folder(), width=300, anchor='center')
folder_button.grid(row=0, column=0, padx=20, pady=20, sticky="ew", columnspan=10)

# Folder label to display selected folder
folder_label = ctk.CTkLabel(main_frame, text="No folder selected", width=200, anchor="center", text_color="gray")
folder_label.grid(row=1, column=0, padx=20, pady=20, sticky="ew", columnspan=2)

# Apply Patch button with modern style
apply_button = ctk.CTkButton(main_frame, text="Apply Patch", command=lambda: apply_patch_action(), state=ctk.DISABLED, width=300, anchor='center')
apply_button.grid(row=2, column=0, padx=10, pady=10)

# Output text area with scroll functionality
output_frame = ctk.CTkFrame(main_frame, width=300)
output_frame.grid(row=3, column=0, padx=10, pady=5)

output_text = ctk.CTkTextbox(output_frame, height=8, width=300)
output_text.grid(row=0, column=0, sticky="nsew")

# Scrollbar for the text area
scrollbar = ctk.CTkScrollbar(output_frame, command=output_text.yview)
scrollbar.grid(row=0, column=1, sticky="ns")

output_text.configure(yscrollcommand=scrollbar.set, state=ctk.DISABLED)

# Progress bar
progress_label = ctk.CTkLabel(main_frame, text="Progress", width=300, anchor='center')
progress_label.grid(row=4, column=0, padx=10)

progress_bar = ctk.CTkProgressBar(main_frame, orientation="horizontal")
progress_bar.grid(row=5, column=0, pady=10)
progress_bar.set(0)

def select_folder():
    """Select a folder to set as the game folder."""
    global game_folder
    folder_path = filedialog.askdirectory()
    if folder_path:
        game_folder = folder_path
        folder_label.configure(text=f"Selected Folder: {folder_path}")
        apply_button.configure(state=ctk.NORMAL)
    else:
        messagebox.showwarning("Warning", "No folder selected.")
        apply_button.configure(state=ctk.DISABLED)

def apply_patch_action():
    """Apply patch to the selected game folder."""
    if not game_folder:
        messagebox.showwarning("Warning", "Please select a game folder!")
        return
    apply_patch(game_folder)

def apply_patch(game_folder):
    """Main function to apply patch based on selected folder."""
    folder_button.configure(state=ctk.DISABLED)
    delete_files_path = os.path.join(game_folder, 'deletefiles.txt')
    if not os.path.exists(delete_files_path):
        folder_button.configure(state=ctk.NORMAL)
        log_output('deletefiles.txt does not exist in the game directory!')
        return

    hdiff_map_path = os.path.join(game_folder, 'hdiffmap.json')
    if not os.path.exists(hdiff_map_path):
        folder_button.configure(state=ctk.NORMAL)
        log_output('hdiffmap.json does not exist in the game directory!')
        return

    # Read deletefiles.txt and delete the specified files
    with open(delete_files_path, 'r') as delete_files:
        for file in delete_files.read().split('\n'):
            if len(file) < 1:
                continue
            file_path = os.path.join(game_folder, file)
            if os.path.exists(file_path):
                log_output(f'Deleting {file_path}')
                os.remove(file_path)

    # Check if hpatchz is available in the system path
    hzpatchz = os.path.join(current_dir, 'hpatchz.exe')
    if not os.path.exists(hzpatchz):
        folder_button.configure(state=ctk.NORMAL)
        log_output(f"HDiffPatch not found in the current directory ({current_dir})!\nPlease make sure hpatchz.exe is in the same folder as the script.")
        return

    # Read hdiffmap.json
    with open(hdiff_map_path, 'r') as hdiff_json:
        data = json.load(hdiff_json)

    total_patches = len(data['diff_map'])
    progress_bar.set(0)

    # Apply patches
    for i, entry in enumerate(data['diff_map']):
        source_file_name = os.path.join(game_folder, entry['source_file_name'])
        patch_file_name = os.path.join(game_folder, entry['patch_file_name'])
        target_file_name = os.path.join(game_folder, entry['target_file_name'])

        # Check if files exist
        if not os.path.exists(source_file_name):
            log_output(f"Source file missing: {source_file_name}")
            continue
        if not os.path.exists(patch_file_name):
            log_output(f"Patch file missing: {patch_file_name}")
            continue

        log_output(f"Applying patch: {patch_file_name} -> {target_file_name} using {source_file_name}")
        subprocess.run([hzpatchz, source_file_name, patch_file_name, target_file_name])

        # Update progress bar
        progress_percentage = float((i + 1) / total_patches)
        progress_bar.set(progress_percentage)
        app.update_idletasks()

    log_output("Patch application complete.")

    folder_button.configure(state=ctk.NORMAL)

def log_output(message):
    """Log the output in the Text widget."""
    output_text.configure(state=ctk.NORMAL)
    output_text.insert(ctk.END, message + "\n\n")
    output_text.yview(ctk.END)
    output_text.configure(state=ctk.DISABLED)

app.mainloop()
