import tkinter as tk
from tkinter import messagebox, ttk
import math
import logging
import json
import os
import concurrent.futures
from typing import Union

# Настройка логирования
logging.basicConfig(filename='calculator.log', level=logging.INFO,
                    format='%(asctime)s - %(levelень)s - %(сообщение)s')

HISTORY_FILE = 'history.json'
LOCALE_FILES = {
    'ru': 'locales/ru.json',
    'en': 'locales/en.json'
}
current_locale = 'ru'

def load_locale(locale_file: str) -> dict:
    with open(locale_file, 'r', encoding='utf-8-sig') as f:
        return json.load(f)

locale = load_locale(LOCALE_FILES[current_locale])

def translate(key: str) -> str:
    return locale.get(key, key)

def add(x: float, y: float) -> float:
    return x + y

def subtract(x: float, y: float) -> float:
    return x - y

def multiply(x: float, y: float) -> float:
    return x * y

def divide(x: float, y: float) -> float:
    if y == 0:
        raise ValueError(translate("На ноль делить нельзя"))
    return x / y

def power(x: float, y: float) -> float:
    return x ** y

def sqrt(x: float) -> float:
    if x < 0:
        raise ValueError(translate("Нельзя вычислить квадратный корень из отрицательного числа"))
    return math.sqrt(x)

def is_valid_number(entry: str) -> bool:
    try:
        float(entry)
        return True
    except ValueError:
        return False

def save_history() -> None:
    with open(HISTORY_FILE, 'w', encoding='utf-8') as f:
        history = history_text.get("1.0", tk.END).strip()
        json.dump(history.split('\n'), f, ensure_ascii=False, indent=4)
        logging.info(translate("История операций сохранена"))

def load_history() -> None:
    if os.path.exists(HISTORY_FILE):
        with open(HISTORY_FILE, 'r', encoding='utf-8') as f:
            history = json.load(f)
            for entry in history:
                history_text.insert(tk.END, entry + '\n')
            history_text.see(tk.END)
            logging.info(translate("История операций загружена"))

def calculate(num1: float, num2: Union[float, None], operation: str) -> float:
    if operation == translate("Сложение"):
        return add(num1, num2)
    elif operation == translate("Вычитание"):
        return subtract(num1, num2)
    elif operation == translate("Умножение"):
        return multiply(num1, num2)
    elif operation == translate("Деление"):
        return divide(num1, num2)
    elif operation == translate("Возведение в степень"):
        return power(num1, num2)
    elif operation == translate("Квадратный корень"):
        return sqrt(num1)
    else:
        raise ValueError(translate("Неверная операция"))

def perform_operation(event: tk.Event = None) -> None:
    def operation() -> None:
        try:
            if not is_valid_number(entry1.get()):
                raise ValueError(translate("Первое число должно быть числом"))
            num1 = float(entry1.get())

            if selected_operation.get() == translate("Квадратный корень"):
                result = calculate(num1, None, selected_operation.get())
                entry2.delete(0, tk.END)
            else:
                if not is_valid_number(entry2.get()):
                    raise ValueError(translate("Второе число должно быть числом"))
                num2 = float(entry2.get())
                result = calculate(num1, num2, selected_operation.get())

            result_label.config(text=f"{translate('Результат')}: {result}")
            history_text.insert(tk.END, f"{selected_operation.get()}: {num1} {'√' if selected_operation.get() == translate('Квадратный корень') else num2} = {result}\n")
            history_text.see(tk.END)
            save_history()
            logging.info(f"{translate('Выполнена операция')}: {selected_operation.get()} {translate('с числами')} {num1} и {num2 if selected_operation.get() != translate('Квадратный корень') else ''}. {translate('Результат')}: {result}")
        except ValueError as e:
            messagebox.showerror(translate("Ошибка"), str(e))
            logging.error(f"{translate('Ошибка ввода данных')}: {str(e)}")
        except Exception as e:
            messagebox.showerror(translate("Ошибка"), translate("Неверный ввод данных"))
            logging.error(f"{translate('Непредвиденная ошибка')}: {str(e)}")

    executor.submit(operation)

