import tkinter as tk
import urllib.request
import json
import threading
import time
from datetime import datetime
import calendar
import math
from PIL import Image, ImageTk
import os
import configparser
import sys
import urllib.parse

# Load config
def load_config():
    config = configparser.ConfigParser()
    cfg_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "k8e_config.ini")
    if not os.path.exists(cfg_path):
        # First run — show setup dialog
        show_setup(cfg_path)
    config.read(cfg_path)
    return config

def lookup_city(city_name):
    try:
        url = ("https://geocoding-api.open-meteo.com/v1/search?"
               f"name={urllib.parse.quote(city_name)}&count=1&language=en&format=json")
        with urllib.request.urlopen(url, timeout=10) as r:
            d = json.loads(r.read())
        if d.get("results"):
            res = d["results"][0]
            name = res.get("name","")
            country = res.get("country","")
            state = res.get("admin1","")
            display = f"{name}, {state}, {country}".strip(", ")
            return {
                "city": display,
                "latitude": str(res["latitude"]),
                "longitude": str(res["longitude"]),
                "timezone": res.get("timezone", "UTC")
            }
    except:
        pass
    return None

def show_setup(cfg_path):
    setup = tk.Tk()
    setup.title("K8E Widget Setup")
    setup.geometry("420x280")
    setup.configure(bg="#000000")
    setup.resizable(False, False)

    tk.Label(setup, text="K8E WIDGET", bg="#000000", fg="#00ff41",
             font=("Courier New", 18, "bold")).pack(pady=(20,2))
    tk.Label(setup, text="JUSTICE IS COMING  //  k8e-ai.com",
             bg="#000000", fg="#334455", font=("Courier New", 8)).pack()
    tk.Label(setup, text="Enter your city to get live local weather",
             bg="#000000", fg="#667788", font=("Courier New", 9)).pack(pady=(12,8))

    entry_frame = tk.Frame(setup, bg="#000000")
    entry_frame.pack(padx=30, fill="x")
    city_entry = tk.Entry(entry_frame, bg="#0a0a0f", fg="#ffffff",
                           insertbackground="#00ff41",
                           font=("Courier New", 12), relief="flat",
                           bd=0, highlightthickness=1,
                           highlightbackground="#334455",
                           highlightcolor="#00ff41")
    city_entry.pack(fill="x", ipady=8)
    city_entry.insert(0, "e.g. London, Tokyo, Sydney, Chicago")
    city_entry.bind("<FocusIn>", lambda e: city_entry.delete(0, "end")
                    if "e.g." in city_entry.get() else None)

    status_label = tk.Label(setup, text="", bg="#000000", fg="#00cfff",
                             font=("Courier New", 9))
    status_label.pack(pady=4)

    def do_save():
        city_input = city_entry.get().strip()
        if not city_input or "e.g." in city_input:
            status_label.config(text="Please enter a city name!", fg="#ff5555")
            return
        status_label.config(text="Looking up your city...", fg="#00cfff")
        setup.update()
        result = lookup_city(city_input)
        if result:
            config = configparser.ConfigParser()
            config["Settings"] = result
            with open(cfg_path, "w") as f:
                config.write(f)
            status_label.config(text=f"Found: {result['city']}", fg="#00ff41")
            setup.update()
            setup.after(800, setup.destroy)
        else:
            status_label.config(
                text="City not found. Try a bigger nearby city.", fg="#ff5555")

    tk.Button(setup, text="LAUNCH WIDGET", bg="#00ff41", fg="#000000",
              font=("Courier New", 11, "bold"), bd=0, padx=20, pady=8,
              cursor="hand2", command=do_save).pack(pady=12)
    city_entry.bind("<Return>", lambda e: do_save())
    setup.mainloop()

config = load_config()
CITY = config.get("Settings", "city", fallback="Cleveland, OH")
LAT = config.getfloat("Settings", "latitude", fallback=41.4993)
LON = config.getfloat("Settings", "longitude", fallback=-81.6944)
TZ = config.get("Settings", "timezone", fallback="America/New_York")

weather_data = {
    "temp": "--", "feels": "--", "desc": "Loading...",
    "wind": "--", "humidity": "--", "high": "--", "low": "--"
}

WMO = {
    0:"Clear",1:"Mainly Clear",2:"Partly Cloudy",3:"Overcast",
    45:"Foggy",51:"Light Drizzle",53:"Drizzle",55:"Heavy Drizzle",
    61:"Light Rain",63:"Rain",65:"Heavy Rain",71:"Light Snow",
    73:"Snow",75:"Heavy Snow",80:"Rain Showers",95:"Thunderstorm"
}

