import logging
import os

from PyQt5.QtGui import QCloseEvent
from PyQt5.QtWidgets import QWidget, QGridLayout, QPushButton, QTableWidget, \
    QTableWidgetItem, QHeaderView, QMessageBox, QFileDialog, QInputDialog

from school_ringer_modules.config import sound_path, config_path
from school_ringer_modules.groups_dataclasses import all_groups_of_calls, GroupOfCalls
from school_ringer_modules.sound import default_sound
from school_ringer_modules.system import run_command


class GroupsEditor(QWidget):
    def __init__(self) -> None:
        """
        Конструктор, создающий экземпляр класса
        """
        super().__init__()
        self.initUI()

    def load_sound(self, row: int, col: int) -> None:
        """
        Выбор, запись в таблицу UI и копирование файла для воспроизведения звонка
        :param row: номер строки
        :param col: номер столбца
        """
        if col != 0:
            options = QFileDialog.Options()
            options |= QFileDialog.DontUseNativeDialog
            fileName, _ = QFileDialog.getOpenFileName(self, "Выберите звуковой файл", "",
                                                      "Sound Files (*.mp3 *.wav *.ogg *.oga)", options=options)
            if fileName:
                file_name_without_path = fileName.split('/')[-1]
                file_name_without_spaces = file_name_without_path.replace(' ', '_')
                if file_name_without_spaces not in os.listdir(f'{sound_path}'):
                    run_command(f'pkexec cp "{fileName}" {sound_path}/{file_name_without_spaces}')
                self.groups_table.item(row, col).setText(file_name_without_spaces)
                logging.info(f'Выбран звуковой файл {file_name_without_path}')

    def load_data(self) -> None:
        """
        Заполнение таблицы UI данными из json-файла
        @rtype: None
        """
        self.groups_table.clear()
        self.groups_table.setRowCount(len(self.groups.groups.keys()) - 1)
        self.groups_table.setHorizontalHeaderLabels(['Название', 'Звук начала', 'Звук окончания', 'Предварительный '
                                                                                                  'звонок'])
        row = 0
        print('Groups after loading data:')
        self.groups.__repr__()
        for group in self.groups.items_to_list():
            if group.name != 'По умолчанию':
                self.groups_table.setItem(row, 0, QTableWidgetItem(group.name))
                self.groups_table.setItem(row, 1, QTableWidgetItem(group.start))
                self.groups_table.setItem(row, 2, QTableWidgetItem(group.end))
                self.groups_table.setItem(row, 3, QTableWidgetItem(group.pre))

                row += 1

        logging.info(f'Таблица групп звонков заполнена данными (без группы по умолчанию):\n{self.groups.groups}')

    def add_row(self) -> None:
        """
        Добавление пустой строки в таблицу с проверкой корректности данных.
        Группа по умолчанию называется Новая группа. Если такая уже есть, предлагается сначала её переименовать.
        :return: None
        """
        new_group_exists = False
        for row in range(self.groups_table.rowCount()):
            if self.groups_table.item(row, 0).text() == 'Новая группа':
                new_group_exists = True

        if new_group_exists:

            dlg = QMessageBox(self)
            dlg.setWindowTitle("Ошибка")
            dlg.setText("Новая группа уже есть. Введите для неё другое название.")
            button = dlg.exec()
            if button == QMessageBox.Ok:
                return

        else:
            self.groups_table.setRowCount(self.groups_table.rowCount() + 1)
            self.groups_table.setItem(self.groups_table.rowCount() - 1, 0, QTableWidgetItem("Новая группа"))
            for column in range(1, 4):
                self.groups_table.setItem(self.groups_table.rowCount() - 1, column, QTableWidgetItem(default_sound()))
            # self.groups.__setitem__("Новая группа",
            #                         GroupOfCalls("Новая группа", default_sound(), default_sound(), default_sound()))
        logging.info(f'groups after add row: {self.groups.groups}')

    def delete_row(self) -> None:
        """
        Удаление строки из таблицы
        :return: None
        """
        row = self.groups_table.currentRow()
        if row < 0:
            return
        item_text = str(self.groups_table.item(row, 0).text())
        messageBox = QMessageBox.warning(
            self,
            "Подтверждение удаления!",
            f"Вы действительно хотите удалить группу {item_text}?",
            QMessageBox.Ok | QMessageBox.Cancel,
        )
        if messageBox == QMessageBox.Ok:
            self.groups.__delitem__(item_text)
            logging.info(f'groups after delete: {self.groups.groups}')
            self.groups_table.removeRow(self.groups_table.currentRow())

    def update_data(self, item: QTableWidgetItem) -> None:
        """
        Обновляет данные о группах после редактирования или импорта с проверкой корректности
        @param item: ячейка, которую редактировали
        @return: None
        """
        # проверка корректности, обновление словаря
        other_groups = ['По умолчанию']
        for i in range(self.groups_table.rowCount()):
            if i != item.row() and self.groups_table.item(i, 0) is not None:
                other_groups.append(self.groups_table.item(i, 0).text())
        logging.info(f'Остальные группы: {other_groups}')

        if self.groups_table.item(item.row(), 0) is None:
            dlg = QMessageBox(self)
            dlg.setWindowTitle("Ошибка")
            dlg.setText("Нельзя редактировать группу без названия.")
            button = dlg.exec()
            if button == QMessageBox.Ok:
                row = item.row()
                for column in range(1, 4):
                    self.groups_table.setItem(row, column, None)
                return

        elif self.groups_table.item(item.row(), 0).text() in other_groups:
            group_name = self.groups_table.item(item.row(), 0).text()
            done1 = True
            while done1 and group_name in other_groups:
                group_name, done1 = QInputDialog.getText(
                    self, 'Ошибка', 'Такая группа уже есть. Введите другое название:')
                if not done1:
                    self.load_data()
                    logging.info(f'Отмена ввода названия группы')
                elif group_name not in other_groups:
                    self.groups_table.item(item.row(), 0).setText(group_name)
                    logging.info(f'Группа переименована в {group_name}')

        elif self.groups_table.item(item.row(), 0).text() == '':
            self.groups_table.item(item.row(), 0).setText("Новая группа")
        try:
            if self.groups_table.item(item.row(), 0).text() not in self.groups.groups.keys() and item.column() > 0:
                name = self.groups_table.item(item.row(), 0).text()
                start = self.groups_table.item(item.row(), 1).text()
                end = self.groups_table.item(item.row(), 2).text()
                pre = self.groups_table.item(item.row(), 3).text()

                # self.groups.__setitem__(name, GroupOfCalls(name, start, end, pre))
                logging.info(f'Установлена новая группа: f{self.groups.groups[name]}')

            else:
                self.groups.clean()
                logging.info(f'groups after recreating: {self.groups.groups}')
                for row in range(self.groups_table.rowCount()):
                    name = self.groups_table.item(row, 0).text()
                    start = self.groups_table.item(row, 1).text()
                    end = self.groups_table.item(row, 2).text()
                    pre = self.groups_table.item(row, 3).text()
                    self.groups.__setitem__(name, GroupOfCalls(name, start, end, pre))
        # это на случай добавления новой строки - чтобы вызывалось add_row
        except Exception:
            logging.info('Ошибка во время редактирования списка групп')
        logging.info(f'groups after update: {self.groups.groups}')
        self.groups.__repr__()
        return

    def get_groups_from_table(self) -> dict:
        """
        Возвращает словарь групп из таблицы + группу По умолчанию
        @return: словарь групп, считанный из таблицы в её текущем состоянии
        """
        temp_groups = {
            "По умолчанию": {
                "name": "По умолчанию",
                "start": default_sound(),
                "end": default_sound(),
                "pre": default_sound()
            }
        }
        for i in range(self.groups_table.rowCount()):
            name = self.groups_table.item(i, 0).text()
            start = self.groups_table.item(i, 1).text()
            end = self.groups_table.item(i, 2).text()
            pre = self.groups_table.item(i, 3).text()
            temp_groups[name] = {
                "name": name,
                "start": start,
                "end": end,
                "pre": pre
            }
        return temp_groups

    def write_groups_to_file(self) -> None:
        """
        Сохраняет группы звонков в файл конфига
        """
        self.groups.write(self.get_groups_from_table())
        self.groups.groups = self.get_groups_from_table()

    def closeEvent(self, event: QCloseEvent) -> None:
        """
        Обработка закрытия окна редактирования групп звонков
        @param event: событие, которое привело к закрытию окна
        """
        tempfile = run_command('mktemp').strip()
        self.groups.write(self.get_groups_from_table(), tempfile)
        if run_command(f'diff {tempfile} {config_path}/groups.json').strip():
            dlg = QMessageBox()
            dlg.setWindowTitle('Внимание!')
            dlg.setText('Сохранить изменения?')
            dlg.setStandardButtons(QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
            pressed_button = dlg.exec()
            if pressed_button == QMessageBox.Cancel:
                event.ignore()
            else:
                if pressed_button == QMessageBox.Yes:
                    self.write_groups_to_file()
                else:
                    self.groups.groups = self.groups.read()
                event.accept()
                self.parent.groups_editor = None

    def initUI(self) -> None:
        """
        Инициализация графического интерфейса
        """
        grid = QGridLayout()
        self.setLayout(grid)

        self.groups_table = QTableWidget()
        self.groups_table.cellClicked.connect(self.load_sound)
        self.groups_table.setColumnCount(4)
        self.groups_table_keys = ["group", "start", "end", "pre"]
        groups_table_headers = ['Название', 'Звук начала', 'Звук окончания', 'Предварительный звонок']
        self.groups_table.setHorizontalHeaderLabels(groups_table_headers)
        self.groups_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.groups_table.setColumnWidth(0, 238)

        self.groups = all_groups_of_calls
        if not self.groups.groups:
            self.groups_table.setRowCount(0)
            dlg = QMessageBox(self)
            dlg.setWindowTitle("Ошибка")
            dlg.setText("Группы звонков не найдены.")
            dlg.exec()
        else:
            self.load_data()
        grid.addWidget(self.groups_table, 0, 0, 1, 3)
        self.groups_table.itemChanged.connect(self.update_data)
        button = QPushButton('Добавить группу')
        button.clicked.connect(self.add_row)
        grid.addWidget(button, 1, 0)

        button = QPushButton('Удалить текущую группу')
        button.clicked.connect(self.delete_row)
        grid.addWidget(button, 1, 1)

        button = QPushButton('Сохранить группы')
        button.clicked.connect(self.write_groups_to_file)
        grid.addWidget(button, 1, 2)

        self.setGeometry(300, 200, 800, 500)
        self.setWindowTitle('Редактирование групп звонков')
        self.show()
