# Window.py -- Pamhyr
# Copyright (C) 2023  INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

# -*- coding: utf-8 -*-

import logging

from copy import deepcopy

from config import Config
from View.Tools.PamhyrWindow import PamhyrDialog
from View.Tools.PamhyrTable import PamhyrTableModel

from View.Stricklers.Table import TableModel
from View.Stricklers.translate import StricklersTranslate
from View.Stricklers.UndoCommand import *

from View.Configure.Translate import ConfigureTranslate
from View.Configure.Solver.Window import ConfigureSolverWindow

from PyQt5.QtGui import (
    QKeySequence,
)

from PyQt5.QtCore import (
    Qt, QVariant, QAbstractTableModel,
)

from PyQt5.QtWidgets import (
    QDialogButtonBox, QPushButton, QLineEdit,
    QFileDialog, QTableView, QAbstractItemView,
    QComboBox, QUndoStack, QShortcut, QHeaderView,
)

from Solver.Solvers import solver_long_name

logger = logging.getLogger()


class SolverTableModel(PamhyrTableModel):
    def data(self, index, role):
        if role != Qt.ItemDataRole.DisplayRole:
            return QVariant()

        ret = self._data[index.row()][self._headers[index.column()]]

        if self._headers[index.column()] == "type":
            ret = solver_long_name[ret]

        return ret

    def removeRow(self, index):
        del self._data[index.row()]
        self.layoutChanged.emit()

    def add_solver(self, solver):
        self._data.append(solver)
        self.layoutChanged.emit()

    def change_solver(self, solver, index):
        self._data[index.row()] = solver
        self.layoutChanged.emit()


