import tkinter as tk
from tkinter import ttk, filedialog
import random, string, json

from PIL import Image, ImageDraw, ImageFont
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas as pdf_canvas
# from docx import Document

wnd = tk.Tk()
wnd.geometry("850x550")
wnd.title("WordSrch")
wnd.configure(bg="#0A1128")

main = tk.Frame(wnd, bg="#0A1128")
welcome_frame = tk.Frame(wnd, bg="#0A1128")
main.pack(fill="both", expand=True)

cvs = None
w_sz = h_sz = diff = 0
grid = []
reds = []
words = []
word_boxes = []

def load_stuff():
    global words, w_sz, h_sz, diff
    try:
        with open("settings.json", "r") as f:
            d = json.load(f)
            words = d["wordlist"]
            w_sz = d["x_size"]
            h_sz = d["y_size"]
            diff = d["level"]
    except:
        words, w_sz, h_sz, diff = [], 10, 10, 1

def save_stuff(x_ent, y_ent, lv_var):
    j = {
        "wordlist": [e.get() for e in word_boxes if e.get().strip()],
        "x_size": int(x_ent.get()),
        "y_size": int(y_ent.get()),
        "level": int(lv_var.get())
    }
    with open("settings.json", "w") as f:
        json.dump(j, f, indent=2)
    load_stuff()

def mk_grid():
    global grid, reds
    grid = [["" for _ in range(w_sz)] for _ in range(h_sz)]
    reds = []
    dirs = [(1, 0)]
    if diff > 1: dirs.append((0, 1))
    if diff > 2: dirs.append((1, 1))

    for wd in words:
        wd = wd.upper()
        done = False
        tries = 0
        while not done and tries < 200:
            dx, dy = random.choice(dirs)
            sx = random.randint(0, w_sz - (len(wd) if dx else 1))
            sy = random.randint(0, h_sz - (len(wd) if dy else 1))

            ok = True
            for i, ch in enumerate(wd):
                cx, cy = sx + i * dx, sy + i * dy
                cell = grid[cy][cx]
                if cell not in ("", ch):
                    ok = False
                    break

            if ok:
                overlap_ok = True
                for i, ch in enumerate(wd):
                    cx, cy = sx + i * dx, sy + i * dy
                    if grid[cy][cx] == ch and random.random() > 0.8:
                        continue
                    elif grid[cy][cx] == "":
                        continue
                    elif grid[cy][cx] != ch:
                        overlap_ok = False
                        break
                if not overlap_ok:
                    tries += 1
                    continue

                for i, ch in enumerate(wd):
                    cx, cy = sx + i * dx, sy + i * dy
                    grid[cy][cx] = ch
                    reds.append((cy, cx))
                done = True
            tries += 1

    for r in range(h_sz):
        for c in range(w_sz):
            if grid[r][c] == "":
                grid[r][c] = random.choice(string.ascii_uppercase)


def draw():
    cvs.delete("all")
    cw = 500 / w_sz
    ch = 500 / h_sz
    for r in range(h_sz):
        for c in range(w_sz):
            col = "red" if (r, c) in reds else "black"
            cvs.create_text(c*cw+cw/2, r*ch+ch/2, text=grid[r][c], font=("Arial", 16), fill=col)
    for i in range(w_sz+1):
        cvs.create_line(i*cw, 0, i*cw, 500)
    for j in range(h_sz+1):
        cvs.create_line(0, j*ch, 500, j*ch)

def show_frame(frame):
    for child in wnd.winfo_children():
        child.pack_forget()
    frame.pack(fill="both", expand=True)

def welcome_page():
    for w in welcome_frame.winfo_children():
        w.destroy()

    lbl = tk.Label(welcome_frame, text="Welcome to WordSrch!", font=("Arial", 24), bg="#0A1128", fg="#FEFCFB")
    lbl.pack(pady=50)

    btns = tk.Frame(welcome_frame, bg="#0A1128")
    btns.pack(pady=20)

    def start_new():
        show_frame(main)

    def load_project():
        file_path = filedialog.askopenfilename(filetypes=[("JSON Files", "*.json")])
        if not file_path:
            return
        try:
            with open(file_path, "r") as f:
                data = json.load(f)
                with open("settings.json", "w") as out:
                    json.dump(data, out, indent=2)
            load_stuff()
            show_frame(main)
            gui()
        except:
            print("Failed to load project.")

    tk.Button(btns, text="Load Project", font=("Arial", 14), width=15, bg="#034078", fg="#FEFCFB", activebackground="#1282A2").pack(side="left", padx=10)
    tk.Button(btns, text="New Project", font=("Arial", 14), width=15, bg="#034078", fg="#FEFCFB", activebackground="#1282A2", command=start_new).pack(side="left", padx=10)

