import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import requests
import threading

BASE_URL = "https://api.digitalocean.com/v2"


class DigitalOceanManagerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("DigitalOcean Bulk Resource Manager")
        self.root.geometry("950x700")

        self.tokens = []
        self.headers = {}
        self.droplets = []
        self.images = []
        self.connected = False

        self.build_ui()

    def build_ui(self):

        top_frame = ttk.Frame(self.root, padding=10)
        top_frame.pack(fill="x")

        ttk.Label(top_frame, text="API Tokens (one per line):").pack(anchor="w")

        self.token_box = scrolledtext.ScrolledText(top_frame, height=5)
        self.token_box.pack(fill="x", pady=5)

        btn_frame = ttk.Frame(self.root, padding=10)
        btn_frame.pack(fill="x")

        ttk.Button(btn_frame, text="Connect Tokens", command=self.connect_tokens).pack(side="left", padx=5)
        ttk.Button(btn_frame, text="Load Droplets", command=self.load_droplets).pack(side="left", padx=5)
        ttk.Button(btn_frame, text="Load Images", command=self.load_images).pack(side="left", padx=5)

        ttk.Button(btn_frame, text="Select All Droplets", command=self.select_all_droplets).pack(side="left", padx=5)
        ttk.Button(btn_frame, text="Select All Images", command=self.select_all_images).pack(side="left", padx=5)

        ttk.Button(btn_frame, text="Bulk Delete Droplets", command=self.delete_selected_droplets).pack(side="left", padx=5)
        ttk.Button(btn_frame, text="Bulk Delete Images", command=self.delete_selected_images).pack(side="left", padx=5)

        paned = ttk.Panedwindow(self.root, orient=tk.HORIZONTAL)
        paned.pack(fill="both", expand=True, padx=10, pady=10)

        droplets_frame = ttk.Labelframe(paned, text="Droplets", padding=10)
        images_frame = ttk.Labelframe(paned, text="Custom Images", padding=10)

        paned.add(droplets_frame, weight=1)
        paned.add(images_frame, weight=1)

        self.droplet_listbox = tk.Listbox(droplets_frame, selectmode=tk.MULTIPLE)
        self.droplet_listbox.pack(fill="both", expand=True)

        self.image_listbox = tk.Listbox(images_frame, selectmode=tk.MULTIPLE)
        self.image_listbox.pack(fill="both", expand=True)

        log_frame = ttk.Labelframe(self.root, text="Logs", padding=10)
        log_frame.pack(fill="both", padx=10, pady=(0, 10))

        self.log_box = scrolledtext.ScrolledText(log_frame, height=12, state="disabled")
        self.log_box.pack(fill="both", expand=True)

    def log(self, message):
        self.log_box.config(state="normal")
        self.log_box.insert(tk.END, message + "\n")
        self.log_box.see(tk.END)
        self.log_box.config(state="disabled")

    def connect_tokens(self):
        raw = self.token_box.get("1.0", tk.END).strip()
        self.tokens = [t.strip() for t in raw.splitlines() if t.strip()]

        if not self.tokens:
            messagebox.showerror("Error", "Please enter at least one API token.")
            return

        self.connected = True
        self.log(f"Loaded {len(self.tokens)} API tokens.")

    def set_headers(self, token):
        return {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        }

    def api_get_paginated(self, endpoint, key):

        items = []
        url = f"{BASE_URL}{endpoint}"

        while url:
            response = requests.get(url, headers=self.headers, timeout=30)
            response.raise_for_status()
            data = response.json()
            items.extend(data.get(key, []))
            url = data.get("links", {}).get("pages", {}).get("next")

        return items

    def load_droplets(self):

        if not self.connected:
            messagebox.showerror("Error", "Connect tokens first.")
            return

        threading.Thread(target=self._load_droplets_worker, daemon=True).start()

    def _load_droplets_worker(self):

        self.droplet_listbox.delete(0, tk.END)
        self.droplets = []

        for token in self.tokens:

            try:
                self.headers = self.set_headers(token)

                droplets = self.api_get_paginated("/droplets", "droplets")

                for d in droplets:

                    display = f"{d['name']} | ID:{d['id']} | Region:{d['region']['slug']} | Status:{d['status']}"

                    self.droplets.append((token, d))
                    self.droplet_listbox.insert(tk.END, display)

                self.log(f"{len(droplets)} droplets loaded.")

            except Exception as e:
                self.log(f"Error loading droplets: {e}")

    def load_images(self):

        if not self.connected:
            messagebox.showerror("Error", "Connect tokens first.")
            return

        threading.Thread(target=self._load_images_worker, daemon=True).start()

    def _load_images_worker(self):

        self.image_listbox.delete(0, tk.END)
        self.images = []

        for token in self.tokens:

            try:
                self.headers = self.set_headers(token)

                images = self.api_get_paginated("/images?private=true", "images")

                for img in images:

                    display = f"{img['name']} | ID:{img['id']} | {img.get('distribution','')}"

                    self.images.append((token, img))
                    self.image_listbox.insert(tk.END, display)

                self.log(f"{len(images)} images loaded.")

            except Exception as e:
                self.log(f"Error loading images: {e}")

    def select_all_droplets(self):
        self.droplet_listbox.select_set(0, tk.END)
        self.log("All droplets selected.")

    def select_all_images(self):
        self.image_listbox.select_set(0, tk.END)
        self.log("All images selected.")

    def delete_selected_droplets(self):

        selected = self.droplet_listbox.curselection()

        if not selected:
            messagebox.showwarning("Warning", "No droplets selected.")
            return

        threading.Thread(target=self._delete_droplets_worker, args=(selected,), daemon=True).start()

    def _delete_droplets_worker(self, indexes):

        for i in indexes:

            token, droplet = self.droplets[i]

            try:
                self.headers = self.set_headers(token)

                response = requests.delete(
                    f"{BASE_URL}/droplets/{droplet['id']}",
                    headers=self.headers,
                    timeout=30
                )

                if response.status_code == 204:
                    self.log(f"Deleted droplet {droplet['name']}")
                else:
                    self.log(f"Failed deleting {droplet['name']}")

            except Exception as e:
                self.log(f"Error deleting {droplet['name']} : {e}")

        self.load_droplets()

    def delete_selected_images(self):

        selected = self.image_listbox.curselection()

        if not selected:
            messagebox.showwarning("Warning", "No images selected.")
            return

        threading.Thread(target=self._delete_images_worker, args=(selected,), daemon=True).start()

    def _delete_images_worker(self, indexes):

        for i in indexes:

            token, image = self.images[i]

            try:
                self.headers = self.set_headers(token)

                response = requests.delete(
                    f"{BASE_URL}/images/{image['id']}",
                    headers=self.headers,
                    timeout=30
                )

                if response.status_code == 204:
                    self.log(f"Deleted image {image['name']}")
                else:
                    self.log(f"Failed deleting {image['name']}")

            except Exception as e:
                self.log(f"Error deleting {image['name']} : {e}")

        self.load_images()


if __name__ == "__main__":
    root = tk.Tk()
    app = DigitalOceanManagerApp(root)
    root.mainloop()