#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
ui_widgets.py

Creates all of the widgets used in NativeUI and stores references to them as attributes
of a single object for ease of reference
"""

__author__ = "Benjamin Mummery"
__credits__ = ["Benjamin Mummery", "Dónal Murray", "Tim Powell", "Tiago Sarmento"]
__license__ = "GPL"
__version__ = "0.0.1"
__maintainer__ = "Benjamin Mummery"
__email__ = "benjamin.mummery@stfc.ac.uk"
__status__ = "Prototype"

import json
import logging
import os
import shutil

from alarm_widgets.alarm_handler import AlarmHandler
from alarm_widgets.alarm_list import AlarmList
from alarm_widgets.alarm_popup import AlarmPopup
from alarm_widgets.alarm_table import AlarmTable
from global_widgets.global_send_popup import SetConfirmPopup
from global_widgets.global_spinbox import labelledSpin
from global_widgets.global_typeval_popup import AbstractTypeValPopup
from global_widgets.tab_hold_buttons import timerConfirmPopup
from global_widgets.tab_modeswitch_button import TabModeswitchButton
from handler_library.maintenance_handler import MaintenanceHandler
from PySide2.QtWidgets import QButtonGroup, QWidget
from widget_library.clinical_explanation_label import ClinicalExplanationLabel
from widget_library.alarm_control_widget import AlarmControlWidget
from widget_library.battery_display_widget import BatteryDisplayWidget
from widget_library.chart_buttons_widget import ChartButtonsWidget
from widget_library.history_buttons_widget import HistoryButtonsWidget
from widget_library.info_display_widgets import (
    MaintenanceTimeDisplayWidget,
    UpdateTimeDisplayWidget,
    UptimeDisplayWidget,
    VersionDisplayWidget,
)
from widget_library.line_edit_widget import LabelledLineEditWidget
from widget_library.localisation_button_widget import LocalisationButtonWidget
from widget_library.localised_base_widgets import (
    LocalisedQLabel,
    LocalisedQPushButton,
    LocalisedQRadioButton,
    LocalisedQStackedWidget,
    LocalisedQWidget,
)
from widget_library.measurements_widget import (
    ExpertMeasurementsBloackWidget,
    NormalMeasurementsBlockWidget,
)
from widget_library.ok_cancel_buttons_widget import (
    CancelButtonWidget,
    OkButtonWidget,
    OkSendButtonWidget,
)
from widget_library.page_buttons_widget import PageButton, PageButtonsWidget
from widget_library.personal_display_widget import PersonalDisplayWidget
from widget_library.plot_widget import (
    ChartsPlotWidget,
    CirclePlotsWidget,
    TimePlotsWidget,
)
from widget_library.spin_buttons_widget import SpinButton
from widget_library.startup_calibration_widget import calibrationWidget
from widget_library.startup_handler import StartupHandler
from widget_library.ventilator_start_stop_buttons_widget import (
    VentilatorStartStopButtonsWidget,
)


class Widgets:
    def __init__(self, NativeUI, *args, **kwargs):
        """
        Creates and stores references to all of the widgets we use.

        Widgets are grouped by pages for convenience, however this class deliberately
        contains no layout logic.
        """
        # NativeUI = NativeUI

        self.widget_list = []

        # Start up procedure
        self.startup_confirm_popup = SetConfirmPopup(NativeUI)
        self.maintenance_confirm_popup = SetConfirmPopup(NativeUI)
        self.startup_handler = StartupHandler(NativeUI, self.startup_confirm_popup)
        self.maintenance_handler = MaintenanceHandler(
            NativeUI, self.maintenance_confirm_popup
        )
        self.localisation_startup_button = LocalisedQPushButton(
            NativeUI, "language_name"
        )
        self.widget_list = self.widget_list + [
            self.startup_confirm_popup,
            self.maintenance_confirm_popup,
            self.startup_handler,
            self.maintenance_handler,
            self.localisation_startup_button,
        ]

        # Import startup_config
        if not os.path.isfile("NativeUI/configs/startup_config.json"):
            logging.warning(
                "startup_config not found. If this is the first time using this "
                "ventilator you can safely ignore this warning."
            )
            shutil.copyfile(
                "NativeUI/configs/startup_config_default.json",
                "NativeUI/configs/startup_config.json",
            )
        with open("NativeUI/configs/startup_config.json") as json_file:
            startupDict = json.load(json_file)
        with open("NativeUI/configs/startup_config_default.json") as json_file:
            startup_dict_default = json.load(json_file)
        for key, procedureDict in startupDict.items():
            if key in startup_dict_default:
                self.add_handled_widget(
                    calibrationWidget(NativeUI, key, procedureDict),
                    key,
                    self.startup_handler,
                )
            else:
                logging.warning(
                    "Key %s in startup_config.json is not present in startup_config_default.json and will be ignored.",
                    key,
                )
        for key in startup_dict_default:
            if key not in startupDict:
                logging.error(
                    "Expected key %s is absent from startup_config.json.", key
                )

        # Import maintanence_config
        if not os.path.isfile("NativeUI/configs/maintenance_config.json"):
            logging.warning(
                "maintenance_config not found. If this is the first time using this "
                "ventilator you can safely ignore this warning."
            )
            shutil.copyfile(
                "NativeUI/configs/maintenance_config_default.json",
                "NativeUI/configs/maintenance_config.json",
            )
        with open("NativeUI/configs/maintenance_config.json") as json_file:
            maintenanceDict = json.load(json_file)
        for key, procedureDict in maintenanceDict.items():
            self.add_handled_widget(
                calibrationWidget(NativeUI, key, procedureDict),
                key,
                self.maintenance_handler,
            )

        for mode in NativeUI.modeList:
            self.add_handled_widget(
                LocalisedQRadioButton(mode),
                "startup_radio_" + mode,
                self.startup_handler,
            )

        self.add_handled_widget(
            OkButtonWidget(NativeUI), "startup_nextButton", self.startup_handler
        )
        self.startup_nextButton.setColour(0)

        self.add_handled_widget(
            CancelButtonWidget(NativeUI), "startup_backButton", self.startup_handler
        )
        self.startup_backButton.setColour(1)

        # Top bar widgets
        self.tab_modeswitch = TabModeswitchButton(NativeUI)
        self.battery_display = BatteryDisplayWidget(NativeUI)
        self.personal_display = PersonalDisplayWidget(NativeUI)
        self.localisation_button = LocalisationButtonWidget(
            NativeUI.localisation_files, NativeUI.colors
        )
        self.alarm_control = AlarmControlWidget(NativeUI)
        self.alarm_control_startup = AlarmControlWidget(NativeUI, test=True)
        self.widget_list = self.widget_list + [
            self.tab_modeswitch,
            self.battery_display,
            self.personal_display,
            self.localisation_button,
            self.alarm_control,
            self.alarm_control_startup,
        ]

        # Left Bar widgets
        self.standby_timer = timerConfirmPopup(NativeUI, "popup_hold_standby")
        self.stop_timer = timerConfirmPopup(NativeUI, "popup_hold_stop")
        self.page_buttons = PageButtonsWidget(NativeUI)
        self.ventilator_start_stop_buttons_widget = VentilatorStartStopButtonsWidget(
            NativeUI, self.standby_timer, self.stop_timer
        )
        self.lock_button = PageButton(
            NativeUI, "", signal_value="lock_screen", icon=NativeUI.icons["lock_screen"]
        )
        self.widget_list = self.widget_list + [
            self.standby_timer,
            self.stop_timer,
            self.page_buttons,
            self.ventilator_start_stop_buttons_widget,
            self.lock_button,
        ]

        # Main Page Widgets
        self.history_buttons = HistoryButtonsWidget(NativeUI)
        self.normal_plots = TimePlotsWidget(NativeUI)
        self.detailed_plots = TimePlotsWidget(NativeUI)
        self.normal_measurements = NormalMeasurementsBlockWidget(NativeUI)
        self.circle_plots = CirclePlotsWidget(NativeUI)
        self.detailed_measurements = ExpertMeasurementsBloackWidget(NativeUI)
        self.widget_list = self.widget_list + [
            self.history_buttons,
            self.normal_plots,
            self.normal_measurements,
            self.circle_plots,
            self.detailed_measurements,
        ]

        # Alarm Page Widgets
        self.alarm_handler = AlarmHandler(NativeUI)
        self.alarm_popup = AlarmPopup(NativeUI)
        self.alarm_list = AlarmList(NativeUI)
        self.acknowledge_button = LocalisedQPushButton(
            NativeUI, "button_label_alarms_list_reset_alarms"
        )
        self.alarm_table = AlarmTable(NativeUI)
        self.clinical_tab = LocalisedQWidget()  # TabClinical(NativeUI)
        self.widget_list = self.widget_list + [
            self.alarm_handler,
            self.alarm_popup,
            self.alarm_list,
            self.acknowledge_button,
            self.alarm_table,
            self.clinical_tab,
        ]

        ### Alarm limits
        self.clinical_explanation_label = ClinicalExplanationLabel(NativeUI)
        self.widget_list.append(self.clinical_explanation_label)
        with open("NativeUI/configs/clinical_config.json") as json_file:
            clinicalDict = json.load(json_file)

        for setting in clinicalDict["settings"]:
            attrName = "clinical_spin_" + setting[0][2]
            if len(setting) == 1:
                self.add_handled_widget(
                    labelledSpin(NativeUI, NativeUI.typeValPopupNum, setting[0]),
                    attrName + "_lim",
                    NativeUI.clinical_handler,
                )
            if len(setting) >= 2:
                self.add_handled_widget(
                    labelledSpin(NativeUI, NativeUI.typeValPopupNum, setting[0]),
                    attrName + "_min",
                    NativeUI.clinical_handler,
                )
                setting[-1][0] = ""
                self.add_handled_widget(
                    labelledSpin(NativeUI, NativeUI.typeValPopupNum, setting[-1]),
                    attrName + "_max",
                    NativeUI.clinical_handler,
                )
                if len(setting) == 3:
                    setting[1][0] = ""
                    self.add_handled_widget(
                        labelledSpin(NativeUI, NativeUI.typeValPopupNum, setting[1]),
                        attrName + "_set",
                        NativeUI.clinical_handler,
                    )

        self.add_handled_widget(
            OkButtonWidget(NativeUI), "clinical_ok_button", NativeUI.clinical_handler
        )
        self.add_handled_widget(
            CancelButtonWidget(NativeUI),
            "clinical_cancel_button",
            NativeUI.clinical_handler,
        )

        #### Mode settings tab: Mode (x4), Personal

        # Modes Page Widgets
        with open("NativeUI/configs/mode_config.json") as json_file:
            modeDict = json.load(json_file)

        radioSettings = modeDict["radioSettings"]
        modes = NativeUI.modeList

        self.add_handled_widget(
            LocalisedQStackedWidget(), "main_mode_stack", NativeUI.mode_handler
        )
        for setting in modeDict["settings"]:
            if setting[0] in modeDict["mainPageSettings"]:
                attrName = "CURRENT_" + setting[2]
                self.add_handled_widget(
                    SpinButton(NativeUI, NativeUI.typeValPopupNum, setting),
                    attrName,
                    NativeUI.mode_handler,
                )

        self.add_handled_widget(
            OkButtonWidget(NativeUI), "CURRENT_ok_button", NativeUI.mode_handler
        )
        self.add_handled_widget(
            CancelButtonWidget(NativeUI), "CURRENT_cancel_button", NativeUI.mode_handler
        )

        self.groupDict = {}
        for mode in modes:
            for startup in ["", "_startup"]:
                self.groupDict[mode + startup] = QButtonGroup()
                for setting in modeDict["settings"]:
                    attrName = mode + startup + "_" + setting[2]
                    targettedSetting = [
                        target.replace(
                            "SET_TARGET_",
                            "SET_TARGET_" + mode.replace("/", "_").replace("-", "_"),
                        )
                        if isinstance(target, str)
                        else target
                        for target in setting
                    ]
                    if startup == "_startup":
                        self.add_handled_widget(
                            labelledSpin(
                                NativeUI, NativeUI.typeValPopupNum, targettedSetting
                            ),
                            "spin_" + attrName,
                            self.startup_handler,
                        )
                    else:
                        self.add_handled_widget(
                            labelledSpin(
                                NativeUI, NativeUI.typeValPopupNum, targettedSetting
                            ),
                            "spin_" + attrName,
                            NativeUI.mode_handler,
                        )

                    if setting[0] in radioSettings:
                        radioButton = LocalisedQRadioButton()
                        self.groupDict[mode + startup].addButton(radioButton)
                        if startup == "_startup":
                            self.add_handled_widget(
                                radioButton, "radio_" + attrName, self.startup_handler
                            )
                        else:
                            self.add_handled_widget(
                                radioButton, "radio_" + attrName, NativeUI.mode_handler
                            )

                if startup != "_startup":
                    self.add_handled_widget(
                        OkButtonWidget(NativeUI),
                        "ok_button_" + mode,
                        NativeUI.mode_handler,
                    )
                    self.add_handled_widget(
                        OkSendButtonWidget(NativeUI),
                        "ok_send_button_" + mode,
                        NativeUI.mode_handler,
                    )
                    self.add_handled_widget(
                        CancelButtonWidget(NativeUI),
                        "cancel_button_" + mode,
                        NativeUI.mode_handler,
                    )

        # Personal tab widgets
        # self.personal_confirm_popup = SetConfirmPopup(NativeUI)
        # NativeUI.personal_handler = PersonalHandler(NativeUI, self.personal_confirm_popup)

        with open("NativeUI/configs/personal_config.json") as json_file:
            personalDict = json.load(json_file)
        textBoxes = personalDict["textBoxes"]
        for startup in ["", "startup_"]:
            for setting in personalDict["settings"]:
                attrName = "personal_edit_" + setting[2]
                if setting[0] in textBoxes:
                    if startup == "startup_":
                        self.add_handled_widget(
                            LabelledLineEditWidget(
                                NativeUI, NativeUI.typeValPopupAlpha, setting
                            ),
                            "text_" + startup + attrName,
                            self.startup_handler,
                        )
                    else:
                        self.add_handled_widget(
                            LabelledLineEditWidget(
                                NativeUI, NativeUI.typeValPopupAlpha, setting
                            ),
                            "text_" + startup + attrName,
                            NativeUI.personal_handler,
                        )
                else:
                    if startup == "startup_":
                        self.add_handled_widget(
                            labelledSpin(NativeUI, NativeUI.typeValPopupNum, setting),
                            "spin_" + startup + attrName,
                            self.startup_handler,
                        )
                    else:
                        self.add_handled_widget(
                            labelledSpin(NativeUI, NativeUI.typeValPopupNum, setting),
                            "spin_" + startup + attrName,
                            NativeUI.personal_handler,
                        )

        self.add_handled_widget(
            OkButtonWidget(NativeUI), "ok_button_personal", NativeUI.personal_handler
        )
        self.add_handled_widget(
            OkSendButtonWidget(NativeUI),
            "ok_send_button_personal",
            NativeUI.personal_handler,
        )
        self.add_handled_widget(
            CancelButtonWidget(NativeUI),
            "cancel_button_personal",
            NativeUI.personal_handler,
        )

        ##### Settings Tab: Expert and Charts tabs
        self.add_widget(LocalisedQStackedWidget(), "expert_passlock_stack")
        self.add_handled_widget(
            AbstractTypeValPopup(NativeUI, "alpha"),
            "expert_password_widget",
            NativeUI.expert_handler,
        )

        # Expert Tab
        with open("NativeUI/configs/expert_config.json") as json_file:
            controlDict = json.load(json_file)

        for key in controlDict:

            self.add_widget(LocalisedQLabel(key), "expert_label_" + key)
            for setting in controlDict[key]:
                attrName = "expert_spin_" + setting[2]
                self.add_handled_widget(
                    labelledSpin(NativeUI, NativeUI.typeValPopupNum, setting),
                    attrName,
                    NativeUI.expert_handler,
                )

        self.add_handled_widget(
            OkButtonWidget(NativeUI), "ok_button_expert", NativeUI.expert_handler
        )
        self.add_handled_widget(
            OkSendButtonWidget(NativeUI),
            "ok_send_button_expert",
            NativeUI.expert_handler,
        )
        self.add_handled_widget(
            CancelButtonWidget(NativeUI),
            "cancel_button_expert",
            NativeUI.expert_handler,
        )

        # Chart Tab
        # self.charts_widget = ChartsPlotWidget(colors=NativeUI.colors)
        # self.chart_buttons_widget = ChartButtonsWidget(colors=NativeUI.colors)
        # self.widget_list = self.widget_list + [
        #     self.charts_widget,
        #     self.chart_buttons_widget,
        # ]

        # Info Tab
        self.version_display_widget = VersionDisplayWidget(NativeUI.colors)
        self.uptime_display_widget = UptimeDisplayWidget(NativeUI.colors)
        self.maintenance_time_display_widget = MaintenanceTimeDisplayWidget(
            NativeUI.colors
        )
        self.update_time_display_widget = UpdateTimeDisplayWidget(NativeUI.colors)
        self.widget_list = self.widget_list + [
            self.version_display_widget,
            self.uptime_display_widget,
            self.maintenance_time_display_widget,
            self.update_time_display_widget,
        ]

    def add_widget(self, widget, name) -> int:
        setattr(self, name, widget)
        self.widget_list.append(getattr(self, name))
        return 0

    def add_handled_widget(self, widget, name, handler) -> int:
        """Add a widget to Widgets and pass it into a handler"""
        setattr(self, name, widget)
        handler.add_widget(widget, name)
        self.widget_list.append(getattr(self, name))
        return 0

    def get_widget(self, name) -> QWidget:
        return getattr(self, name)
