import json
import random
import sys
from typing import Callable, Any
from PySide6.QtWidgets import QApplication, QWidget, QMessageBox, QMainWindow, QHBoxLayout, QVBoxLayout, QLineEdit, QLabel
from PySide6.QtGui import QIcon, QPixmap, QShortcut, QResizeEvent, QFont, QKeySequence
from PySide6.QtCore import Qt,QSize
from codes.ui.login import Ui_login
from codes.ui.app import Ui_App
from codes.common.worker import Worker
from codes.common import clibs
from codes.common.secure_encrypt import PassCipher
from codes.common import db_operation

class LoginWindow(QWidget, Ui_login):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.pre_dos()

    def pre_dos(self):
        self.setWindowIcon(QIcon(f"{clibs.base_path}/assets/media/icon.ico"))
        self.lb_logo.setPixmap(QPixmap(f"{clibs.base_path}/assets/media/avatar.png"))
        self.lb_logo.setScaledContents(True)

        # bindings
        QShortcut("Esc", self).activated.connect(self.close)
        self.pb_login.clicked.connect(self.login)
        self.pb_cancel.clicked.connect(self.close)
        self.le_password.returnPressed.connect(self.login)

    def login(self):
        def login_failed():
            QMessageBox.warning(self, "告警", "\n用户名或密码不正确，请重新输入！")
            self.le_username.setText("")
            self.le_password.setText("")

        def validate_login():
            nonlocal username, password
            with open(f"{clibs.base_path}/assets/conf/config.json", mode="rt", encoding="utf-8") as f_conf:
                clibs.account = json.load(f_conf)
            if username != clibs.account["username"] or len(password) < clibs.account["minimum_password_length"]:
                login_failed()
                return False

            salt = PassCipher.gen_salt(password)
            cipher = PassCipher(salt)
            # password_encrypt = cipher.encrypt(password)
            # print(f"password_encrypt = {password_encrypt}")
            # exit()
            try:
                decrypt_password = cipher.decrypt(clibs.account["login_password"])
            except ValueError:
                login_failed()
                return False

            if password != decrypt_password:
                login_failed()
                return False

            self.mainWindow = MainWindow()
            self.mainWindow.show()
            self.deleteLater()
            return True

        username = self.le_username.text()
        password = self.le_password.text()
        validate_login()

    
