import tkinter as tk
from tkinter import scrolledtext, messagebox
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.backends import default_backend
import sys
import hashlib


# --- Серверная часть ---
class Server:
    def __init__(self):
        # Генерация пары ключей RSA для сервера
        self.private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
            backend=default_backend()
        )
        self.public_key = self.private_key.public_key()

        # Хранилище пользователей: {username: password_hash}
        self.users = {
            "user": self.hash_password("pass")  # Предустановленный пользователь
        }

    def hash_password(self, password):
        """Хеширование пароля с использованием SHA-256."""
        return hashlib.sha256(password.encode()).hexdigest()

    def authenticate(self, username, password):
        """Проверка учетных данных."""
        if username in self.users and self.users[username] == self.hash_password(password):
            return "Authenticated"
        else:
            return "Authentication Failed"

    def register_user(self, username, password):
        """Регистрация нового пользователя."""
        if username in self.users:
            return "User Already Exists"
        else:
            self.users[username] = self.hash_password(password)
            return "Registration Successful"

    def decrypt_message(self, ciphertext):
        """Расшифровка сообщения от клиента."""
        try:
            message = self.private_key.decrypt(
                ciphertext,
                padding.OAEP(
                    mgf=padding.MGF1(algorithm=hashes.SHA256()),
                    algorithm=hashes.SHA256(),
                    label=None
                )
            )
            return message.decode()
        except Exception as e:
            return f"Decryption Failed: {str(e)}"

    def encrypt_message(self, message, client_public_key):
        """Шифрование сообщения для клиента."""
        ciphertext = client_public_key.encrypt(
            message.encode(),
            padding.OAEP(
                mgf=padding.MGF1(algorithm=hashes.SHA256()),
                algorithm=hashes.SHA256(),
                label=None
            )
        )
        return ciphertext

    def handle_authentication(self, ciphertext, client_public_key):
        """Обработка зашифрованной аутентификации или регистрации от клиента."""
        try:
            auth_payload = self.decrypt_message(ciphertext)
            parts = auth_payload.split('\n')
            if len(parts) < 3:
                return self.encrypt_message("Invalid Request Format", client_public_key)

            request_type = parts[0]
            username = parts[1]
            password = parts[2]

            if request_type == "AUTH":
                auth_result = self.authenticate(username, password)
            elif request_type == "REGISTER":
                auth_result = self.register_user(username, password)
            else:
                auth_result = "Unknown Request Type"

            # Шифруем ответ для клиента
            response_ciphertext = self.encrypt_message(auth_result, client_public_key)
            return response_ciphertext
        except Exception as e:
            error_message = f"Authentication Error: {str(e)}"
            return self.encrypt_message(error_message, client_public_key)

    def handle_client_message(self, ciphertext, client_public_key):
        """Обработка зашифрованного сообщения от клиента."""
        decrypted_message = self.decrypt_message(ciphertext)
        print(f"Server received: {decrypted_message}")

        # Формирование ответа
        response = f"Server received your message: '{decrypted_message}'"
        encrypted_response = self.encrypt_message(response, client_public_key)
        return encrypted_response


