from PyQt5.QtWidgets import QMainWindow, QMessageBox, QApplication, QMenu
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QBrush, QColor
from PyQt5.QtCore import pyqtSlot, QEvent, Qt
import sys

sys.path.append('../')
from common.globals import *
from client.main_window_ui import Ui_MainWindow

LOGGER = logging.getLogger('client')


class ClientMainWindow(QMainWindow):
    def __init__(self, database, transport):
        super().__init__()

        # основные переменные
        self.database = database
        self.transport = transport

        # Загружаем конфигурацию окна из дизайнера
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # Кнопка "Выход"
        # self.ui.menu_exit.triggered.connect(qApp.exit)

        # Кнопка отправить сообщение
        self.ui.EnterBT.clicked.connect(self.send_message)

        # Панель пользователей и контактов
        # self.ui.usersTab.installEventFilter(self)

        self.ui.UserList.installEventFilter(self)
        self.ui.UpdateUsersBT.clicked.connect(self.update_lists)

        self.ui.ContactList.installEventFilter(self)
        self.ui.UpdateContsBT.clicked.connect(self.update_lists)

        # "добавить контакт"
        # self.ui.add_contact_context = QListWidget()
        # self.ui.add_contact_context.addItem('Добавить контакт')
        # self.ui.UserList.contextMenuEvent.connect(self.add_contact_context)

        # self.ui.UserList.customContextMenuRequested.connect(self.add_contact_context)
        # QObject.connect(self.pushButton, PYQT_SIGNAL("clicked()"), self.add_contact_context)
        # self.ui.btn_add_contact.clicked.connect(self.add_contact_window)
        # self.ui.menu_add_contact.triggered.connect(self.add_contact_window)

        # Удалить контакт

        # self.ui.btn_remove_contact.clicked.connect(self.delete_contact_window)
        # self.ui.menu_del_contact.triggered.connect(self.delete_contact_window)

        # Дополнительные требующиеся атрибуты
        self.contacts_model = None
        self.users_model = None
        self.history_model = None
        self.messages = QMessageBox()
        self.current_chat = None  # Текущий контакт с которым идёт обмен сообщениями
        self.ui.MsgField.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.ui.MsgField.setWordWrap(True)

        # Double click по списку контактов отправляется в обработчик
        self.ui.ContactList.doubleClicked.connect(self.select_active_user)

        self.update_contacts_list()
        self.update_users_list()
        self.set_disabled_input()
        self.show()

    def eventFilter(self, source, event):
        if event.type() == QEvent.ContextMenu:
            # print(source.indexAt(event.pos()))
            if source is self.ui.UserList:
                menu = QMenu()
                menu.addAction('Добавить контакт')
                try:
                    if menu.exec_(event.globalPos()):
                        item = source.indexAt(event.pos())
                        LOGGER.debug(f'Добавляю контакт: {item.data()}')
                        if item and not self.database.check_contact(item.data()):
                            self.ui.usersTab.setCurrentIndex(1)
                            self.transport.add_contact(item.data())
                            self.update_contacts_list()
                    return True
                except Exception as e:
                    LOGGER.error(f'Не удалось добавить контакт: {e}')

            if source is self.ui.ContactList:
                menu = QMenu()
                menu.addAction('Удалить контакт')
                try:
                    if menu.exec_(event.globalPos()):
                        item = source.indexAt(event.pos())
                        LOGGER.debug(f'Удаляю контакт: {item.data()}')
                        if item and self.database.check_contact(item.data()):
                            self.transport.del_contact(item.data())
                            self.update_contacts_list()
                    return True
                except Exception as e:
                    LOGGER.error(f'Не удалось удалить контакт: {e}')
        return super().eventFilter(source, event)

    # Деактивировать поля ввода
    def set_disabled_input(self):
        # Надпись  - получатель.
        self.ui.ContactName.setText('Выберите пользователя')
        self.ui.EnterTE.clear()
        if self.history_model:
            self.history_model.clear()

        # Поле ввода и кнопка отправки неактивны до выбора получателя.
        self.ui.EnterBT.setDisabled(True)
        self.ui.EnterTE.setDisabled(True)

    def update_lists(self):
        if self.ui.usersTab.currentWidget().objectName() == 'Users':
            self.transport.update_db_list(USER_LIST)
            self.update_users_list()
        elif self.ui.usersTab.currentWidget().objectName() == 'Conts':
            self.transport.update_db_list(GET_CONTACTS)
            self.update_contacts_list()
        # print(self.ui.usersTab.currentWidget().objectName())

    # Функция, обновляющая контакт-лист
    def update_contacts_list(self):
        LOGGER.debug('Запрос скиска контактов')
        contacts_list = self.database.get_contacts()
        self.contacts_model = QStandardItemModel()
        for i in sorted(contacts_list):
            item = QStandardItem(i)
            item.setEditable(False)
            self.contacts_model.appendRow(item)
        self.ui.ContactList.setModel(self.contacts_model)

    # Функция, обновляющая лист пользователей
    def update_users_list(self):
        LOGGER.debug('Запрос скиска пользователей')
        users_list = self.database.get_users()
        self.users_model = QStandardItemModel()
        for i in sorted(users_list):
            item = QStandardItem(i)
            item.setEditable(False)
            self.users_model.appendRow(item)
        self.ui.UserList.setModel(self.users_model)

    # Функция обработчик double click по контакту
    def select_active_user(self):
        # Выбранный пользователем контакт находится в выделенном элементе в QListView
        self.current_chat = self.ui.ContactList.currentIndex().data()
        # вызываем основную функцию
        self.set_active_user()

    # Функция, устанавливающая активного собеседника
    def set_active_user(self):
        # Ставим надпись и активируем кнопки
        self.ui.ContactName.setText(self.current_chat)
        self.ui.EnterBT.setDisabled(False)
        self.ui.EnterTE.setDisabled(False)

        # Заполняем окно историю сообщений по требуемому пользователю.
        self.history_list_update()

    # Функция отправки сообщения пользователю.
    def send_message(self):
        # Текст в поле, проверяем что поле не пустое затем забирается сообщение и поле очищается
        msg_text = self.ui.EnterTE.toPlainText()
        self.ui.EnterTE.clear()
        if not msg_text:
            return
        self.transport.send_text_message(self.current_chat, msg_text)
        self.history_list_update()
        # try:
        #     self.transport.send_text_message(self.current_chat, message_text)
        # except ServerError as err:
        #     self.messages.critical(self, 'Ошибка', err.text)
        # except OSError as err:
        #     if err.errno:
        #         self.messages.critical(self, 'Ошибка', 'Потеряно соединение с сервером!')
        #         self.close()
        #     self.messages.critical(self, 'Ошибка', 'Таймаут соединения!')
        # except (ConnectionResetError, ConnectionAbortedError):
        #     self.messages.critical(self, 'Ошибка', 'Потеряно соединение с сервером!')
        #     self.close()
        # else:
        #     self.database.save_message(self.current_chat, 'o', message_text)
        #     LOGGER.debug(f'Отправлено сообщение для {self.current_chat}: {message_text}')
            # self.history_list_update()

    # Заполняем историю сообщений.
    def history_list_update(self):
        # Получаем историю сортированную по дате
        LOGGER.debug(f'Загрузка истории сообщений')
        list_messages = sorted(self.database.get_history(self.current_chat),
                               key=lambda item: item[3])
        # Если модель не создана, создадим.
        if not self.history_model:
            LOGGER.debug(f'Создание модели истории сообщений')
            self.history_model = QStandardItemModel()
            self.ui.MsgField.setModel(self.history_model)
        # Очистим от старых записей
        self.history_model.clear()
        # Берём не более 20 последних записей.
        # LOGGER.debug(f'Выводим последние 20 сообщений')
        length = len(list_messages)
        start_index = 0
        if length > 20:
            start_index = length - 20
        # Заполнение модели записями, так же стоит разделить входящие и исходящие
        # сообщения выравниванием и разным фоном.
        # Записи в обратном порядке, поэтому выбираем их с конца и не более 20
        for i in range(start_index, length):
            item = list_messages[i]
            if item[1] == 'i':
                mess = QStandardItem(f'{self.current_chat} ({item[3].replace(microsecond=0)}):\n {item[2]}')
                mess.setEditable(False)
                mess.setBackground(QBrush(QColor(224, 233, 255)))
                mess.setTextAlignment(Qt.AlignLeft)
                self.history_model.appendRow(mess)
            else:
                mess = QStandardItem(f'{self.transport.acc_name} ({item[3].replace(microsecond=0)}):\n {item[2]}')
                mess.setEditable(False)
                mess.setTextAlignment(Qt.AlignRight)
                mess.setBackground(QBrush(QColor(224, 255, 233)))
                self.history_model.appendRow(mess)
        self.ui.MsgField.scrollToBottom()

    @pyqtSlot(str)
    def show_message(self, msg):
        if msg:
            self.messages.question(self, 'Внимание', f'SERVER: {msg}, ', QMessageBox.Close)

    # Слот приёма нового сообщений
    @pyqtSlot(str)
    def message(self, sender):
        if sender == self.current_chat:
            self.history_list_update()
        else:
            # Проверим есть ли такой пользователь у нас в контактах:
            if self.database.check_contact(sender):
                # Если есть, спрашиваем о желании открыть с ним чат и открываем при желании
                if self.messages.question(self, 'Новое сообщение',
                                          f'Получено новое сообщение от {sender}, '
                                          f'открыть чат с ним?', QMessageBox.Yes,
                                          QMessageBox.No) == QMessageBox.Yes:
                    self.current_chat = sender
                    self.set_active_user()
            else:
                # Раз нет, спрашиваем хотим ли добавить юзера в контакты.
                if self.messages.question(self, 'Новое сообщение',
                                          f'Получено новое сообщение от {sender}.\n '
                                          f'Данного пользователя нет в вашем контакт-листе.\n'
                                          f' Добавить в контакты и открыть чат с ним?',
                                          QMessageBox.Yes, QMessageBox.No) == QMessageBox.Yes:
                    self.transport.add_contact(sender)
                    self.current_chat = sender
                    self.update_contacts_list()
                    self.set_active_user()

    # Слот потери соединения
    # Выдаёт сообщение об ошибке и завершает работу приложения
    @pyqtSlot()
    def connection_lost(self):
        self.messages.warning(self, 'Сбой соединения', 'Потеряно соединение с сервером. ')
        self.close()

    @pyqtSlot()
    def sig_205(self):
        '''
        Слот выполняющий обновление баз данных по команде сервера.
        '''
        if self.current_chat and not self.database.check_user(
                self.current_chat):
            self.messages.warning(
                self,
                'Сочувствую',
                'К сожалению собеседник был удалён с сервера.')
            self.set_disabled_input()
            self.current_chat = None
        self.update_contacts_list()

    def make_connection(self, trans_obj):
        trans_obj.new_message.connect(self.message)
        trans_obj.connection_lost.connect(self.connection_lost)
        trans_obj.message_205.connect(self.sig_205)
        trans_obj.show_message.connect(self.show_message)


# class PopupWin(QDialog):
#     def __init__(self, msg):
#         super().__init__()
#         self.database = database
#
#         self.setFixedSize(350, 120)
#         self.setWindowTitle(f'Внимание')
#         self.setAttribute(Qt.WA_DeleteOnClose)
#         self.setModal(True)
#
#         self.selector_label = QLabel(msg)
#         self.selector_label.setFixedSize(330, 50)
#         self.selector_label.move(10, 0)
#
#         self.btn_ok = QPushButton('Ясно, понятно', self)
#         self.btn_ok.setFixedSize(150, 30)
#         self.btn_ok.move(100, 70)
#
#         self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    from client_db import ClientDB

    database = ClientDB('test1')
    from transport import ClientTransport

    transport = ClientTransport(database, 'test1', '127.0.0.1', 7777)
    window = ClientMainWindow(database, transport)
    sys.exit(app.exec_())
