import tkinter as tk
from tkinter import filedialog, colorchooser, messagebox
from PIL import Image
import openpyxl
from openpyxl.styles import PatternFill
from openpyxl.utils import get_column_letter

# Function to convert an RGB value into an Excel fill color
def rgb_to_fill(rgb):
    return PatternFill(start_color=rgb, end_color=rgb, fill_type='solid')

# Function to map image colors to a predefined palette
def map_colors(img, palette):
    # Convert the image to RGB if it's not already in RGB mode
    img = img.convert('RGB')
    
    # Create a new image with the same size as the original to apply the palette mapping
    new_img = Image.new('RGB', img.size)
    
    for x in range(img.size[0]):
        for y in range(img.size[1]):
            # Get the current pixel color
            current_color = img.getpixel((x, y))
            # Find the nearest color from the palette
            nearest_color = min(palette, key=lambda color: sum((s - q) ** 2 for s, q in zip(color, current_color)))
            # Set the pixel to the nearest color
            new_img.putpixel((x, y), nearest_color)
    
    return new_img

# GUI Functions
def upload_image():
    global img_path
    img_path = filedialog.askopenfilename(filetypes=[("Image files", "*.jpg *.jpeg *.png")])
    if img_path:
        image_label.config(text="Image Loaded: " + img_path.split('/')[-1])

def choose_color(entry_widget):
    color_code = colorchooser.askcolor(title="Choose color")
    if color_code[1]:
        entry_widget.delete(0, tk.END)
        entry_widget.insert(0, color_code[1])

def add_color_entry():
    color_entry = tk.Entry(frame, width=7)
    color_entry.pack(side=tk.LEFT)
    color_picker_btn = tk.Button(frame, text="Choose Color", command=lambda: choose_color(color_entry))
    color_picker_btn.pack(side=tk.LEFT)
    color_entries.append(color_entry)

def generate_pixel_art():
    try:
        # Retrieve the selected colors and dimensions from the GUI
        color_entries_hex = [entry.get() for entry in color_entries if entry.get() != '']
        colors_rgb = [tuple(int(hex_color[i:i+2], 16) for i in (1, 3, 5)) for hex_color in color_entries_hex]

        # Load and process the image, ensuring no alpha channel
        img = Image.open(img_path).convert('RGB')
        max_size = (int(width_entry.get()), int(height_entry.get()))
        img = img.resize(max_size, Image.Resampling.NEAREST)
        img_mapped = map_colors(img, colors_rgb)

        # Create a new Excel workbook for the color-mapped pixel art
        wb_mapped_palette = openpyxl.Workbook()
        complete_sheet = wb_mapped_palette.active
        complete_sheet.title = "Complete Image"

        # Fill in the complete image sheet with all layers combined
        for x in range(1, img_mapped.size[0] + 1):
            for y in range(1, img_mapped.size[1] + 1):
                pixel = img_mapped.getpixel((x - 1, y - 1))
                hex_color = ''.join([f'{value:02X}' for value in pixel])
                cell = complete_sheet.cell(row=y, column=x)
                cell.fill = rgb_to_fill(hex_color)
                complete_sheet.column_dimensions[get_column_letter(x)].width = 3
                complete_sheet.row_dimensions[y].height = 20

        # Generate a layer for each color
        for color in colors_rgb:
            hex_color = ''.join([f'{value:02X}' for value in color])
            ws = wb_mapped_palette.create_sheet(title=hex_color)
            for x in range(1, img_mapped.size[0] + 1):
                for y in range(1, img_mapped.size[1] + 1):
                    pixel = img_mapped.getpixel((x - 1, y - 1))
                    if pixel == color:  # Only fill the cell if it matches the layer's color
                        cell = ws.cell(row=y, column=x)
                        cell.fill = rgb_to_fill(hex_color)
                    ws.column_dimensions[get_column_letter(x)].width = 3
                    ws.row_dimensions[y].height = 20
        
        # Save the color-mapped Excel file
        output_file_path_mapped_palette = filedialog.asksaveasfilename(defaultextension=".xlsx",
                                                                      filetypes=[("Excel files", "*.xlsx")])
        if output_file_path_mapped_palette:
            wb_mapped_palette.save(output_file_path_mapped_palette)
            messagebox.showinfo("Success", "Pixel Art saved as " + output_file_path_mapped_palette)
    except Exception as e:
        messagebox.showerror("Error", str(e))

# Set up the main application window
app = tk.Tk()
app.title("Pixel Art Generator")

# Layout
frame = tk.Frame(app)
frame.pack(padx=10, pady=10)

image_label = tk.Label(frame, text="No image selected")
image_label.pack()

upload_btn = tk.Button(frame, text="Upload Image", command=upload_image)
upload_btn.pack()

# List to store color entry widgets
color_entries = []

# Add default three color entries
for _ in range(3):
    add_color_entry()

# Button to add more color entries
add_color_btn = tk.Button(frame, text="Add Another Color", command=add_color_entry)
add_color_btn.pack()

# Entry for dimensions
width_label = tk.Label(frame, text="Width:")
width_label.pack(side=tk.LEFT)
width_entry = tk.Entry(frame, width=5)
width_entry.pack(side=tk.LEFT)
width_entry.insert(0, "50")  # Default value

height_label = tk.Label(frame, text="Height:")
height_label.pack(side=tk.LEFT)
height_entry = tk.Entry(frame, width=5)
height_entry.pack(side=tk.LEFT)
height_entry.insert(0, "50")  # Default value

# Button to generate pixel art
generate_btn = tk.Button(frame, text="Generate Pixel Art", command=generate_pixel_art)
generate_btn.pack()

app.mainloop()