import tkinter as tk
from tkinter import ttk


class LoadingPopup:
    def __init__(self, root, title="Working..."):
        self.top = tk.Toplevel(root)
        self.top.title(title)
        self.top.geometry("280x100")
        self.top.resizable(False, False)
        self.top.transient(root)
        self.top.grab_set()
        self.top.protocol("WM_DELETE_WINDOW", lambda: None)

        frm = ttk.Frame(self.top, padding=12)
        frm.pack(fill=tk.BOTH, expand=True)
        self.label = ttk.Label(frm, text=title)
        self.label.pack(anchor=tk.W)
        self.prog = ttk.Progressbar(frm, mode="indeterminate")
        self.prog.pack(fill=tk.X, pady=(8,0))
        self.prog.start(10)

    def set_text(self, text: str):
        try:
            self.label.config(text=text)
            self.top.update_idletasks()
        except Exception:
            pass

    def close(self):
        try:
            self.prog.stop()
            self.top.grab_release()
            self.top.destroy()
        except Exception:
            pass


class MapPopup:
    def __init__(self, master, fetch_camera, fetch_roads, fetch_vehicles, fetch_accidents=None):
        self.master = master
        self.window = tk.Toplevel(master)
        self.window.title("2D Minimap")
        self.window.geometry("600x650")
        self.window.resizable(True, True)
        self.window.attributes('-topmost', True)

        frame = ttk.Frame(self.window, padding="6")
        frame.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.W, tk.E))
        self.window.columnconfigure(0, weight=1)
        self.window.rowconfigure(0, weight=1)

        # Canvas for the map
        self.canvas = tk.Canvas(frame, width=560, height=560, bg="#1a1a1a", highlightthickness=0)
        self.canvas.grid(row=0, column=0, columnspan=4, sticky=(tk.N, tk.S, tk.W, tk.E))
        frame.rowconfigure(0, weight=1)

        # Control buttons
        ttk.Button(frame, text="-", width=3, command=lambda: self._zoom(0.8)).grid(row=1, column=0, pady=(6,0), sticky=tk.W)
        ttk.Button(frame, text="+", width=3, command=lambda: self._zoom(1.25)).grid(row=1, column=1, pady=(6,0), sticky=tk.W)
        ttk.Button(frame, text="Center", width=6, command=self._center_on_camera).grid(row=1, column=2, pady=(6,0))
        ttk.Button(frame, text="Close", command=self.window.withdraw).grid(row=1, column=3, pady=(6,0), sticky=tk.E)

        frame.columnconfigure(0, weight=1)
        frame.columnconfigure(1, weight=1)
        frame.columnconfigure(2, weight=1)
        frame.columnconfigure(3, weight=1)

        # Status label
        self.status_label = ttk.Label(frame, text="Minimap Ready", foreground="#666666")
        self.status_label.grid(row=2, column=0, columnspan=4, pady=(2,0), sticky=tk.W)

        self._zoom_scale = 2.0
        self._last_draw = 0.0
        self._center_x = 0.0
        self._center_z = 0.0
        self._auto_center = True

        self.fetch_camera = fetch_camera
        self.fetch_roads = fetch_roads
        self.fetch_vehicles = fetch_vehicles
        self.fetch_accidents = fetch_accidents or (lambda: [])

    def _zoom(self, factor):
        self._zoom_scale = max(0.5, min(20.0, self._zoom_scale * factor))
        self._last_draw = 0.0
        self._update_status()

    def _center_on_camera(self):
        try:
            cam_eye, cam_view = self.fetch_camera()
            self._center_x = cam_eye.X
            self._center_z = cam_eye.Z
            self._auto_center = False
            self._last_draw = 0.0
            self._update_status()
        except Exception:
            pass

    def _update_status(self):
        try:
            zoom_pct = int(self._zoom_scale * 50)
            mode = "Auto" if self._auto_center else "Manual"
            self.status_label.config(text=f"Zoom: {zoom_pct}% | Mode: {mode} | Vehicles: {len(self.fetch_vehicles(self.fetch_camera()[0]) if self.fetch_camera else [])}")
        except Exception:
            self.status_label.config(text="Minimap Status")

    def update_if_needed(self, now):
        if now - self._last_draw < 0.2:  # Update more frequently for smoother animation
            return
        self._last_draw = now
        self._draw_frame()

    def _draw_frame(self):
        try:
            cam_eye, cam_view = self.fetch_camera()
            roads = self.fetch_roads()
            vehs = self.fetch_vehicles(cam_eye)
            accidents = self.fetch_accidents()

            canvas = self.canvas
            w = int(canvas.winfo_width())
            h = int(canvas.winfo_height())
            if w <= 0 or h <= 0:
                return

            canvas.delete("all")

            # Auto-center on camera if enabled
            if self._auto_center:
                self._center_x = cam_eye.X
                self._center_z = cam_eye.Z

            cx, cy = w//2, h//2
            scale = self._zoom_scale

            def world_to_screen(x, z):
                return (cx + (x - self._center_x)/scale, cy - (z - self._center_z)/scale)

            # Draw roads (GTA-style road network)
            for road in roads:
                try:
                    length = getattr(road, 'Length', 0.0)
                    if length <= 0.0:
                        continue
                    steps = max(8, min(80, int(length/50)))
                    points = []
                    for s in range(steps+1):
                        d = length * s/steps
                        p = road.GetPositionAt(d)
                        x, y = world_to_screen(p.X, p.Z)
                        points.append((x,y))

                    # Draw road segments
                    for i in range(len(points)-1):
                        x1,y1 = points[i]
                        x2,y2 = points[i+1]
                        canvas.create_line(x1,y1,x2,y2, fill="#4a90e2", width=3, capstyle=tk.ROUND)

                    # Add road direction arrows every 100 units
                    if length > 100:
                        for i in range(0, int(length), 100):
                            try:
                                p = road.GetPositionAt(float(i))
                                x, y = world_to_screen(p.X, p.Z)
                                # Simple arrow pointing in road direction
                                canvas.create_oval(x-2, y-2, x+2, y+2, fill="#4a90e2", outline="")
                            except:
                                pass
                except Exception:
                    pass

            # Draw vehicles (GTA-style blips)
            for v in vehs:
                try:
                    pos = v.Position
                    x,y = world_to_screen(pos.X, pos.Z)
                    # Larger, more visible vehicle dots
                    r = 4
                    canvas.create_oval(x-r, y-r, x+r, y+r, fill="#ffcc00", outline="#ffffff", width=1)
                except Exception:
                    pass

            # Draw accidents (red danger markers)
            for accident in accidents:
                try:
                    pos = accident.get('position', None)
                    if pos:
                        x,y = world_to_screen(pos.X, pos.Z)
                        # Red danger triangle
                        size = 8
                        canvas.create_polygon(
                            x, y-size,
                            x-size*0.866, y+size*0.5,
                            x+size*0.866, y+size*0.5,
                            fill="#ff4444", outline="#ffffff", width=2
                        )
                        # White exclamation mark
                        canvas.create_text(x, y, text="!", fill="#ffffff", font=("Arial", 10, "bold"))
                except Exception:
                    pass

            # Draw camera position and direction (player marker)
            try:
                cam_x, cam_y = world_to_screen(cam_eye.X, cam_eye.Z)
                # Camera position (player blip)
                r = 6
                canvas.create_oval(cam_x-r, cam_y-r, cam_x+r, cam_y+r, fill="#00ff00", outline="#ffffff", width=2)

                # Camera direction arrow (showing where player is facing)
                dx, dz = (cam_view.X - cam_eye.X), (cam_view.Z - cam_eye.Z)
                norm = max((dx*dx + dz*dz) ** 0.5, 1e-6)
                dx/=norm; dz/=norm
                arrow_length = 15
                x1,y1 = world_to_screen(cam_eye.X, cam_eye.Z)
                x2,y2 = world_to_screen(cam_eye.X + dx*arrow_length, cam_eye.Z + dz*arrow_length)
                canvas.create_line(x1,y1,x2,y2, fill="#ffffff", width=3, arrow=tk.LAST, arrowshape=(8,10,3))
            except Exception:
                pass

            # Draw coordinate grid (optional, for reference)
            if self._zoom_scale < 1.0:
                grid_size = 100 / self._zoom_scale
                grid_start_x = self._center_x - (w/2 * self._zoom_scale)
                grid_start_z = self._center_z - (h/2 * self._zoom_scale)
                grid_end_x = self._center_x + (w/2 * self._zoom_scale)
                grid_end_z = self._center_z + (h/2 * self._zoom_scale)

                for gx in range(int(grid_start_x // grid_size * grid_size), int(grid_end_x + grid_size), int(grid_size)):
                    x1, y1 = world_to_screen(gx, grid_start_z)
                    x2, y2 = world_to_screen(gx, grid_end_z)
                    canvas.create_line(x1, y1, x2, y2, fill="#333333", width=1, dash=(2,4))

                for gz in range(int(grid_start_z // grid_size * grid_size), int(grid_end_z + grid_size), int(grid_size)):
                    x1, y1 = world_to_screen(grid_start_x, gz)
                    x2, y2 = world_to_screen(grid_end_x, gz)
                    canvas.create_line(x1, y1, x2, y2, fill="#333333", width=1, dash=(2,4))

            self._update_status()

        except Exception as e:
            # Draw error message on canvas
            canvas = self.canvas
            canvas.delete("all")
            canvas.create_text(w//2, h//2, text=f"Minimap Error:\n{str(e)}", fill="#ff6666", justify=tk.CENTER)