def fetch_weather():
    while True:
        try:
            url = ("https://api.open-meteo.com/v1/forecast?"
                   f"latitude={LAT}&longitude={LON}"
                   "&current=temperature_2m,apparent_temperature,weathercode,"
                   "windspeed_10m,relative_humidity_2m"
                   "&daily=temperature_2m_max,temperature_2m_min"
                   "&temperature_unit=fahrenheit&windspeed_unit=mph"
                   f"&timezone={TZ.replace('/','%2F')}&forecast_days=1")
            with urllib.request.urlopen(url, timeout=10) as r:
                d = json.loads(r.read())
            c = d["current"]
            daily = d["daily"]
            weather_data["temp"] = str(round(c["temperature_2m"]))
            weather_data["feels"] = str(round(c["apparent_temperature"]))
            weather_data["wind"] = str(round(c["windspeed_10m"]))
            weather_data["humidity"] = str(round(c["relative_humidity_2m"]))
            weather_data["high"] = str(round(daily["temperature_2m_max"][0]))
            weather_data["low"] = str(round(daily["temperature_2m_min"][0]))
            weather_data["desc"] = WMO.get(c["weathercode"], "Unknown")
        except:
            weather_data["desc"] = "Weather unavailable"
        time.sleep(600)


class K8EWidget:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("K8E Widget")
        self.root.overrideredirect(True)
        self.root.attributes("-topmost", False)
        self.root.attributes("-alpha", 0.95)
        self.root.geometry("300x600+50+50")
        self.root.configure(bg="#000000")
        self.drag_x = 0
        self.drag_y = 0

        # Try to load K8E logo
        self.logo_img = None
        logo_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "k8e_logo_transparent.png")
        alt_path = r"M:\k8e_logo_transparent.png"
        for p in [logo_path, alt_path]:
            if os.path.exists(p):
                try:
                    img = Image.open(p).convert("RGBA")
                    img = img.resize((200, 200), Image.LANCZOS)
                    self.logo_img = ImageTk.PhotoImage(img)
                    break
                except:
                    pass

        self.build_ui()
        self.root.bind("<Button-1>", self.start_drag)
        self.root.bind("<B1-Motion>", self.drag)
        self.root.bind("<Button-3>", self.right_click)
        # Allow resizing
        self.root.resizable(True, True)
        self._add_resize_grip()
        threading.Thread(target=fetch_weather, daemon=True).start()
        self.update_loop()
        self.root.mainloop()

    def build_ui(self):
        BG = "#000000"
        CARD = "#0a0a0f"
        GREEN = "#00ff41"
        CYAN = "#00cfff"
        WHITE = "#ffffff"
        DIM = "#667788"
        WARM = "#ff7850"

        # Title bar
        title = tk.Frame(self.root, bg="#050510", height=28)
        title.pack(fill="x")
        title.pack_propagate(False)
        tk.Label(title, text="K8E  //  JUSTICE IS COMING",
                 bg="#050510", fg=GREEN,
                 font=("Courier New", 7, "bold")).pack(side="left", padx=10)
        tk.Button(title, text="x", bg="#050510", fg="#445566",
                  bd=0, font=("Segoe UI", 9),
                  command=self.root.destroy).pack(side="right", padx=8)
        title.bind("<Button-1>", self.start_drag)
        title.bind("<B1-Motion>", self.drag)


        # K8E CLOCK — big canvas, logo as face, numbers outside
        clock_card = tk.Frame(self.root, bg=CARD, pady=10)
        clock_card.pack(fill="x", padx=8, pady=(6,3))

        self.clock_canvas = tk.Canvas(clock_card, width=280, height=280,
                                       bg=BG, highlightthickness=0)
        self.clock_canvas.pack()

        # Temp + weather BELOW clock
        wrow = tk.Frame(self.root, bg=CARD, pady=8, padx=12)
        wrow.pack(fill="x", padx=8, pady=(0,3))

        self.temp_label = tk.Label(wrow, text="--F", bg=CARD, fg=WHITE,
                                    font=("Courier New", 28, "bold"))
        self.temp_label.pack(side="left")

        winfo = tk.Frame(wrow, bg=CARD)
        winfo.pack(side="left", padx=12)
        self.desc_label = tk.Label(winfo, text="Loading...", bg=CARD,
                                    fg=GREEN, font=("Courier New", 9))
        self.desc_label.pack(anchor="w")
        self.feels_label = tk.Label(winfo, text="Feels --F", bg=CARD,
                                     fg=DIM, font=("Courier New", 8))
        self.feels_label.pack(anchor="w")

        # Details
        det_card = tk.Frame(self.root, bg=CARD, pady=6, padx=12)
        det_card.pack(fill="x", padx=8, pady=(0,3))
        det = tk.Frame(det_card, bg=CARD)
        det.pack(fill="x")
        items = [("WIND","wind_val",WHITE),("HUMID","hum_val",WHITE),
                 ("HIGH","high_val",WARM),("LOW","low_val",CYAN)]
        for i,(lbl,attr,color) in enumerate(items):
            col = tk.Frame(det, bg="#050510", padx=4, pady=4)
            col.grid(row=0, column=i, padx=2, sticky="ew")
            det.columnconfigure(i, weight=1)
            tk.Label(col, text=lbl, bg="#050510", fg=GREEN,
                     font=("Courier New", 7)).pack()
            val = tk.Label(col, text="--", bg="#050510", fg=color,
                           font=("Courier New", 9, "bold"))
            val.pack()
            setattr(self, attr, val)

        # Calendar with Katie faded background
        ccard = tk.Frame(self.root, bg=CARD, pady=8, padx=12)
        ccard.pack(fill="x", padx=8, pady=(3,4))
        self.month_label = tk.Label(ccard, text="", bg=CARD, fg=GREEN,
                                     font=("Courier New", 9, "bold"))
        self.month_label.pack(anchor="w")

        # Load Katie faded image
        self.katie_bg = None
        try:
            k_img = Image.open("M:/katie_faded.png")
            self.katie_bg = ImageTk.PhotoImage(k_img)
        except:
            pass

        # Canvas with Katie as background
        self.cal_canvas = tk.Canvas(ccard, width=276, height=175,
                                     bg=CARD, highlightthickness=0)
        self.cal_canvas.pack()
        if self.katie_bg:
            self.cal_canvas.create_image(0, 0, anchor="nw", image=self.katie_bg)

        # Day headers
        days = ["Su","Mo","Tu","We","Th","Fr","Sa"]
        for i, d in enumerate(days):
            self.cal_canvas.create_text(18 + i*38, 10, text=d,
                                         fill="#00cfff",
                                         font=("Courier New", 8, "bold"))

        # Calendar number cells as canvas text
        self.cal_cells = []
        for row in range(6):
            rc = []
            for col in range(7):
                cid = self.cal_canvas.create_text(
                    18 + col*38, 28 + row*21,
                    text="", fill="#cccccc",
                    font=("Courier New", 9),
                    anchor="center"
                )
                rc.append(cid)
            self.cal_cells.append(rc)

        self.date_label = tk.Label(self.root, text="", bg=BG, fg=DIM,
                                    font=("Courier New", 8))
        self.date_label.pack(pady=(2,6))


    def draw_clock(self, now):
        c = self.clock_canvas
        c.delete("all")
        cx, cy = 140, 140
        r_face = 110   # face radius
        r_nums = 128   # numbers outside face
        GREEN = "#00ff41"
        CYAN = "#00cfff"

        # Outer glow ring
        for i in range(4, 0, -1):
            alpha_color = ["#003300","#004400","#006600","#009900"][i-1]
            c.create_oval(cx-(r_face+i*3), cy-(r_face+i*3),
                          cx+(r_face+i*3), cy+(r_face+i*3),
                          outline=alpha_color, width=2)

        # Green outer ring
        c.create_oval(cx-r_face-2, cy-r_face-2,
                      cx+r_face+2, cy+r_face+2,
                      outline=GREEN, width=2)

        # Cyan inner ring
        c.create_oval(cx-r_face+8, cy-r_face+8,
                      cx+r_face-8, cy+r_face-8,
                      outline=CYAN, width=1)

        # Dark face fill
        c.create_oval(cx-r_face, cy-r_face, cx+r_face, cy+r_face,
                      fill="#05050f", outline="")

        # K8E logo in center if loaded
        if self.logo_img:
            c.create_image(cx, cy, image=self.logo_img)
        else:
            # Draw K8E text if no logo
            c.create_text(cx, cy, text="K8E", fill=CYAN,
                          font=("Courier New", 28, "bold"))

        # Hour numbers OUTSIDE the face
        for i in range(1, 13):
            angle = math.radians(i * 30 - 90)
            nx = cx + r_nums * math.cos(angle)
            ny = cy + r_nums * math.sin(angle)
            c.create_text(nx, ny, text=str(i), fill=GREEN,
                          font=("Courier New", 9, "bold"))

        # Tick marks on face edge
        for i in range(60):
            angle = math.radians(i * 6 - 90)
            if i % 5 == 0:
                r1, r2, w = r_face-2, r_face-10, 2
                col = GREEN
            else:
                r1, r2, w = r_face-2, r_face-6, 1
                col = "#224422"
            c.create_line(cx + r1*math.cos(angle), cy + r1*math.sin(angle),
                          cx + r2*math.cos(angle), cy + r2*math.sin(angle),
                          fill=col, width=w)

        # Hour hand
        h_ang = math.radians((now.hour % 12) * 30 + now.minute * 0.5 - 90)
        c.create_line(cx, cy,
                      cx + (r_face*0.52)*math.cos(h_ang),
                      cy + (r_face*0.52)*math.sin(h_ang),
                      fill=WHITE, width=4, capstyle="round")

        # Minute hand
        m_ang = math.radians(now.minute * 6 + now.second * 0.1 - 90)
        c.create_line(cx, cy,
                      cx + (r_face*0.72)*math.cos(m_ang),
                      cy + (r_face*0.72)*math.sin(m_ang),
                      fill=WHITE, width=2, capstyle="round")

        # Second hand — CYAN
        s_ang = math.radians(now.second * 6 - 90)
        c.create_line(cx, cy,
                      cx + (r_face*0.80)*math.cos(s_ang),
                      cy + (r_face*0.80)*math.sin(s_ang),
                      fill=CYAN, width=1, capstyle="round")

        # Center cap
        c.create_oval(cx-4, cy-4, cx+4, cy+4, fill=GREEN, outline="")


    def update_loop(self):
        now = datetime.now()
        self.draw_clock(now)
        self.date_label.config(
            text=now.strftime("%A  %B %d, %Y  //  %I:%M:%S %p").lstrip("0"))
        self.temp_label.config(text=f"{weather_data['temp']}F")
        self.desc_label.config(text=weather_data["desc"])
        self.feels_label.config(text=f"Feels like {weather_data['feels']}F")
        self.wind_val.config(text=f"{weather_data['wind']}mph")
        self.hum_val.config(text=f"{weather_data['humidity']}%")
        self.high_val.config(text=f"{weather_data['high']}F")
        self.low_val.config(text=f"{weather_data['low']}F")
        self.month_label.config(text=now.strftime("// %B %Y //"))
        cal = calendar.monthcalendar(now.year, now.month)
        today = now.day
        for r2, row_cells in enumerate(self.cal_cells):
            for c2, cid in enumerate(row_cells):
                if r2 < len(cal):
                    day = cal[r2][c2]
                    if day == 0:
                        self.cal_canvas.itemconfig(cid, text="")
                    elif day == today:
                        self.cal_canvas.itemconfig(cid, text=str(day),
                                                    fill="#00ff41",
                                                    font=("Courier New", 10, "bold"))
                    else:
                        self.cal_canvas.itemconfig(cid, text=str(day),
                                                    fill="#ffffff",
                                                    font=("Courier New", 9))
                else:
                    self.cal_canvas.itemconfig(cid, text="")
        self.root.after(1000, self.update_loop)

    def _add_resize_grip(self):
        grip = tk.Label(self.root, text="⠿", bg="#050510", fg="#334455",
                        cursor="size_nw_se", font=("Segoe UI", 10))
        grip.place(relx=1.0, rely=1.0, anchor="se")
        grip.bind("<Button-1>", self._resize_start)
        grip.bind("<B1-Motion>", self._resize_drag)
        self._rw = 300
        self._rh = 600

    def _resize_start(self, e):
        self._rw = self.root.winfo_width()
        self._rh = self.root.winfo_height()
        self._rx = e.x_root
        self._ry = e.y_root

    def _resize_drag(self, e):
        nw = max(260, self._rw + (e.x_root - self._rx))
        nh = max(400, self._rh + (e.y_root - self._ry))
        self.root.geometry(f"{nw}x{nh}")

    def start_drag(self, e):
        self.drag_x = e.x
        self.drag_y = e.y

    def drag(self, e):
        x = self.root.winfo_x() + e.x - self.drag_x
        y = self.root.winfo_y() + e.y - self.drag_y
        self.root.geometry(f"+{x}+{y}")

    def right_click(self, e):
        menu = tk.Menu(self.root, tearoff=0)
        menu.add_command(label="K8E-AI.COM", command=lambda: None)
        menu.add_separator()
        menu.add_command(label="Close Widget", command=self.root.destroy)
        menu.post(e.x_root, e.y_root)

# Check for PIL
try:
    from PIL import Image, ImageTk
except ImportError:
    Image = None
    ImageTk = None
    class K8EWidget2(K8EWidget):
        def __init__(self):
            self.logo_img = None
            super().__init__()

WHITE = "#ffffff"
K8EWidget()
