import tkinter as tk
from tkinter import messagebox, ttk
from typing import TYPE_CHECKING

import netaddr

from core.gui.dialogs.dialog import Dialog
from core.gui.themes import FRAME_PAD, PADX, PADY
from core.gui.widgets import ListboxScroll

if TYPE_CHECKING:
    from core.gui.app import Application


class IpConfigDialog(Dialog):
    def __init__(self, app: "Application") -> None:
        super().__init__(app, "IP Configuration")
        self.ip4 = self.app.guiconfig.ips.ip4
        self.ip6 = self.app.guiconfig.ips.ip6
        self.ip4s = self.app.guiconfig.ips.ip4s
        self.ip6s = self.app.guiconfig.ips.ip6s
        self.ip4_entry = None
        self.ip4_listbox = None
        self.ip6_entry = None
        self.ip6_listbox = None
        self.draw()

    def draw(self) -> None:
        self.top.columnconfigure(0, weight=1)
        self.top.rowconfigure(0, weight=1)

        # draw ip4 and ip6 lists
        frame = ttk.Frame(self.top)
        frame.columnconfigure(0, weight=1)
        frame.columnconfigure(1, weight=1)
        frame.rowconfigure(0, weight=1)
        frame.grid(sticky="nsew", pady=PADY)

        ip4_frame = ttk.LabelFrame(frame, text="IPv4", padding=FRAME_PAD)
        ip4_frame.columnconfigure(0, weight=1)
        ip4_frame.rowconfigure(0, weight=1)
        ip4_frame.grid(row=0, column=0, stick="nsew")
        self.ip4_listbox = ListboxScroll(ip4_frame)
        self.ip4_listbox.listbox.bind("<<ListboxSelect>>", self.select_ip4)
        self.ip4_listbox.grid(sticky="nsew", pady=PADY)
        for index, ip4 in enumerate(self.ip4s):
            self.ip4_listbox.listbox.insert(tk.END, ip4)
            if self.ip4 == ip4:
                self.ip4_listbox.listbox.select_set(index)
        self.ip4_entry = ttk.Entry(ip4_frame)
        self.ip4_entry.grid(sticky="ew", pady=PADY)
        ip4_button_frame = ttk.Frame(ip4_frame)
        ip4_button_frame.columnconfigure(0, weight=1)
        ip4_button_frame.columnconfigure(1, weight=1)
        ip4_button_frame.grid(sticky="ew")
        ip4_add = ttk.Button(ip4_button_frame, text="Add", command=self.click_add_ip4)
        ip4_add.grid(row=0, column=0, sticky="ew")
        ip4_del = ttk.Button(
            ip4_button_frame, text="Delete", command=self.click_del_ip4
        )
        ip4_del.grid(row=0, column=1, sticky="ew")

        ip6_frame = ttk.LabelFrame(frame, text="IPv6", padding=FRAME_PAD)
        ip6_frame.columnconfigure(0, weight=1)
        ip6_frame.rowconfigure(0, weight=1)
        ip6_frame.grid(row=0, column=1, stick="nsew")
        self.ip6_listbox = ListboxScroll(ip6_frame)
        self.ip6_listbox.listbox.bind("<<ListboxSelect>>", self.select_ip6)
        self.ip6_listbox.grid(sticky="nsew", pady=PADY)
        for index, ip6 in enumerate(self.ip6s):
            self.ip6_listbox.listbox.insert(tk.END, ip6)
            if self.ip6 == ip6:
                self.ip6_listbox.listbox.select_set(index)
        self.ip6_entry = ttk.Entry(ip6_frame)
        self.ip6_entry.grid(sticky="ew", pady=PADY)
        ip6_button_frame = ttk.Frame(ip6_frame)
        ip6_button_frame.columnconfigure(0, weight=1)
        ip6_button_frame.columnconfigure(1, weight=1)
        ip6_button_frame.grid(sticky="ew")
        ip6_add = ttk.Button(ip6_button_frame, text="Add", command=self.click_add_ip6)
        ip6_add.grid(row=0, column=0, sticky="ew")
        ip6_del = ttk.Button(
            ip6_button_frame, text="Delete", command=self.click_del_ip6
        )
        ip6_del.grid(row=0, column=1, sticky="ew")

        # draw buttons
        frame = ttk.Frame(self.top)
        frame.grid(stick="ew")
        for i in range(2):
            frame.columnconfigure(i, weight=1)
        button = ttk.Button(frame, text="Save", command=self.click_save)
        button.grid(row=0, column=0, sticky="ew", padx=PADX)
        button = ttk.Button(frame, text="Cancel", command=self.destroy)
        button.grid(row=0, column=1, sticky="ew")

    def click_add_ip4(self) -> None:
        ip4 = self.ip4_entry.get()
        if not ip4 or not netaddr.valid_ipv4(ip4):
            messagebox.showerror("IPv4 Error", f"Invalid IPv4 {ip4}")
        else:
            self.ip4_listbox.listbox.insert(tk.END, ip4)

    def click_del_ip4(self) -> None:
        if self.ip4_listbox.listbox.size() == 1:
            messagebox.showerror("IPv4 Error", "Must have at least one address")
        else:
            selection = self.ip4_listbox.listbox.curselection()
            self.ip4_listbox.listbox.delete(selection)
            self.ip4_listbox.listbox.select_set(0)

    def click_add_ip6(self) -> None:
        ip6 = self.ip6_entry.get()
        if not ip6 or not netaddr.valid_ipv6(ip6):
            messagebox.showerror("IPv6 Error", f"Invalid IPv6 {ip6}")
        else:
            self.ip6_listbox.listbox.insert(tk.END, ip6)

    def click_del_ip6(self) -> None:
        if self.ip6_listbox.listbox.size() == 1:
            messagebox.showerror("IPv6 Error", "Must have at least one address")
        else:
            selection = self.ip6_listbox.listbox.curselection()
            self.ip6_listbox.listbox.delete(selection)
            self.ip6_listbox.listbox.select_set(0)

    def select_ip4(self, _event: tk.Event) -> None:
        selection = self.ip4_listbox.listbox.curselection()
        self.ip4 = self.ip4_listbox.listbox.get(selection)

    def select_ip6(self, _event: tk.Event) -> None:
        selection = self.ip6_listbox.listbox.curselection()
        self.ip6 = self.ip6_listbox.listbox.get(selection)

    def click_save(self) -> None:
        ip4s = []
        for index in range(self.ip4_listbox.listbox.size()):
            ip4 = self.ip4_listbox.listbox.get(index)
            ip4s.append(ip4)
        ip6s = []
        for index in range(self.ip6_listbox.listbox.size()):
            ip6 = self.ip6_listbox.listbox.get(index)
            ip6s.append(ip6)
        ip_config = self.app.guiconfig.ips
        ip_config.ip4 = self.ip4
        ip_config.ip6 = self.ip6
        ip_config.ip4s = ip4s
        ip_config.ip6s = ip6s
        self.app.core.interfaces_manager.update_ips(self.ip4, self.ip6)
        self.app.save_config()
        self.destroy()