# --- Клиентская часть ---
class Client:
    def __init__(self, server):
        self.server = server
        # Генерация пары ключей RSA для клиента
        self.private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
            backend=default_backend()
        )
        self.public_key = self.private_key.public_key()
        # Предполагаем, что клиент знает публичный ключ сервера
        self.server_public_key = server.public_key

    def encrypt_message(self, message):
        """Шифрование сообщения для сервера."""
        ciphertext = self.server_public_key.encrypt(
            message.encode(),
            padding.OAEP(
                mgf=padding.MGF1(algorithm=hashes.SHA256()),
                algorithm=hashes.SHA256(),
                label=None
            )
        )
        return ciphertext

    def decrypt_message(self, ciphertext):
        """Расшифровка сообщения от сервера."""
        try:
            message = self.private_key.decrypt(
                ciphertext,
                padding.OAEP(
                    mgf=padding.MGF1(algorithm=hashes.SHA256()),
                    algorithm=hashes.SHA256(),
                    label=None
                )
            )
            return message.decode()
        except Exception as e:
            return f"Decryption Failed: {str(e)}"

    def authenticate(self, username, password):
        """Аутентификация на сервере."""
        # Формат сообщения: "AUTH\nusername\npassword"
        auth_message = f"AUTH\n{username}\n{password}"
        ciphertext = self.encrypt_message(auth_message)
        # Отправка зашифрованных данных серверу и получение ответа
        response_ciphertext = self.server.handle_authentication(ciphertext, self.public_key)
        response = self.decrypt_message(response_ciphertext)
        return response

    def register(self, username, password):
        """Регистрация на сервере."""
        # Формат сообщения: "REGISTER\nusername\npassword"
        register_message = f"REGISTER\n{username}\n{password}"
        ciphertext = self.encrypt_message(register_message)
        # Отправка зашифрованных данных серверу и получение ответа
        response_ciphertext = self.server.handle_authentication(ciphertext, self.public_key)
        response = self.decrypt_message(response_ciphertext)
        return response

    def send_message(self, message):
        """Отправка сообщения серверу и получение ответа."""
        encrypted_message = self.encrypt_message(message)
        response_ciphertext = self.server.handle_client_message(encrypted_message, self.public_key)
        response = self.decrypt_message(response_ciphertext)
        return response