def gui():
    global cvs, word_boxes
    for w in main.winfo_children():
        w.destroy()
    main.configure(bg="#0A1128")

    tk.Label(main, text="Words:", font=("Arial", 14), bg="#0A1128", fg="#FEFCFB").grid(row=0, column=0, sticky="w", padx=10)

    wrap = tk.Frame(main, bg="#0A1128"); wrap.grid(row=1, column=0, padx=10, pady=5)
    can = tk.Canvas(wrap, width=250, height=210, bg="#0A1128", highlightthickness=0)
    scr = ttk.Scrollbar(wrap, orient="vertical", command=can.yview)
    frm = tk.Frame(can, bg="#0A1128")
    frm.bind("<Configure>", lambda e: can.configure(scrollregion=can.bbox("all")))
    can.create_window((0,0), window=frm, anchor="nw")
    can.configure(yscrollcommand=scr.set)
    can.pack(side="left", fill="both", expand=True); scr.pack(side="right", fill="y")

    word_boxes = []
    def add_entry():
        ent = tk.Entry(frm, width=26, bg="#001F54", fg="#FEFCFB", insertbackground="#FEFCFB")
        ent.pack(pady=2)
        word_boxes.append(ent)
        ent.bind("<KeyRelease>", lambda e: on_type(ent))
    def on_type(entry):
        if entry.get().strip() != "" and entry == word_boxes[-1]:
            add_entry()
    add_entry()

    tk.Label(main, text="Size:", font=("Arial", 14), bg="#0A1128", fg="#FEFCFB").grid(row=2, column=0, sticky="w", padx=10)
    szf = tk.Frame(main, bg="#0A1128"); szf.grid(row=3, column=0, sticky="w", padx=10)
    tk.Label(szf, text="x", bg="#0A1128", fg="#FEFCFB").pack(side="left")
    x_ent = tk.Entry(szf, width=10, bg="#001F54", fg="#FEFCFB", insertbackground="#FEFCFB"); x_ent.insert(0, "10"); x_ent.pack(side="left", padx=5)
    tk.Label(szf, text="y", bg="#0A1128", fg="#FEFCFB").pack(side="left")
    y_ent = tk.Entry(szf, width=10, bg="#001F54", fg="#FEFCFB", insertbackground="#FEFCFB"); y_ent.insert(0, "10"); y_ent.pack(side="left", padx=5)

    tk.Label(main, text="Level 1-3:", font=("Arial", 14), bg="#0A1128", fg="#FEFCFB").grid(row=4, column=0, sticky="w", padx=10)
    lv_var = tk.StringVar(); lv_box = ttk.Combobox(main, width=25, textvariable=lv_var, values=["1","2","3"], state="readonly")
    lv_box.grid(row=5, column=0, sticky="w", padx=10); lv_box.current(0)

    stat = tk.Label(main, text="", fg="green", bg="#0A1128"); stat.grid(row=6, column=0, padx=10, pady=5)

    def go():
        save_stuff(x_ent, y_ent, lv_var)
        mk_grid(); draw()
        stat.config(text="done!")

    tk.Button(main, text="GENERATE", font=("Arial", 14), bg="#034078", fg="#FEFCFB", activebackground="#1282A2", command=go).grid(row=7, column=0, padx=10, pady=20)

    def open_export_window():
        win = tk.Toplevel()
        win.geometry("300x200")
        win.title("Export")
        tk.Label(win, text="Filename:", font=("Arial", 12)).pack(pady=10)
        name_entry = tk.Entry(win, width=30)
        name_entry.pack()
        tk.Label(win, text="Format:", font=("Arial", 12)).pack(pady=10)
        format_var = tk.StringVar()
        format_box = ttk.Combobox(win, textvariable=format_var, values=["json", "txt", "docx", "png", "pdf"], state="readonly")
        format_box.pack()
        format_box.current(0)
        def do_export():
            name = name_entry.get().strip()
            fmt = format_var.get()
            if not name:
                name = "export"
            if fmt == "json":
                with open(name + ".json", "w") as f:
                    json.dump({"grid": grid, "words": words}, f, indent=2)
            elif fmt == "txt":
                with open(name + ".txt", "w") as f:
                    for row in grid:
                        f.write(" ".join(row) + "\n")
            elif fmt == "docx":
                doc = Document()
                doc.add_heading("Word Search Grid", level=1)
                table = doc.add_table(rows=len(grid), cols=len(grid[0]))
                for i, row in enumerate(grid):
                    for j, cell in enumerate(row):
                        table.cell(i, j).text = cell
                doc.save(name + ".docx")
            elif fmt == "png":
                cell_size = 40
                font = ImageFont.load_default()
                img = Image.new("RGB", (cell_size * w_sz, cell_size * h_sz), color="white")
                draw = ImageDraw.Draw(img)
                for r in range(h_sz):
                    for c in range(w_sz):
                        x = c * cell_size
                        y = r * cell_size
                        draw.rectangle([x, y, x+cell_size, y+cell_size], outline="black")
                        draw.text((x+10, y+10), grid[r][c], fill="black", font=font)
                img.save(name + ".png")
            elif fmt == "pdf":
                c = pdf_canvas.Canvas(name + ".pdf", pagesize=letter)
                x0, y0 = 50, 750
                size = 20
                for i, row in enumerate(grid):
                    for j, ch in enumerate(row):
                        c.drawString(x0 + j*size, y0 - i*size, ch)
                c.save()
            win.destroy()
        tk.Button(win, text="Export", command=do_export, font=("Arial", 12)).pack(pady=15)

    tk.Button(main, text="EXPORT", font=("Arial", 14), bg="#034078", fg="#FEFCFB", activebackground="#1282A2", command=open_export_window).grid(row=8, column=0, padx=10, pady=5)

    cvs = tk.Canvas(main, width=500, height=500, bg="white")
    cvs.grid(row=0, column=1, rowspan=20, padx=30, pady=20, sticky="n")

load_stuff()
gui()
welcome_page()
show_frame(welcome_frame)
wnd.mainloop()