def clear_entries(event: tk.Event = None) -> None:
    entry1.delete(0, tk.END)
    entry2.delete(0, tk.END)
    result_label.config(text=f"{translate('Результат')}: ")

def on_operation_change(*args) -> None:
    if selected_operation.get() == translate("Квадратный корень"):
        entry2.config(state=tk.DISABLED)
    else:
        entry2.config(state=tk.NORMAL)

def show_info(event: tk.Event = None) -> None:
    messagebox.showinfo(translate("О калькуляторе"), translate("Этот калькулятор выполнен на Python с использованием библиотеки Tkinter."))

def show_shortcuts(event: tk.Event = None) -> None:
    messagebox.showinfo(translate("Клавиатурные шорткаты"), translate("Ctrl+C: Скопировать результат\nCtrl+I: О приложении\nCtrl+Q: Выход\nCtrl+K: Клавиатурные шорткаты"))

def exit_app(event: tk.Event = None) -> None:
    save_history()
    root.destroy()

def copy_result(event: tk.Event = None) -> None:
    root.clipboard_clear()
    root.clipboard_append(result_label.cget("text").split(": ")[1])
    messagebox.showinfo(translate("Скопировано"), translate("Результат скопирован в буфер обмена."))

def switch_language() -> None:
    global current_locale, locale
    current_locale = 'en' if current_locale == 'ru' else 'ru'
    locale = load_locale(LOCALE_FILES[current_locale])
    update_ui_language()

def update_labels() -> None:
    labels = {
        "Первое число": label1,
        "Второе число": label2,
        "Операция": label3,
        "Результат": result_label,
        "История операций": label_history
    }

    for key, widget in labels.items():
        widget.config(text=translate(key))

def update_buttons() -> None:
    buttons = {
        "Вычислить": calculate_button,
        "Очистить": clear_button,
        "Скопировать результат": copy_button,
        "О приложении": info_button,
        "Клавиатурные шорткаты": shortcuts_button,
        "Выход": exit_button,
        "Переключить язык": language_button
    }

    for key, widget in buttons.items():
        widget.config(text=translate(key))

def update_operation_menu() -> None:
    menu = operation_menu['menu']
    menu.delete(0, 'end')
    operations = [translate("Сложение"), translate("Вычитание"), translate("Умножение"), translate("Деление"), translate("Возведение в степень"), translate("Квадратный корень")]
    for operation in operations:
        menu.add_command(label=operation, command=tk._setit(selected_operation, operation))
    selected_operation.set(operations[0])

def update_ui_language() -> None:
    root.title(translate("Калькулятор"))
    update_labels()
    update_buttons()
    update_operation_menu()

def switch_theme(theme: str) -> None:
    style.theme_use(theme)

root = tk.Tk()
root.title(translate("Калькулятор"))
root.geometry("800x450")
root.configure(bg="#2e3f4f")

style = ttk.Style()
style.theme_use('clam')

executor = concurrent.futures.ThreadPoolExecutor(max_workers=2)

selected_operation = tk.StringVar()
selected_operation.set(translate("Сложение"))
selected_operation.trace("w", on_operation_change)

label1 = ttk.Label(root, text=translate("Первое число"), font=("Arial", 14), background="#2e3f4f", foreground="white")
label1.grid(row=0, column=0, padx=10, pady=10, sticky='w')
entry1 = ttk.Entry(root, font=("Arial", 14))
entry1.grid(row=0, column=1, padx=10, pady=10, sticky='w')

label2 = ttk.Label(root, text=translate("Второе число"), font=("Arial", 14), background="#2e3f4f", foreground="white")
label2.grid(row=1, column=0, padx=10, pady=10, sticky='w')
entry2 = ttk.Entry(root, font=("Arial", 14))
entry2.grid(row=1, column=1, padx=10, pady=10, sticky='w')

