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

import copy
import sys
import csv
from time import time

from tools import trace, timer

from PyQt5.QtGui import (
    QKeySequence,
)
from PyQt5.QtCore import (
    QModelIndex, Qt, QEvent, QCoreApplication
)
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QFileDialog, QCheckBox,
    QUndoStack, QShortcut,
)

from Model.Geometry.Reach import Reach
from Model.Geometry.ProfileXYZ import ProfileXYZ

from View.ASubWindow import WindowToolKit
from View.Geometry.Profile.mainwindow_ui_profile import Ui_MainWindow
from View.Geometry.Profile.Plot import Plot
from View.Geometry.Profile.Table import *

_translate = QCoreApplication.translate


class ProfileWindow(QMainWindow, WindowToolKit):
    def __init__(self, profile=None, parent=None):
        self.parent = parent
        super(ProfileWindow, self).__init__(self.parent)

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self._profile = profile
        self._model = None

        self.setup_window()
        self.setup_sc()
        self.setup_model()
        self.setup_connections()
        self.plot()

        self._model.dataChanged.connect(self.update_plot)
        self.fileName = None

        # self.ui.tableView.installEventFilter(self)
        # self._model.dataChanged.connect(self.tableview_is_modified)

        # self.ui.btn_go_back.setEnabled(False)
        # self.ui.btn_check.setEnabled(False)
        # self._model.dataChanged.connect(self.set_enable_cancel_btn)
        # self._model.dataChanged.connect(self.set_enable_validate_changes_btn)
        # self.ui.btn_reset.setEnabled(False)
        # self._model.dataChanged.connect(self.set_enable_go_back_initial_state_btn)

    def setup_window(self):
        header = _translate("MainWindowProfile", "Profile")

        name = self._profile.name
        if (name is None) or (name == ""):
            name = _translate("MainWindowProfile", "(no name)")

        self.setWindowTitle(
            header + " - " +
            f"{self._profile.reach.name}" + " - " +
            f"{name} ({self._profile.kp})"
        )

    def setup_sc(self):
        self._undo_stack = QUndoStack()

        self.undo_sc = QShortcut(QKeySequence.Undo, self)
        self.redo_sc = QShortcut(QKeySequence.Redo, self)
        self.copy_sc = QShortcut(QKeySequence.Copy, self)
        self.paste_sc = QShortcut(QKeySequence.Paste, self)

    def setup_model(self):
        self._model = TableEditableModel(
            profile = self._profile,
            undo = self._undo_stack
        )

        self.ui.tableView.setModel(self._model)
        self.ui.tableView.setItemDelegate(Delegate())

    def setup_connections(self):
        self.ui.btn_sort_asc_x.triggered.connect(self.sort_X_ascending)
        self.ui.btn_sort_desc_x.triggered.connect(self.sort_X_descending)
        self.ui.btn_sort_asc_y.triggered.connect(self.sort_Y_ascending)
        self.ui.btn_sort_desc_y.triggered.connect(self.sort_Y_descending)
        self.ui.btn_move_up.triggered.connect(self.move_row_up)
        self.ui.btn_move_down.triggered.connect(self.move_row_down)
        self.ui.btn_export.triggered.connect(self.handleSave)
        self.ui.btn_add.triggered.connect(self.insert_row)
        self.ui.btn_delete.triggered.connect(self.delete_row)
        # self.ui.btn_copy.clicked.connect(self.copyTable)
        # self.ui.btn_paste.clicked.connect(self.pasteTable)
        # self.ui.btn_check.clicked.connect(self.validate_changes)
        # self.ui.btn_go_back.clicked.connect(self.cancel_validate_changes)
        # self.ui.btn_reset.clicked.connect(self.go_back_to_initial_state)

        self.undo_sc.activated.connect(self.undo)
        self.redo_sc.activated.connect(self.redo)
        self.copy_sc.activated.connect(self.copy)
        self.paste_sc.activated.connect(self.paste)

    def plot(self):
        self.ui.tableView.model().blockSignals(True)

        self._plot = Plot(
            canvas = self.ui.canvas,
            data = self._profile,
            toolbar = None,
            table = self.ui.tableView,
        )
        self._plot.draw()

        self.ui.tableView.model().blockSignals(False)

    def update_plot(self):
        self.ui.tableView.model().blockSignals(True)

        # TODO: Do not rebuild all graph
        self._plot.update()

        self.ui.tableView.model().blockSignals(False)

    def index_selected_row(self):
        rows = self.ui.tableView\
                      .selectionModel()\
                      .selectedRows()
        if len(rows) == 0:
            return 0

        return self.ui.tableView\
                      .selectionModel()\
                      .selectedRows()[0]\
                      .row()

    def insert_row(self):
        if len(self.ui.tableView.selectedIndexes()) == 0:
            self._model.insert_row(self._model.rowCount())
        else:
            row = self.index_selected_row()
            self._model.insert_row(row + 1)
        self.update_plot()

    def delete_row(self):
        rows = sorted(
            list(
                set(
                    [index.row() for index in self.ui.tableView.selectedIndexes()]
                )
            )
        )

        if len(rows) > 0:
            self._model.remove_rows(rows)
            self.update_plot()

    def sort_X_ascending(self):
        self._model.sort('x', order=Qt.AscendingOrder)
        self.update_plot()

    def sort_X_descending(self):
        self._model.sort('x', order=Qt.DescendingOrder)
        self.update_plot()

    def sort_Y_ascending(self):
        self._model.sort('y', order=Qt.AscendingOrder)
        self.update_plot()

    def sort_Y_descending(self):
        self._model.sort('y', order=Qt.DescendingOrder)
        self.update_plot()

    def move_row_down(self):
        rows = list(
            set(
                [index.row() for index in self.ui.tableView.selectedIndexes()]
            )
        )

        for row in rows:
            if row < self._model.rowCount() - 1:
                self._model.move_row_down(row)

        self.update_plot()

    def move_row_up(self):
        rows = list(
            set(
                [index.row() for index in self.ui.tableView.selectedIndexes()]
            )
        )

        for row in rows:
            if 0 < row:
                self._model.move_row_up(row)

        self.update_plot()

    def copy(self):
        rows = self.ui.tableView\
                      .selectionModel()\
                      .selectedRows()
        table = []
        table.append(["x", "y", "z", "name"])

        for row in rows:
            point = self._profile.point(row.row())
            table.append(
                [
                    point.x, point.y, point.z, point.name
                ]
            )

        self.copyTableIntoClipboard(table)

    def paste(self):
        header, data = self.parseClipboardTable()

        if len(data) == 0:
            return

        if len(header) != 0:
            header.append("profile")
        for row in data:
            row.append(self._profile)

        row = self.index_selected_row()
        self._model.paste(row, header, data)
        self.update_plot()

    def undo(self):
        self._model.undo()
        self.update_plot()

    def redo(self):
        self._model.redo()
        self.update_plot()

    def handleSave(self):
        if self.fileName is None or self.fileName == '':
            self.fileName, self.filters = QFileDialog.getSaveFileName(
                self, filter="CSV files (*.csv)"
            )

        if self.fileName != '':
            with open(self.fileName, 'w') as stream:
                csvout = csv.writer(stream, delimiter='\t', quotechar=' ',
                                    escapechar=None,
                                    quoting=csv.QUOTE_NONNUMERIC,
                                    lineterminator='\n')

                for row in range(self._model.rowCount(QModelIndex())):
                    rowdata = []
                    for column in range(self._model.columnCount(QModelIndex())):
                        item = self._model.index(
                            row, column, QModelIndex()
                        ).data(Qt.DisplayRole)

                        if item is not None:
                            rowdata.append(item)

                        if item == 'nan':
                            rowdata.remove(item)

                    csvout.writerow(rowdata)

    def handleOpen(self):
        self.fileName, self.filterName = QFileDialog.getOpenFileName(self)

        if self.fileName != '':
            with open(self.fileName, 'r') as f:
                reader = csv.reader(f, delimiter='\t')
                header = next(reader)

                buf = []
                for row in reader:
                    row[0] = QCheckBox("-")
                    buf.append(row)

                self._model = None
                self._model = TableEditableModel(buf)
                self.ui.tableView.setModel(self._model)
                self.fileName = ''

    def set_enable_validate_changes_btn(self):
        self.ui.btn_check.setEnabled(True)

    def set_enable_cancel_btn(self):
        self.ui.btn_go_back.setEnabled(True)

    def set_enable_go_back_initial_state_btn(self):
        self.ui.btn_reset.setEnabled(True)

    def delete_empty_rows(self):
        if self._model.data_contains_nan():
            buttonReply = QtWidgets.QMessageBox.question(
                self,
                _translate("MainWindowProfile",
                           "Suppression les lignes incomplètes"),
                _translate("MainWindowProfile",
                           "Supprimer les lignes des cellules"
                           " non renseignées ?"),
                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
            )

            if buttonReply == QtWidgets.QMessageBox.Yes:
                self._model.delete_empty_rows()

            if buttonReply == QtWidgets.QMessageBox.No:
                pass

    def remove_duplicates_point_names(self):
        counter_list = []
        list_deleted_names = []

        for ind, name_point in enumerate(self._model.name):
            if name_point not in counter_list:
                counter_list.append(name_point)
            elif len(name_point.strip()) > 0 and name_point in counter_list:
                if name_point not in list_deleted_names:
                    list_deleted_names.append(name_point)

        if list_deleted_names:
            self.msg_box_check_duplication_names(list_deleted_names)

    def closeEvent(self, event):
        print("TODO: Close")
        # if self.status_change_tableview:
        #     reply = QtWidgets.QMessageBox.question(
        #         self,
        #         _translate("MainWindowProfile", "Terminer l'édition du profil "),
        #         _translate("MainWindowProfile", "Voulez-vous vraiment quitter "
        #                    "?\n Oui : Valider et quitter\n"
        #                    "Non : Annuler"),
        #         QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
        #     )

        #     if reply == QtWidgets.QMessageBox.Yes:
        #         self.validate_changes()
        #         self.plot()
        #         event.accept()
        #     else:
        #         event.ignore()
        #         self.ui.btn_check.setEnabled(True)
        #         self.ui.btn_go_back.setEnabled(True)

    def msg_box_check_duplication_names(self, list_deleted_names):  # name_point,list_deleted_names,counter_list):
        if len(list_deleted_names) == 1:
            text = _translate("MainWindowProfile",
                              "Le nom ''{}'' est dupliqué."
                              " \n\nYes : Ne garder que la première occurrence. \nNo :"
                              " Annuler la suppression.".format(list_deleted_names[0]))
        else:
            text = _translate("MainWindowProfile",
                              "Les noms suivants :  \n{} sont dupliqués"
                              "  \n\nYes : Ne garder que la première occurrence de "
                              "chaque nom. \nNo :"
                              " Annuler la suppression.".format(list_deleted_names))

        buttonReply = QtWidgets.QMessageBox.question(
            self, _translate("MainWindowProfile",
                             "Suppression des noms répétés"),
            text,
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
        )

        if buttonReply == QtWidgets.QMessageBox.Yes:
            self._model.remove_duplicates_names()

    def ask_quit(self):
        choice = QtWidgets.QMessageBox.question(
            self,
            _translate("MainWindowProfile", "Quittez ?"),
            _translate("MainWindowProfile",
                       "Etes-vous sûr de vouloir quitter ?"),
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
        )
        return choice == QtWidgets.QMessageBox.Yes

    def initial_state_model(self, profile_initial_state):
        return profile_initial_state