# --- GUI на Tkinter ---
class Application(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Локальный Клиент-Сервер с Шифрованием")
        self.geometry("600x500")
        self.resizable(False, False)

        # Инициализация серверной и клиентской части
        self.server = Server()
        self.client = Client(self.server)
        self.authenticated = False

        # Создание интерфейса
        self.create_widgets()

    def create_widgets(self):
        # Вкладки для входа и регистрации
        self.tabs = tk.Frame(self)
        self.tabs.pack(pady=10)

        self.login_tab = tk.Button(self.tabs, text="Вход", width=15, command=self.show_login)
        self.login_tab.grid(row=0, column=0, padx=5)

        self.register_tab = tk.Button(self.tabs, text="Регистрация", width=15, command=self.show_register)
        self.register_tab.grid(row=0, column=1, padx=5)

        # Фрейм для входа
        self.login_frame = tk.LabelFrame(self, text="Аутентификация", padx=10, pady=10)
        self.login_frame.pack(padx=10, pady=10, fill="x")

        tk.Label(self.login_frame, text="Username:").grid(row=0, column=0, padx=5, pady=5, sticky="e")
        self.login_username_entry = tk.Entry(self.login_frame, width=30)
        self.login_username_entry.grid(row=0, column=1, padx=5, pady=5)

        tk.Label(self.login_frame, text="Password:").grid(row=1, column=0, padx=5, pady=5, sticky="e")
        self.login_password_entry = tk.Entry(self.login_frame, show="*", width=30)
        self.login_password_entry.grid(row=1, column=1, padx=5, pady=5)

        self.auth_button = tk.Button(self.login_frame, text="Войти", command=self.authenticate)
        self.auth_button.grid(row=2, column=0, columnspan=2, pady=10)

        # Фрейм для регистрации (изначально скрыт)
        self.register_frame = tk.LabelFrame(self, text="Регистрация", padx=10, pady=10)
        self.register_frame.pack(padx=10, pady=10, fill="x")
        self.register_frame.pack_forget()

        tk.Label(self.register_frame, text="Username:").grid(row=0, column=0, padx=5, pady=5, sticky="e")
        self.register_username_entry = tk.Entry(self.register_frame, width=30)
        self.register_username_entry.grid(row=0, column=1, padx=5, pady=5)

        tk.Label(self.register_frame, text="Password:").grid(row=1, column=0, padx=5, pady=5, sticky="e")
        self.register_password_entry = tk.Entry(self.register_frame, show="*", width=30)
        self.register_password_entry.grid(row=1, column=1, padx=5, pady=5)

        self.register_button = tk.Button(self.register_frame, text="Зарегистрироваться", command=self.register)
        self.register_button.grid(row=2, column=0, columnspan=2, pady=10)

        # Разделитель
        separator = tk.Frame(self, height=2, bd=1, relief="sunken")
        separator.pack(fill="x", padx=5, pady=5)

        # Фрейм для отправки сообщений
        self.message_frame = tk.LabelFrame(self, text="Отправка Сообщений", padx=10, pady=10)
        self.message_frame.pack(padx=10, pady=10, fill="both", expand=True)
        self.message_frame.pack_forget()

        self.message_text = scrolledtext.ScrolledText(self.message_frame, wrap=tk.WORD, width=70, height=15,
                                                      state='disabled')
        self.message_text.pack(padx=5, pady=5)

        self.entry_message = tk.Entry(self.message_frame, width=50)
        self.entry_message.pack(padx=5, pady=5, side="left", expand=True, fill="x")

        self.send_button = tk.Button(self.message_frame, text="Отправить", command=self.send_message, state='disabled')
        self.send_button.pack(padx=5, pady=5, side="left")

    def show_login(self):
        """Показать вкладку входа."""
        self.login_frame.pack(padx=10, pady=10, fill="x")
        self.register_frame.pack_forget()
        self.message_frame.pack_forget()

    def show_register(self):
        """Показать вкладку регистрации."""
        self.register_frame.pack(padx=10, pady=10, fill="x")
        self.login_frame.pack_forget()
        self.message_frame.pack_forget()

    def authenticate(self):
        """Обработка аутентификации пользователя."""
        username = self.login_username_entry.get()
        password = self.login_password_entry.get()

        if not username or not password:
            messagebox.showwarning("Внимание", "Пожалуйста, введите имя пользователя и пароль.")
            return

        response = self.client.authenticate(username, password)
        if response == "Authenticated":
            self.authenticated = True
            self.auth_button.config(state='disabled')
            self.login_username_entry.config(state='disabled')
            self.login_password_entry.config(state='disabled')
            self.send_button.config(state='normal')
            self.message_frame.pack(padx=10, pady=10, fill="both", expand=True)
            self.message_text.config(state='normal')
            self.message_text.insert(tk.END, "Аутентификация прошла успешно.\n")
            self.message_text.config(state='disabled')
        else:
            messagebox.showerror("Ошибка", f"Аутентификация не удалась: {response}")
            self.message_text.config(state='normal')
            self.message_text.insert(tk.END, f"Аутентификация не удалась: {response}\n")
            self.message_text.config(state='disabled')

    def register(self):
        """Обработка регистрации нового пользователя."""
        username = self.register_username_entry.get()
        password = self.register_password_entry.get()

        if not username or not password:
            messagebox.showwarning("Внимание", "Пожалуйста, введите имя пользователя и пароль.")
            return

        if len(username) < 3 or len(password) < 3:
            messagebox.showwarning("Внимание", "Имя пользователя и пароль должны быть длиной минимум 3 символа.")
            return

        response = self.client.register(username, password)
        if response == "Registration Successful":
            messagebox.showinfo("Успех", "Регистрация прошла успешно. Теперь вы можете войти.")
            self.show_login()
        else:
            messagebox.showerror("Ошибка", f"Регистрация не удалась: {response}")
            self.message_text.config(state='normal')
            self.message_text.insert(tk.END, f"Регистрация не удалась: {response}\n")
            self.message_text.config(state='disabled')

    def send_message(self):
        """Отправка сообщения серверу и получение ответа."""
        if not self.authenticated:
            messagebox.showwarning("Внимание", "Сначала выполните аутентификацию.")
            return

        message = self.entry_message.get()
        if not message:
            messagebox.showwarning("Внимание", "Пожалуйста, введите сообщение.")
            return

        response = self.client.send_message(message)
        self.message_text.config(state='normal')
        self.message_text.insert(tk.END, f"Вы: {message}\n")
        self.message_text.insert(tk.END, f"Сервер: {response}\n")
        self.message_text.config(state='disabled')
        self.entry_message.delete(0, tk.END)


# --- Запуск Приложения ---
if __name__ == "__main__":
    app = Application()
    app.mainloop() добавь второе окно , при открытие пусть будет это серверной частью и возмодность ввода сообщений со смайликами