class ConfigureWindow(PamhyrDialog):
    _pamhyr_ui = "ConfigureDialog"
    _pamhyr_name = "Configure"

    def __init__(self, config=None, parent=None):
        if config is None:
            config = Config()

        trad = ConfigureTranslate()

        super(ConfigureWindow, self).__init__(
            title=trad[self._pamhyr_name],
            config=config,
            trad=trad,
            options=[],
            parent=parent
        )

        self._trad_stricklers = StricklersTranslate()

        self.setup_custom_sc()
        self.setup_solver()
        self.setup_stricklers()
        self.setup_data()
        self.setup_connection()

    def setup_solver(self):
        table = self.find(QTableView, "tableView_solver")
        self.solver_table_model = SolverTableModel(
            table_view=table,
            table_headers=self._trad.get_dict("table_headers"),
            data=self._config.solvers
        )

    def setup_stricklers(self):
        table = self.find(QTableView, f"tableView_stricklers")
        self._stricklers = deepcopy(self._config.stricklers)
        self._stricklers_table = TableModel(
            table_view=table,
            table_headers=self._trad_stricklers.get_dict("table_headers"),
            editable_headers=["name", "comment", "minor", "medium"],
            data=self._stricklers,
            undo=self._undo_stack,
        )

    def setup_data(self):
        # # Meshing_Tool
        # self.set_line_edit_text("lineEdit_meshing_tool",
        #                         self._config.meshing_tool)

        # Const
        self.set_line_edit_text("lineEdit_segment", str(self._config.segment))
        self.set_line_edit_text("lineEdit_max_listing",
                                str(self._config.max_listing))

        # Backup
        self.set_check_box("checkBox_backup", self._config.backup_enable)
        self.set_line_edit_text("lineEdit_backup_path",
                                self._config.backup_path)
        self.set_time_edit("timeEdit_backup_frequence",
                           self._config.backup_frequence)
        self.set_spin_box("spinBox_backup_max", self._config.backup_max)

        # Editor
        self.set_line_edit_text("lineEdit_editor_cmd",
                                str(self._config.editor))

        # Language
        languages = Config.languages()
        for lang in languages:
            self.combobox_add_item("comboBox_language", lang)
            if self._config.lang == languages[lang]:
                self.set_combobox_text("comboBox_language", lang)

    def setup_custom_sc(self):
        self._debug_sc = QShortcut(QKeySequence("Ctrl+G"), self)
        self._debug_sc.activated.connect(self.set_debug)

    def setup_connection(self):
        buttons = {
            # Solvers
            "pushButton_solver_add": self.add_solver,
            "pushButton_solver_del": self.remove_solver,
            "pushButton_solver_edit": self.edit_solver,
            # Stricklers
            "pushButton_stricklers_add": self.add_stricklers,
            "pushButton_stricklers_del": self.del_stricklers,
            "pushButton_stricklers_sort": self.sort_stricklers,
            # Others
            "pushButton_backup_path": lambda: self.file_dialog(
                select_file=False,
                callback=lambda f: self.set_line_edit_text(
                    "lineEdit_backup_path", f[0]
                )
            ),
            # "pushButton_meshing_tool": lambda: self.file_dialog(
            #     select_file=True,
            #     callback=lambda f: self.set_line_edit_text(
            #         "lineEdit_meshing_tool", f[0]
            #     )
            # ),
        }

        for button in buttons:
            self.find(QPushButton, button).clicked.connect(buttons[button])

    def accept(self):
        # Solvers
        self._config.solvers = self.solver_table_model._data.copy()

        # # Meshing_Tool
        # self._config.meshing_tool = self.get_line_edit_text(
        #     "lineEdit_meshing_tool")

        # Const
        self._config.segment = self.get_line_edit_text("lineEdit_segment")
        self._config.max_listing = self.get_line_edit_text(
            "lineEdit_max_listing")

        # Backup
        self._config.backup_enable = self.get_check_box("checkBox_backup")
        self._config.backup_path = self.get_line_edit_text(
            "lineEdit_backup_path")
        self._config.backup_frequence = self.get_time_edit(
            "timeEdit_backup_frequence")
        self._config.backup_max = self.get_spin_box("spinBox_backup_max")

        # Stricklers
        self._config.stricklers = deepcopy(self._stricklers)

        # Editor
        self._config.editor = self.get_line_edit_text("lineEdit_editor_cmd")

        # Language
        self._config.lang = Config.languages(
        )[self.get_combobox_text("comboBox_language")]

        self.end()

    def reject(self):
        # Nothing todo
        self.end()

    def end(self):
        self._config.save()
        self.close()

    # Debug

    def set_debug(self):
        self._config.debug = not self._config.debug
        logger.info(f"Debug mode set : {self._config.debug}")
        self.parent.setup_debug_mode()

    # Solvers

    def edit_solver(self):
        indexes = self.find(
            QTableView, "tableView_solver").selectionModel().selectedRows()
        for index in indexes:
            self.edit_solver = ConfigureSolverWindow(
                data=self.solver_table_model._data[index.row()],
                config=self._config,
                parent=self
            )
            if self.edit_solver.exec_():
                self.solver_table_model.change_solver(
                    self.edit_solver.data, index)

    def add_solver(self):
        dialog_solver = ConfigureSolverWindow(parent=self)
        if dialog_solver.exec_():
            self.solver_table_model.add_solver(dialog_solver.data)

    def remove_solver(self):
        indices = self.find(
            QTableView, "tableView_solver").selectionModel().selectedRows()
        for index in sorted(indices):
            self.solver_table_model.removeRow(index)

    # Stricklers

    def index_selected_rows_strikclers(self):
        table = self.find(QTableView, f"tableView_stricklers")
        return list(
            set(
                map(
                    lambda i: i.row(),
                    table.selectedIndexes()
                )
            )
        )

    def add_stricklers(self):
        rows = self.index_selected_rows_strikclers()
        if len(rows) == 0:
            self._stricklers_table.add(0)
        else:
            self._stricklers_table.add(rows[0])

    def del_stricklers(self):
        rows = self.index_selected_rows_strikclers()
        if len(rows) == 0:
            return

        self._stricklers_table.delete(rows)

    def sort_stricklers(self):
        self._stricklers_table.sort(False)