import tkinter
import tkinter.ttk

import constants
from models import Programme
from widgets import ModuleWidget

# app.py - Main GUI dialog
# TODO: Remove all 'pass' statements and complete the implementation based on class description

class App(tkinter.Tk):
    def __init__(self, db):
        super().__init__()
        self.__db = db
        self.refresh_db()

        self.__programme = None
        self.__modules = None
        self.setup_ui()

    # NOTE: Do not modify this method
    def report_callback_exception(self, *args):
        """When an error is occurred, raise the exception
        so main_gui.py will handle the display of error.
        """
        raise args[1].with_traceback(args[2])

    def refresh_db(self):
        # TODO: Fetch all program records from database, and store it in __programme as a list
        pass

    def setup_ui(self):
        self.title(constants.APP_NAME)
        self.minsize(640, 480)

        # Set weight of column 0 for auto resizing on X axis
        self.columnconfigure(0, weight=1)

        # Header
        frm_top_bar = tkinter.Frame(self)
        frm_top_bar.grid(row=0, sticky=tkinter.EW)
        tkinter.Label(
            frm_top_bar,
            text = constants.APP_NAME,
            font = ('bold', 16)
        ).pack(side = tkinter.LEFT, padx=8, pady=8)
        tkinter.ttk.Separator(self).grid(row=1, sticky=tkinter.EW)

        # Content
        frm_content = tkinter.Frame(self)
        frm_content.grid(row=2, sticky=tkinter.NSEW)
        self.rowconfigure(2, weight=1)

        # Options
        frm_filter = tkinter.LabelFrame(frm_content, text = "Options")
        frm_filter.pack(fill=tkinter.X, side=tkinter.TOP, padx=8, pady=(4, 0))
        frm_filter_container = tkinter.Frame(frm_filter)
        frm_filter_container.pack(fill=tkinter.BOTH, side=tkinter.TOP, padx=6, pady=(0, 4))

        # Options variables
        # TODO: Implement tkinter.StringVar for the widgets in 'Options'

        # Option widgets
        tkinter.Label(
            frm_filter_container,
            text = "Programme",
        ).grid(row=0, column=0, padx=(0, 4), sticky=tkinter.W)
        # TODO: Implement tkinter.OptionMenu __om_programme_filter
        options_list = ["follow methods inside assignment", "follow methods inside assignment 2", "follow methods inside assignment 3", "follow methods inside assignment 4"]
        value_inside = tkinter.StringVar(frm_filter_container)
        question_menu = tkinter.ttk.OptionMenu(frm_filter_container, value_inside, *options_list)
        question_menu.grid(row=0, column=1, padx=(0, 4), sticky=tkinter.W)
        print(question_menu["menu"].keys())

        # Semester select
        tkinter.Label(
            frm_filter_container,
            text = "Semester",
        ).grid(row=0, column=2, padx=(4, 4), sticky=tkinter.W)
        # TODO: Implement tkinter.OptionMenu __om_semester_filter

        # Modules
        frm_modules = tkinter.LabelFrame(frm_content, text = "Modules")
        frm_modules.pack(fill=tkinter.BOTH, side=tkinter.TOP, expand=1, padx=8, pady=(4, 0))
        self.__frm_modules_container = tkinter.Frame(frm_modules)
        self.__frm_modules_container.pack(fill=tkinter.BOTH, side=tkinter.TOP, padx=6, pady=(0, 4))

        self.__module_widgets = list()
        for _ in range(constants.APP_MAX_MODULES):
            widget = ModuleWidget(self.__frm_modules_container, self.on_gpa_changed)
            widget.get_frame().pack(fill=tkinter.X, side=tkinter.TOP, expand=1, pady=8)
            self.__module_widgets.append(widget)

        # Bottom bar
        frm_bottom_bar = tkinter.Frame(self)
        frm_bottom_bar.grid(row=3, sticky=tkinter.EW)

        # Result Label
        # TODO: Implement tkinter.Label __lbl_result

    def setup_module_list(self):
        # TODO: Update the ModuleWidget in list __module_widgets to display
        #       modules for the selected programme and semester
        pass

    def on_programme_changed(self, _):
        # TODO: Get selected programme based on option menu index, and update GUI
        pass

    def on_semester_changed(self, _):
        # TODO: Get modules based on option menu value, and update GUI
        pass

    def on_gpa_changed(self):
        # TODO: Calcuate semester GPA based on self.__modules
        pass
