import csv
import os
import sys
import tkinter as tk
from configparser import NoSectionError, NoOptionError
from tkinter import messagebox
from tkinter import ttk
import json

from config import Config
from windows import SettingsWindow, EditRecord, Window, show_error


class Application:
    def __init__(self):
        # tkinter settings
        x_offset = 700
        y_offset = 200
        width = 1050
        height = 700
        title = "Brovski Adress-Etiketten Verwaltung"

        self.root = tk.Tk(className="BrovskiAdressEtiketten")
        self.root.title(title)
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)
        self.root.geometry(f"{width}x{height}+{x_offset}+{y_offset}")
        self.config = Config()
        self.config_good = False

        # variables
        self.address_list = []
        self.current_record: int | None = None
        self.sort_order = False

        # init paths to json and csv file
        self.json_file_name = "brovski-adress-etiketten-verwaltung.json"
        self.csv_file_name = "brovski-adress-etiketten.csv"
        self.json_path = ""
        self.csv_path = ""
        self.load_config()
        self.json_file = os.path.join(self.json_path, self.json_file_name)
        self.csv_file = os.path.join(self.csv_path, self.csv_file_name)

        # leave application if settings are bad
        if not self.config_good:
            show_error(message_title="Fehler Konfiguration",
                       message="Die Konfiguration ist fehlerhaft, bitte prüfe deine config.ini",
                       parent=self.root
                       )
            sys.exit()

        top_frame = tk.Frame(self.root)
        top_frame.pack(side=tk.TOP, fill=tk.X)
        button_width = 8
        tk.Button(top_frame, text="Insert", command=self.insert_record, width=button_width).pack(side=tk.LEFT)
        tk.Button(top_frame, text="Delete", command=self.delete_record, width=button_width).pack(side=tk.LEFT)
        tk.Button(top_frame, text="Export CSV", command=self.export_csv, width=button_width).pack(side=tk.LEFT)
        tk.Button(top_frame, text="Toggle Aktiv", command=self.toggle_active, width=button_width).pack(side=tk.LEFT)
        tk.Button(top_frame, text="Quit", command=self.on_close, width=button_width).pack(side=tk.RIGHT)
        tk.Button(top_frame, text="Settings", command=self.show_settings, width=button_width).pack(side=tk.RIGHT)

        data_frame = tk.Frame(self.root, bg="teal")
        data_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True)

        scrollbar = ttk.Scrollbar(data_frame, orient=tk.VERTICAL)
        self.table = ttk.Treeview(data_frame, yscrollcommand=scrollbar.set, columns=("0", "1", "2", "3", "4"),
                                  show="headings")
        scrollbar.config(command=self.table.yview)
        self.table.heading('0', text="Aktiv")
        self.table.column('0', anchor=tk.CENTER, width=0)
        self.table.heading('1', text="Firma")
        self.table.heading('2', text="Name")
        self.table.heading('3', text="Strasse")
        self.table.heading('4', text="Plz/Ort")
        self.table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.LEFT, fill=tk.Y)

        self.table.bind("<ButtonRelease-1>", self.mouse_click)
        self.table.bind("<Return>", self.mouse_click_double)
        self.table.bind("<Double-1>", self.mouse_click_double)

        self._load_json_file()

        self.root.mainloop()

    def load_config(self):
        try:
            self.json_path = self.config.get("json", "path")
            self.csv_path = self.config.get("csv", "path")
            if self.json_path == "" or self.csv_path == "":
                raise ValueError("Empty JSON or CSV path")
            self.config_good = True
        except NoSectionError:
            self.show_config_error()
            self.show_settings()
        except NoOptionError:
            self.show_config_error()
            self.show_settings()
        except ValueError:
            self.show_config_error()
            self.show_settings()

    def show_config_error(self):
        show_error(message_title="Fehlerhafte Konfiguration",
                   message="Konnte benötigte Parameter in config.ini nicht finden",
                   parent=self.root)

    def on_close(self):
        self.root.destroy()

    def show_settings(self):
        settings = self.open_window_settings()
        settings.wait_window()

    def insert_record(self):
        values = [
            "x",
            "Firma",
            "Name",
            "Strasse",
            "Plz/Ort",
        ]
        last_iid = self.table.get_children()[-1]
        next_iid = int(last_iid) + 1
        self.table.insert('', 'end', iid=next_iid, values=values)
        self._save_json_file()
        self.deselect_tree()

    def delete_record(self):
        if self.current_record is None:
            return

        if messagebox.askyesno(
                "Eintrag löschen?",
                "Willst du diesen Eintrag wirklich löschen?\nDies kann nicht rückgängig gemacht werden"):
            self.table.delete(self.current_record)

        self.deselect_tree()
        self._save_json_file()

    def update_record(self, data: list):
        if self.current_record is None:
            return
        values = {}
        for idx, value in enumerate(data):
            values[str(idx)] = value.get()

        for key, value in values.items():
            self.table.set(self.current_record, key, value)

        self._save_json_file()

    def toggle_active(self):
        items = self.table.selection()
        if len(items) == 0:
            return

        for record_id in items:
            values = self.table.item(record_id, "values")
            active = values[0]
            new_active = "x" if active == "" else ""
            self.table.set(record_id, "0", new_active)

        self._save_json_file()

    def deselect_tree(self):
        while len(self.table.selection()) > 0:
            self.table.selection_remove(self.table.selection()[0])
        self.current_record = None

    def mouse_click(self, event):
        self.current_record = self.table.focus()
        region = self.table.identify("region", event.x, event.y)
        match region:
            case "heading":
                self.click_on_header(event)

    def mouse_click_double(self, event):
        region = self.table.identify("region", event.x, event.y)
        match region:
            case "cell":
                self.click_on_cell()

    def click_on_header(self, event):
        column = self.table.identify_column(event.x)
        match column:
            case "#1":
                self.address_list.sort(key=lambda x: x[int(column[-1]) - 1], reverse=self.sort_order)
                self.populate_table()
            case "#2":
                self.address_list.sort(key=lambda x: x[int(column[-1]) - 1], reverse=self.sort_order)
                self.populate_table()
            case "#3":
                self.address_list.sort(key=lambda x: x[int(column[-1]) - 1], reverse=self.sort_order)
                self.populate_table()
            case "#4":
                self.address_list.sort(key=lambda x: x[int(column[-1]) - 1], reverse=self.sort_order)
                self.populate_table()
            case "#5":
                self.address_list.sort(key=lambda x: x[int(column[-1]) - 1], reverse=self.sort_order)
                self.populate_table()
            case _:
                print(column)
        self.sort_order = not self.sort_order

    def click_on_cell(self):
        self.current_record = self.table.focus()
        values = self.table.item(self.current_record, "values")
        self.open_window_edit_records(values)

    def _load_json_file(self):
        try:
            with open(self.json_file, "r", encoding="utf-8") as f:
                self.address_list = json.load(f)
                self.address_list.sort(key=lambda x: (x[0], x[1]))
        except FileNotFoundError:
            show_error(
                message_title="Datei nicht gefunden",
                message=f"{self.json_file_name} nicht gefunden, erstelle leere Datei unter {self.json_path}",
                parent=self.root
            )
            self.address_list = [["", "firma", "name", "adresse", "plz/ort"]]
            with open(self.json_file, "w", encoding="utf-8") as f:
                json.dump(self.address_list, f)
        self.populate_table()

    def _save_json_file(self):
        self.export_table_to_address_list()
        try:
            with open(self.json_file, "w", encoding="utf-8") as f:
                json.dump(self.address_list, f, indent=4, sort_keys=True)
        except FileNotFoundError:
            show_error(
                message_title="Unexpected Error: File not found?!",
                message=f"{self.json_file_name} not found",
                parent=self.root
            )

    def export_csv(self):
        try:
            with open(self.csv_file, "w", encoding="utf-8") as f:
                writer = csv.writer(f, delimiter=",")
                for address in self.address_list:
                    if address[0] != "x":
                        continue
                    del address[0]
                    if address[0] == "":
                        del address[0]
                    writer.writerow(address)
        except FileNotFoundError:
            show_error(message_title="Unexpected error",
                       message=f"Could not write file {self.csv_file}",
                       parent=self.root
                       )

    def populate_table(self):
        self.delete_all_table_items()
        for index, item in enumerate(self.address_list):
            self.table.insert('', 'end', iid=index, values=item)

    def export_table_to_address_list(self):
        self.address_list.clear()
        for child in self.table.get_children():
            self.address_list.append([])
            for value in self.table.item(child)['values']:
                self.address_list[-1].append(value)

    def delete_all_table_items(self):
        for item in self.table.get_children():
            self.table.delete(item)

    def open_window_settings(self):
        window = SettingsWindow(self, self.root)
        window.wm_transient(self.root)
        window.wait_visibility()
        window.grab_set()
        return window

    def open_window_edit_records(self, data):
        window = EditRecord(self, self.root, data)
        window.wm_transient(self.root)
        window.wait_visibility()
        window.grab_set()




if __name__ == '__main__':
    Application()
