import tkinter as tk
from tkinter import ttk, messagebox
from tkinter.scrolledtext import ScrolledText
import base64
import binascii

class App:
    def __init__(self, root):
        self.root = root
        self.root.title("Base64 конвертер")
        self.root.geometry("600x400")
        self.notebook = ttk.Notebook(root)
        self.notebook.pack(fill=tk.BOTH, expand=True)
        self.create_text_to_b64_tab()
        self.create_b64_to_text_tab()

    def create_text_to_b64_tab(self):
        tab = ttk.Frame(self.notebook)
        self.notebook.add(tab, text="из текста в base64")
        tab.columnconfigure(0, weight=1)
        tab.rowconfigure(0, weight=1)
        tab.rowconfigure(1, weight=1)
        tab.rowconfigure(2, weight=0)

        input_frame = ttk.LabelFrame(tab, text="Исходный текст")
        input_frame.grid(row=0, column=0, sticky="nsew", padx=5, pady=5)
        input_frame.columnconfigure(0, weight=1)
        input_frame.rowconfigure(0, weight=1)
        self.text_input = ScrolledText(input_frame, wrap=tk.WORD)
        self.text_input.grid(row=0, column=0, sticky="nsew")
        paste_btn = ttk.Button(input_frame, text="Вставить из буфера обмена",
                               command=lambda: self.paste_from_clipboard(self.text_input))
        paste_btn.grid(row=0, column=1, sticky="ne", padx=(0, 5), pady=5)

        output_frame = ttk.LabelFrame(tab, text="Base64")
        output_frame.grid(row=1, column=0, sticky="nsew", padx=5, pady=5)
        output_frame.columnconfigure(0, weight=1)
        output_frame.rowconfigure(0, weight=1)
        self.b64_output = ScrolledText(output_frame, wrap=tk.WORD)
        self.b64_output.grid(row=0, column=0, sticky="nsew")
        self.b64_output.config(state='disabled')
        copy_btn = ttk.Button(output_frame, text="Скопировать в буфер",
                              command=lambda: self.copy_to_clipboard(self.b64_output))
        copy_btn.grid(row=0, column=1, sticky="ne", padx=(0, 5), pady=5)

        btn = ttk.Button(tab, text="Конвертировать", command=self.convert_text_to_b64)
        btn.grid(row=2, column=0, pady=5)

    def create_b64_to_text_tab(self):
        tab = ttk.Frame(self.notebook)
        self.notebook.add(tab, text="из base64 в текст")
        tab.columnconfigure(0, weight=1)
        tab.rowconfigure(0, weight=1)
        tab.rowconfigure(1, weight=1)
        tab.rowconfigure(2, weight=0)

        input_frame = ttk.LabelFrame(tab, text="Base64")
        input_frame.grid(row=0, column=0, sticky="nsew", padx=5, pady=5)
        input_frame.columnconfigure(0, weight=1)
        input_frame.rowconfigure(0, weight=1)
        self.b64_input = ScrolledText(input_frame, wrap=tk.WORD)
        self.b64_input.grid(row=0, column=0, sticky="nsew")
        paste_btn = ttk.Button(input_frame, text="Вставить из буфера обмена",
                               command=lambda: self.paste_from_clipboard(self.b64_input))
        paste_btn.grid(row=0, column=1, sticky="ne", padx=(0, 5), pady=5)

        output_frame = ttk.LabelFrame(tab, text="Текст")
        output_frame.grid(row=1, column=0, sticky="nsew", padx=5, pady=5)
        output_frame.columnconfigure(0, weight=1)
        output_frame.rowconfigure(0, weight=1)
        self.text_output = ScrolledText(output_frame, wrap=tk.WORD)
        self.text_output.grid(row=0, column=0, sticky="nsew")
        self.text_output.config(state='disabled')
        copy_btn = ttk.Button(output_frame, text="Скопировать в буфер",
                              command=lambda: self.copy_to_clipboard(self.text_output))
        copy_btn.grid(row=0, column=1, sticky="ne", padx=(0, 5), pady=5)

        btn = ttk.Button(tab, text="Конвертировать", command=self.convert_b64_to_text)
        btn.grid(row=2, column=0, pady=5)

    def paste_from_clipboard(self, target):
        try:
            text = self.root.clipboard_get()
        except tk.TclError:
            messagebox.showwarning("Предупреждение", "Буфер обмена пуст или содержит нетекстовые данные.")
            return
        if target.tag_ranges("sel"):
            target.delete("sel.first", "sel.last")
        target.insert("insert", text)

    def copy_to_clipboard(self, source):
        text = source.get("1.0", "end-1c")
        if not text:
            messagebox.showwarning("Предупреждение", "Нет данных для копирования.")
            return
        self.root.clipboard_clear()
        self.root.clipboard_append(text)

    def convert_text_to_b64(self):
        text = self.text_input.get("1.0", "end-1c")
        if not text:
            messagebox.showwarning("Предупреждение", "Введите текст для кодирования.")
            return
        try:
            encoded = base64.b64encode(text.encode("utf-8")).decode("ascii")
            self.b64_output.config(state='normal')
            self.b64_output.delete("1.0", tk.END)
            self.b64_output.insert("1.0", encoded)
            self.b64_output.config(state='disabled')
        except Exception as e:
            messagebox.showerror("Ошибка", f"Не удалось закодировать: {e}")

    def convert_b64_to_text(self):
        b64 = ''.join(self.b64_input.get("1.0", "end-1c").split())
        if not b64:
            messagebox.showwarning("Предупреждение", "Введите Base64 для декодирования.")
            return
        try:
            decoded_bytes = base64.b64decode(b64, validate=True)
            text = decoded_bytes.decode("utf-8")
            self.text_output.config(state='normal')
            self.text_output.delete("1.0", tk.END)
            self.text_output.insert("1.0", text)
            self.text_output.config(state='disabled')
        except (binascii.Error, UnicodeDecodeError) as e:
            messagebox.showerror("Ошибка", f"Некорректные данные: {e}")
        except Exception as e:
            messagebox.showerror("Ошибка", f"Не удалось декодировать: {e}")

if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    root.mainloop()