label3 = ttk.Label(root, text=translate("Операция"), font=("Arial", 14), background="#2e3f4f", foreground="white")
label3.grid(row=2, column=0, padx=10, pady=10, sticky='w')
operation_menu = tk.OptionMenu(root, selected_operation, translate("Сложение"), translate("Сложение"), translate("Вычитание"), translate("Умножение"), translate("Деление"), translate("Возведение в степень"), translate("Квадратный корень"))
operation_menu.config(font=("Arial", 12))
operation_menu.grid(row=2, column=1, padx=10, pady=10, sticky='w')

calculate_button = ttk.Button(root, text=translate("Вычислить"), command=perform_operation, style="TButton")
calculate_button.grid(row=3, column=0, columnspan=2, pady=10, sticky='w')

clear_button = ttk.Button(root, text=translate("Очистить"), command=clear_entries, style="TButton")
clear_button.grid(row=4, column=0, columnspan=2, pady=10, sticky='w')

result_label = ttk.Label(root, text=f"{translate('Результат')}: ", font=("Arial", 14), background="#2e3f4f", foreground="white")
result_label.grid(row=5, column=0, columnspan=2, pady=10, sticky='w')

button_width = 20
copy_button = ttk.Button(root, text=translate("Скопировать результат"), command=copy_result, style="TButton")
copy_button.grid(row=6, column=0, columnspan=2, pady=10, sticky='w')

info_button = ttk.Button(root, text=translate("О приложении"), command=show_info, style="TButton")
info_button.grid(row=7, column=0, columnspan=2, pady=10, sticky='w')

shortcuts_button = ttk.Button(root, text=translate("Клавиатурные шорткаты"), command=show_shortcuts, style="TButton")
shortcuts_button.grid(row=8, column=0, columnspan=2, pady=10, sticky='w')

exit_button = ttk.Button(root, text=translate("Выход"), command=exit_app, style="TButton")
exit_button.grid(row=9, column=0, columnspan=2, pady=10, sticky='w')

def toggle_language() -> None:
    switch_language()

language_button = ttk.Button(root, text=translate("Переключить язык"), command=toggle_language, style="TButton")
language_button.grid(row=10, column=0, columnspan=2, pady=10, sticky='w')

label_history = ttk.Label(root, text=translate("История операций"), font=("Arial", 14), background="#2e3f4f", foreground="white")
label_history.grid(row=0, column=2, padx=10, pady=10, sticky='nw')

history_frame = ttk.Frame(root)
history_frame.grid(row=1, column=2, rowspan=10, padx=10, pady=10, sticky='nw')
history_text = tk.Text(history_frame, height=18, width=30, font=("Arial", 12))
history_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
history_scroll = ttk.Scrollbar(history_frame)
history_scroll.pack(side=tk.RIGHT, fill=tk.Y)
history_text.config(yscrollcommand=history_scroll.set)
history_scroll.config(command=history_text.yview)

root.bind('<Control-c>', copy_result)
root.bind('<Control-i>', show_info)
root.bind('<Control-q>', exit_app)
root.bind('<Control-k>', show_shortcuts)
root.bind('<Return>', perform_operation)
root.bind('<Escape>', clear_entries)

theme_label = ttk.Label(root, text="Theme:", font=("Arial", 14), background="#2e3f4f", foreground="white")
theme_label.grid(row=11, column=0, padx=10, pady=10, sticky='w')
theme_menu = ttk.Combobox(root, values=style.theme_names(), state="readonly")
theme_menu.set(style.theme_use())
theme_menu.grid(row=11, column=1, padx=10, pady=10, sticky='w')
theme_menu.bind("<<ComboboxSelected>>", lambda event: switch_theme(theme_menu.get()))

load_history()

root.mainloop()
проанализируй код