class MainWindow(QMainWindow, Ui_App):
    def __init__(self):
        super().__init__()
        self.conn = None
        self.cursor = None
        self.thread = None
        self.setupUi(self)
        self.pre_dos()
        self.lock_overlay = None

    def pre_dos(self):
        self.setWindowIcon(QIcon(f"{clibs.base_path}/assets/media/icon.ico"))
        db_operation.db_backup()
        self.conn, self.cursor = db_operation.db_conn()
        # bindings
        self.ac_quit.triggered.connect(self.close)
        self.ac_caging.triggered.connect(self.lock_window)
        self.ac_logs.triggered.connect(lambda : print("test ac log"))

    def launch(self, func, on_anything: Callable[..., Any] = print, *args, **kwargs):
        self.thread = Worker(func, *args, **kwargs)
        self.thread.started.connect(lambda: on_anything({"started": True}))
        self.thread.result.connect(on_anything)
        self.thread.error.connect(on_anything)
        self.thread.finished.connect(lambda: on_anything({"finished": True}))
        self.thread.start()

    def lock_window(self):
        def unlock():
            def check_failed():
                QMessageBox.warning(self, "错误", "\n密码错误，请重新输入！")
                le_password.clear()
                le_password.setFocus()

            password = le_password.text()
            if len(password) < clibs.account["minimum_password_length"]:
                check_failed()
                return False

            salt = PassCipher.gen_salt(password)
            cipher = PassCipher(salt)
            try:
                decrypt_password = cipher.decrypt(clibs.account["unlock_password"])
            except ValueError:
                check_failed()
                return False

            if password != decrypt_password:
                check_failed()
                return False

            self.lock_overlay.deleteLater()
            self.lock_overlay = None
            self.set_shortcuts(True)
            return True

        def gen_lock_screen():
            # generate lock screen
            v_layout = QVBoxLayout(self.lock_overlay)  # v layout
            v_layout.setObjectName(u"v_layout")
            h_layout = QHBoxLayout()  # h layout
            h_layout.setObjectName(u"h_layout")
            h_layout.setContentsMargins(-1, -1, 10, 50)
            lb_e_1 = QLabel(self.lock_overlay)
            lb_e_1.setObjectName(u"lb_e_1")
            h_layout.addWidget(lb_e_1)

            lb_password = QLabel(self.lock_overlay)
            lb_password.setObjectName(u"lb_password")
            lb_password.setMinimumSize(QSize(100, 0))
            lb_password.setMaximumSize(QSize(100, 16777215))
            font = QFont()
            font.setFamilies([u"Consolas"])
            font.setPointSize(14)
            font.setBold(True)
            font.setItalic(True)
            lb_password.setFont(font)
            lb_password.setAlignment(Qt.AlignmentFlag.AlignCenter)
            lb_password.setText("Password")
            h_layout.addWidget(lb_password)

            le_password = QLineEdit(self.lock_overlay)
            le_password.setObjectName(u"le_password")
            le_password.setMinimumSize(QSize(200, 0))
            le_password.setFont(font)
            le_password.setEchoMode(QLineEdit.EchoMode.Password)
            h_layout.addWidget(le_password)

            lb_e_2 = QLabel(self.lock_overlay)
            lb_e_2.setObjectName(u"lb_e_2")
            h_layout.addWidget(lb_e_2)

            h_layout.setStretch(0, 5)
            h_layout.setStretch(1, 2)
            h_layout.setStretch(2, 3)
            h_layout.setStretch(3, 5)
            v_layout.addLayout(h_layout)
            return le_password

        self.set_shortcuts(False)
        if not self.lock_overlay:
            self.lock_overlay = QWidget(self)

        self.lock_overlay.setObjectName("w_overlay")
        cx = random.random()
        cy = random.random()
        stop1 = random.random()
        stop2 = random.random()
        angle = random.randint(0, 360)
        self.lock_overlay.setStyleSheet(f"""background: qconicalgradient(cx:{cx}, cy:{cy}, angle:{angle}, stop:0 #f6f8fa, stop:{stop1} #eef1f5, stop:{stop2} #dce1e8);""")
        # self.lock_overlay.setStyleSheet("""background: qconicalgradient(cx:0.5, cy:0.5, angle:45, stop:0 #f6f8fa, stop:0.5 #eef1f5, stop:1 #dce1e8);""")

        le_password = gen_lock_screen()
        le_password.returnPressed.connect(unlock)
        self.lock_overlay.setGeometry(self.rect())
        self.lock_overlay.show()
        le_password.setFocus()

    def set_shortcuts(self, stat: bool = True):
        if stat:
            self.ac_homepage.setShortcut(QKeySequence("Ctrl+Alt+H"))
            self.ac_settings.setShortcut(QKeySequence("Ctrl+Alt+S"))
            self.ac_logs.setShortcut(QKeySequence("Ctrl+Alt+L"))
            self.ac_about.setShortcut(QKeySequence("Ctrl+Alt+A"))
            self.ac_caging.setShortcut(QKeySequence("Ctrl+Alt+C"))
            self.ac_quit.setShortcut(QKeySequence("Ctrl+Alt+Q"))
        else:
            self.ac_homepage.setShortcut(QKeySequence())
            self.ac_settings.setShortcut(QKeySequence())
            self.ac_logs.setShortcut(QKeySequence())
            self.ac_about.setShortcut(QKeySequence())
            self.ac_caging.setShortcut(QKeySequence())
            self.ac_quit.setShortcut(QKeySequence())

    def resizeEvent(self, event: QResizeEvent):
        super().resizeEvent(event)
        if self.lock_overlay:
            self.lock_overlay.setGeometry(self.rect())

    def closeEvent(self, event):
        reply = QMessageBox.question(self, "退出", "\n程序可能在运行，确定要退出吗？")
        if reply == QMessageBox.StandardButton.Yes:
            db_operation.db_close(self.conn, self.cursor)
            event.accept()
        else:
            event.ignore()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    login = LoginWindow()
    login.show()
    sys.exit(app.exec())
