import sys
import io
import os
import g4f

from g4f.client import Client
from PyQt6.QtCore import pyqtSlot
from PyQt6.QtWidgets import QApplication, QMainWindow, QMessageBox, QFileDialog
from PyQt6.QtWidgets import QMessageBox
from docx import Document

from Authorization import Ui_Authorization
from Registration import Ui_Registration
from MainWindow import Ui_MainWindow

from g4f.Provider import (
    Bing,
    HuggingChat,
    ChatgptDemo,
    OpenAssistant,
    OpenaiChat,
    Aichat,
    Ails
)

sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8')

DATA_FILE = "user_data.txt"

client = Client()

class AuthorizationWindow(QMainWindow, Ui_Authorization):
    def __init__(self):
        super(AuthorizationWindow, self).__init__()
        self.setupUi(self)

        self.pushButton_3.clicked.connect(self.open_registration)
        self.pushButton.clicked.connect(self.login)
        self.user_data = self.load_user_data()

    def load_user_data(self):
        if not os.path.exists(DATA_FILE):
            return {}

        user_data = {}
        try:
            with open(DATA_FILE, "r") as file:
                for line in file:
                    parts = line.strip().split(",")
                    if len(parts) == 2:
                        username, password = parts
                        email = ""
                    elif len(parts) == 3:
                        username, password, email = parts
                    else:
                        continue
                    user_data[username] = {"password": password, "email": email}
        except Exception as e:
            print(f"Error loading user data: {e}")
        return user_data

    def save_user_data(self):
        try:
            with open(DATA_FILE, "w") as file:
                for username, data in self.user_data.items():
                    file.write(f"{username},{data['password']},{data['email']}\n")
        except Exception as e:
            print(f"Error saving user data: {e}")

    @pyqtSlot()
    def open_registration(self):
        try:
            self.registration_window = RegistrationWindow(self)
            self.registration_window.show()
        except Exception as e:
            print(f"Error opening registration window: {e}")

    @pyqtSlot()
    def login(self):
        try:
            username = self.lineEdit.text()
            password = self.lineEdit_2.text()

            msg_box = QMessageBox(self)
            msg_box.setStyleSheet("background-color: white;")

            if username in self.user_data and self.user_data[username]["password"] == password:
                msg_box.setText("Вы успешно вошли в систему!")
                msg_box.setIcon(QMessageBox.Icon.Information)

                self.main_window = MainWindowWindow(self)
                self.main_window.show()
                self.close()
            else:
                msg_box.setText("Неверный логин или пароль!")
                msg_box.setIcon(QMessageBox.Icon.Warning)

            msg_box.exec()
        except Exception as e:
            print(f"Error during login: {e}")

class RegistrationWindow(QMainWindow, Ui_Registration):
    def __init__(self, auth_window):
        super(RegistrationWindow, self).__init__()
        self.setupUi(self)
        self.auth_window = auth_window
        self.pushButton.clicked.connect(self.save_registration)
        
    @pyqtSlot()
    def save_registration(self):
        try:
            email = self.lineEdit_3.text()
            username = self.lineEdit.text()
            password = self.lineEdit_2.text()
            confirm_password = self.lineEdit_4.text()

            msg_box = QMessageBox(self)
            msg_box.setStyleSheet("background-color: white;")

            if password != confirm_password:
                msg_box.setText("Пароли не совпадают!")
                msg_box.setIcon(QMessageBox.Icon.Warning)
                msg_box.exec()
                return

            self.auth_window.user_data[username] = {"password": password, "email": email}
            self.auth_window.save_user_data()
            msg_box.setText("Регистрация успешна!")
            msg_box.setIcon(QMessageBox.Icon.Information)
            msg_box.exec()

            self.close()
        except Exception as e:
            print(f"Error during registration: {e}")

class MainWindowWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, auth_window):
        super(MainWindowWindow, self).__init__()
        self.setupUi(self)
        self.auth_window = auth_window
        self.initialize_signals()

        # Initialize the first tab display
        self.tabWidget.setCurrentIndex(0)

        self.label_139.setWordWrap(True)

    def initialize_signals(self):
        # Connect comboBox signals to methods
        self.comboBox_3.currentIndexChanged.connect(self.handle_comboBox_3_change)
        self.comboBox_6.currentIndexChanged.connect(self.handle_comboBox_6_change)

        # Connect pushButton signals to methods
        self.pushButton_2.clicked.connect(self.handle_push_button_2)
        self.pushButton_3.clicked.connect(self.handle_push_button_3)

        self.pushButton_2.clicked.connect(self.switch_to_tab8)
        self.pushButton_3.clicked.connect(self.switch_to_tab7)

        self.pushButton_4.clicked.connect(self.handle_addition)
        self.pushButton_5.clicked.connect(self.save_to_docx)

    def handle_comboBox_3_change(self, index):
        if index == 0:  # Index for "1"
            self.tabWidget.setCurrentIndex(0)  # Set to tab3
        elif index == 1:  # Index for "2"
            self.tabWidget.setCurrentIndex(1)  # Set to tab4

    def handle_comboBox_6_change(self, index):
        if index == 0:  # Index for "3"
            self.tabWidget.setCurrentIndex(2)  # Set to tab5

    def handle_push_button_2(self):
        # Set tabWidget to tab2
        self.tabWidget_3.setCurrentIndex(1)

    def handle_push_button_3(self):
        # Set tabWidget to tab (initial tab)
        self.tabWidget_3.setCurrentIndex(0)

    def switch_to_tab8(self):
        # Change the active tab in tabWidget3 to tab7
        self.tabWidget_2.setCurrentIndex(1)

    def switch_to_tab7(self):
        # Change the active tab in tabWidget3 to tab6
        self.tabWidget_2.setCurrentIndex(0)

    def handle_addition(self):
        def set_label_text(label, value):
            label.setText(str(round(value, 3)))

        def handle_calculation(expression, label):
            try:
                result = eval(expression)
                if isinstance(result, float):
                    set_label_text(label, result)
                else:
                    raise ValueError("Result is not a float")
            except Exception:
                label.setText("Ошибка ввода")

        calculations = [
            (f"({self.lineEdit_110.text()} + {self.lineEdit_126.text()}) / {self.lineEdit_86.text()}", self.label_156),
            (f"({self.lineEdit_86.text()} - {self.lineEdit_29.text()}) / {self.lineEdit_23.text()}", self.label_172),
            (f"{self.lineEdit_86.text()} / {self.lineEdit_127.text()}", self.label_180),
            (f"{self.lineEdit_86.text()} / ({self.lineEdit_110.text()} + {self.lineEdit_126.text()})", self.label_164),
            (f"({self.lineEdit_86.text()} + {self.lineEdit_110.text()}) / {self.lineEdit_127.text()}", self.label_148),
            (f"({self.lineEdit_116.text()} + {self.lineEdit_146.text()}) / {self.lineEdit_93.text()}", self.label_158),
            (f"({self.lineEdit_93.text()} - {self.lineEdit_47.text()}) / {self.lineEdit_66.text()}", self.label_173),
            (f"{self.lineEdit_93.text()} / {self.lineEdit_147.text()}", self.label_181),
            (f"{self.lineEdit_93.text()} / ({self.lineEdit_116.text()} + {self.lineEdit_146.text()})", self.label_165),
            (f"({self.lineEdit_93.text()} + {self.lineEdit_116.text()}) / {self.lineEdit_147.text()}", self.label_149),
            (f"({self.lineEdit_117.text()} + {self.lineEdit_145.text()}) / {self.lineEdit_100.text()}", self.label_157),
            (f"({self.lineEdit_100.text()} - {self.lineEdit_48.text()}) / {self.lineEdit_71.text()}", self.label_174),
            (f"{self.lineEdit_100.text()} / {self.lineEdit_148.text()}", self.label_182),
            (f"{self.lineEdit_100.text()} / ({self.lineEdit_117.text()} + {self.lineEdit_145.text()})", self.label_166),
            (f"({self.lineEdit_100.text()} + {self.lineEdit_117.text()}) / {self.lineEdit_148.text()}", self.label_150)
        ]

        for expression, label in calculations:
            handle_calculation(expression, label)

        # Вывод в labels
        def handle_comparison(label_current, label_previous, label_diff, label_ratio, label_percent):
            try:
                current_value = float(label_current.text())
                previous_value = float(label_previous.text())

                if previous_value == 0:
                    label_diff.setText("Ошибка деления на ноль")
                    label_ratio.setText("Ошибка деления на ноль")
                    label_percent.setText("Ошибка деления на ноль")
                    return

                diff = current_value - previous_value
                ratio = current_value / previous_value
                percent = (current_value / previous_value) * 100

                set_label_text(label_diff, diff)
                set_label_text(label_ratio, ratio)
                set_label_text(label_percent, percent)
            except ValueError:
                label_diff.setText("Ошибка ввода")
                label_ratio.setText("Ошибка ввода")
                label_percent.setText("Ошибка ввода")

        comparisons = [
            (self.label_157, self.label_156, self.label_159, self.label_161, self.label_160),
            (self.label_174, self.label_172, self.label_175, self.label_176, self.label_177),
            (self.label_182, self.label_180, self.label_183, self.label_184, self.label_185),
            (self.label_166, self.label_164, self.label_167, self.label_168, self.label_169),
            (self.label_150, self.label_148, self.label_151, self.label_152, self.label_153),
        ]

        for current, previous, diff, ratio, percent in comparisons:
            handle_comparison(current, previous, diff, ratio, percent)

        # Отправка данных в GPT и установка ответа в label_139
        self.send_to_gpt()

    def send_to_gpt(self):
        u1_values = (self.label_156.text(), self.label_158.text(), self.label_157.text())
        u11_values = (self.label_159.text(), self.label_161.text(), self.label_160.text())
        u2_values = (self.label_172.text(), self.label_173.text(), self.label_174.text())
        u21_values = (self.label_175.text(), self.label_176.text(), self.label_177.text())
        u3_values = (self.label_180.text(), self.label_181.text(), self.label_182.text())
        u31_values = (self.label_183.text(), self.label_184.text(), self.label_185.text())
        u4_values = (self.label_164.text(), self.label_165.text(), self.label_166.text())
        u41_values = (self.label_167.text(), self.label_168.text(), self.label_169.text())
        u5_values = (self.label_148.text(), self.label_149.text(), self.label_150.text())
        u51_values = (self.label_151.text(), self.label_152.text(), self.label_153.text())

        content = f"""
        Значения коэффициентов:
        1. Коэффициент финансового риска, U1: за 1 год, 2 год, 3 год, {u1_values}, измерительные показатели Абсолютное отклонение, Относительное отклонение, Темп роста {u11_values}
        2. Коэффициент обеспеченности собственными источниками финансирования, U2: за 1 год, 2 год, 3 год, {u2_values}, измерительные показатели Абсолютное отклонение, Относительное отклонение, Темп роста {u21_values}
        3. Коэффициент финансовой независимости (автономии), U3: за 1 год, 2 год, 3 год, {u3_values}, измерительные показатели Абсолютное отклонение, Относительное отклонение, Темп роста {u31_values}
        4. Коэффициент финансирования, U4: за 1 год, 2 год, 3 год, {u4_values}, измерительные показатели Абсолютное отклонение, Относительное отклонение, Темп роста {u41_values}
        5. Коэффициент финансовой устойчивости, U5: за 1 год, 2 год, 3 год, {u5_values}, измерительные показатели Абсолютное отклонение, Относительное отклонение, Темп роста {u51_values}

        Пожалуйста, проанализируйте эти коэффициенты и дайте рекомендации по улучшению финансовой устойчивости компании. А также какие изменения показали измерительные показатели
        """

        try:
            response = g4f.ChatCompletion.create(
                model="gpt-3.5-turbo",
                messages=[{"role": "user", "content": content}],
                provider=ChatgptDemo
            )

            self.label_139.setText(response.choices[0].message.content)
        except Exception as e:
            self.label_139.setText(f"Error during GPT request: {e}")
            print(f"Error during GPT request: {e}")

    def save_to_docx(self):
        import docx

        # Create a new Document
        doc = Document()

        # Add a title
        doc.add_heading('Финансовые коэффициенты', level=1)

        # Create a table with headers
        table = doc.add_table(rows=1, cols=4)
        hdr_cells = table.rows[0].cells
        hdr_cells[0].text = 'Коэффициент'
        hdr_cells[1].text = 'Значение'
        hdr_cells[2].text = 'Абсолютное отклонение'
        hdr_cells[3].text = 'Относительное отклонение'

        # Add rows to the table
        def add_row(coefficient, value, abs_deviation, rel_deviation):
            row_cells = table.add_row().cells
            row_cells[0].text = coefficient
            row_cells[1].text = value
            row_cells[2].text = abs_deviation
            row_cells[3].text = rel_deviation

        # Adding your data
        add_row('U1', self.label_156.text(), self.label_159.text(), self.label_161.text())
        add_row('U2', self.label_172.text(), self.label_175.text(), self.label_176.text())
        add_row('U3', self.label_180.text(), self.label_183.text(), self.label_184.text())
        add_row('U4', self.label_164.text(), self.label_167.text(), self.label_168.text())
        add_row('U5', self.label_148.text(), self.label_151.text(), self.label_152.text())

        # Add GPT response
        doc.add_heading('Анализ', level=2)
        doc.add_paragraph(self.label_139.text())

        # Open a file dialog to select a save location
        file_path, _ = QFileDialog.getSaveFileName(self, "Сохранить файл как", "", "Word Document (*.docx)")

        if file_path:
            try:
                doc.save(file_path)
                self.show_message_box("Сохранение", f"Файл успешно сохранён: {file_path}", QMessageBox.Icon.Information)
            except Exception as e:
                self.show_message_box("Error", f"Ошибка при сохранении файла: {e}", QMessageBox.Icon.Critical)
                print(f"Error saving file: {e}")
        else:
            self.show_message_box("Сохранение", "Сохранение отменено", QMessageBox.Icon.Warning)

    def show_message_box(self, title, text, icon):
        msg_box = QMessageBox(self)
        # Set the style for the QMessageBox and its sub-elements
        msg_box.setStyleSheet("""
            QMessageBox {
                background-color: white;
            }
            QMessageBox QLabel {
                color: black;
                background-color: white;
            }
            QMessageBox QPushButton {
                background-color: white;
                color: black;
            }
            QMessageBox QIcon {
                background-color: white;
            }
        """)
        msg_box.setWindowTitle(title)
        msg_box.setText(text)
        msg_box.setIcon(icon)
        msg_box.exec()

def main():
    app = QApplication(sys.argv)

    try:
        auth_window = AuthorizationWindow()
        auth_window.show()
        sys.exit(app.exec())
    except Exception as e:
        print("Critical error at application start:", e)

if __name__ == "__main__":
    main()

Error during GET request: Cannot connect to host chatgpt.com:443 ssl:True [SSL Cert Verification Error: (1, ‘[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to
get local issuer certificate (_ssl.c:1000)’)]


Error during GPT request: ChatgptDemo is not working