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

# Настройка логирования
logging.basicConfig(
    filename='calculator.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)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:
    try:
        with open(locale_file, 'r', encoding='utf-8-sig') as f:
            return json.load(f)
    except FileNotFoundError:
        logging.error(f"Файл локализации не найден: {locale_file}")
        return {}
    except json.JSONDecodeError as e:
        logging.error(f"Ошибка парсинга файла локализации: {locale_file} - {e}")
        return {}

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:
    try:
        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("История операций сохранена"))
    except Exception as e:
        logging.error(f"Ошибка при сохранении истории: {e}")

def load_history() -> None:
    if os.path.exists(HISTORY_FILE):
        try:
            with open(HISTORY_FILE, 'r', encoding='utf-8') as f:
                history = json.load(f)
                history_text.delete('1.0', tk.END)  # Очистка виджета перед загрузкой
                for entry in history:
                    history_text.insert(tk.END, entry + '\n')
                history_text.see(tk.END)
                logging.info(translate("История операций загружена"))
        except Exception as e:
            logging.error(f"Ошибка при загрузке истории: {e}")

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:
    try:
        if not is_valid_number(entry1.get()):
            raise ValueError(translate("Первое число должно быть числом"))
        num1 = float(entry1.get())

        operation = selected_operation.get()

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

        result_label.config(text=f"{translate('Результат')}: {result}")

        # Форматирование записи для истории
        if operation == translate("Квадратный корень"):
            history_entry = f"{operation}: √{num1} = {result}"
        else:
            history_entry = f"{operation}: {num1} {operation_symbol(operation)} {num2} = {result}"

        history_text.insert(tk.END, history_entry + '\n')
        history_text.see(tk.END)
        save_history()
        logging.info(f"{translate('Выполнена операция')}: {operation} {translate('с числами')} {num1} и {num2 if num2 is not None 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)}")

def operation_symbol(operation: str) -> str:
    symbols = {
        translate("Сложение"): '+',
        translate("Вычитание"): '-',
        translate("Умножение"): '*',
        translate("Деление"): '/',
        translate("Возведение в степень"): '^',
    }
    return symbols.get(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:
    result_text = result_label.cget("text")
    if result_text != f"{translate('Результат')}: ":
        root.clipboard_clear()
        root.clipboard_append(result_label.cget("text").split(": ")[1])
        messagebox.showinfo(translate("Скопировано"), translate("Результат скопирован в буфер обмена."))
    else:
        messagebox.showwarning(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()
    theme_label.config(text=translate("Тема") + ":")

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

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

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

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')

operations = [
    translate("Сложение"),
    translate("Вычитание"),
    translate("Умножение"),
    translate("Деление"),
    translate("Возведение в степень"),
    translate("Квадратный корень")
]

operation_menu = tk.OptionMenu(root, selected_operation, *operations)
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')

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')

language_button = ttk.Button(root, text=translate("Переключить язык"), command=switch_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)

# Функция для обработки шорткатов по keycode
def handle_shortcuts(event):
    # event.state & 0x4 проверяет, нажата ли клавиша Control
    if event.state & 0x4:
        if event.keycode == 67:  # Keycode для 'C'
            copy_result()
        elif event.keycode == 73:  # Keycode для 'I'
            show_info()
        elif event.keycode == 81:  # Keycode для 'Q'
            exit_app()
        elif event.keycode == 75:  # Keycode для 'K'
            show_shortcuts()

root.bind('<Key>', handle_shortcuts)
root.bind('<Return>', perform_operation)
root.bind('<Escape>', clear_entries)

theme_label = ttk.Label(root, text=translate("Тема") + ":", 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()
проанализируй код и улучши его
скидывай всегда целый и готовый код