import tkinter as tk
from tkinter import ttk
from collections import deque

class LuoXiaoHeiCalculator(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("罗小黑计算器")
        self.resizable(False, False)
        self.configure(bg="#F6F6F6")

        # 显示和状态
        self.expression = ""
        self.ans = "0"
        self.history = deque(maxlen=20)  # 保存最近 20 条

        self._create_widgets()
        self._bind_keys()

    def _create_widgets(self):
        # 顶部框架（头像 + 显示）
        top_frame = tk.Frame(self, bg="#F6F6F6", pady=8)
        top_frame.grid(row=0, column=0, padx=10, pady=6)

        # 头像（简单绘制罗小黑风格）
        avatar = tk.Canvas(top_frame, width=72, height=72, bg="#F6F6F6", highlightthickness=0)
        avatar.grid(row=0, column=0, rowspan=2, padx=(0,12))
        self._draw_avatar(avatar)

        # 显示屏（表达式和结果）
        display_frame = tk.Frame(top_frame, bg="#FFFFFF", bd=1, relief="solid")
        display_frame.grid(row=0, column=1, sticky="nsew")

        self.lbl_expr = tk.Label(display_frame, text="", anchor="e",
                                 font=("Helvetica", 12), bg="#FFFFFF", fg="#333333", padx=8)
        self.lbl_expr.pack(fill="both")
        self.lbl_res = tk.Label(display_frame, text="0", anchor="e",
                                font=("Helvetica", 20, "bold"), bg="#FFFFFF", fg="#111111", padx=8)
        self.lbl_res.pack(fill="both")

        # 按钮区域
        btn_frame = tk.Frame(self, bg="#F6F6F6")
        btn_frame.grid(row=1, column=0, padx=10, pady=(0,10))

        btn_specs = [
            [('AC', '#FF6B6B'), ('⌫', '#FFB86B'), ('%', '#FFD56B'), ('/', '#4B7BEC')],
            [('7', '#FFFFFF'), ('8', '#FFFFFF'), ('9', '#FFFFFF'), ('*', '#4B7BEC')],
            [('4', '#FFFFFF'), ('5', '#FFFFFF'), ('6', '#FFFFFF'), ('-', '#4B7BEC')],
            [('1', '#FFFFFF'), ('2', '#FFFFFF'), ('3', '#FFFFFF'), ('+', '#4B7BEC')],
            [('±', '#FFFFFF'), ('0', '#FFFFFF'), ('.', '#FFFFFF'), ('=', '#2ECC71')],
        ]

        self.buttons = {}
        for r, row in enumerate(btn_specs):
            for c, (text, color) in enumerate(row):
                b = tk.Button(btn_frame, text=text, width=6, height=2,
                              bg=color, fg="#111111", bd=0, relief="raised",
                              font=("Helvetica", 12), command=lambda t=text: self.on_button(t))
                b.grid(row=r, column=c, padx=6, pady=6, ipadx=4, ipady=6)
                self.buttons[text] = b

        # 侧边历史记录
        hist_frame = tk.Frame(self, bg="#F6F6F6")
        hist_frame.grid(row=0, column=1, rowspan=2, sticky="ns", padx=(6,10), pady=6)

        hist_label = tk.Label(hist_frame, text="历史记录", bg="#F6F6F6", fg="#333333", font=("Helvetica", 10, "bold"))
        hist_label.pack(anchor="nw")

        self.hist_listbox = tk.Listbox(hist_frame, width=24, height=12, bd=1, relief="solid", activestyle="none")
        self.hist_listbox.pack(pady=(6,0))
        self.hist_listbox.bind("<Double-Button-1>", self.on_history_double)

    def _draw_avatar(self, canvas):
        # 简单的卡通头像模仿罗小黑（黑色小猫风格），避免使用版权图
        # 头部
        canvas.create_oval(8, 8, 64, 64, fill="#111111", outline="")
        # 眼白
        canvas.create_oval(20, 24, 30, 34, fill="#FFFFFF", outline="")
        canvas.create_oval(42, 24, 52, 34, fill="#FFFFFF", outline="")
        # 眼珠
        canvas.create_oval(24, 28, 28, 32, fill="#111111", outline="")
        canvas.create_oval(46, 28, 50, 32, fill="#111111", outline="")
        # 嘴巴（小微笑）
        canvas.create_arc(28, 36, 44, 54, start=0, extent=-180, style="arc", outline="#FF8080", width=2)
        # 耳朵
        canvas.create_polygon(12, 18, 4, 6, 20, 14, fill="#111111", outline="")
        canvas.create_polygon(60, 18, 68, 6, 52, 14, fill="#111111", outline="")

    def _bind_keys(self):
        self.bind("<Key>", self._on_key)
        # 允许点击列表框后按键也能输入
        self.hist_listbox.bind("<Key>", self._on_key)

    def _on_key(self, event):
        key = event.keysym
        char = event.char
        if char in '0123456789':
            self._append(char)
        elif char in '+-*/.%':
            self._append(char)
        elif char == '.':
            self._append('.')
        elif key in ('Return', 'KP_Enter'):
            self._evaluate()
        elif key == 'BackSpace':
            self._backspace()
        elif key == 'Escape':
            self._clear_all()
        elif char == '\r':
            self._evaluate()
        # 支持 ± 切换用 Shift+- 或小按钮
        elif key == 'plus' and ('shift' in event.state.__str__()):  # fallback，通常直接使用 '+'
            self._append('+')

    def on_button(self, text):
        if text == 'AC':
            self._clear_all()
        elif text == '⌫':
            self._backspace()
        elif text == '=':
            self._evaluate()
        elif text == '±':
            self._toggle_sign()
        else:
            self._append(text)

    def _append(self, token):
        # 规范化输入（防止两个运算符连续）
        if token in '+-*/%':
            if self.expression == "" and token != '-':
                return
            if self.expression.endswith(('+','-','*','/','%')):
                # 替换最后一个运算符（允许负号）
                if token == '-' and not self.expression.endswith('-'):
                    self.expression += token
                else:
                    self.expression = self.expression[:-1] + token
            else:
                self.expression += token
        elif token == '.':
            # 防止在同一数字内出现多个小数点：检查最后一段
            last_num = ''
            for ch in reversed(self.expression):
                if ch in '+-*/%':
                    break
                last_num = ch + last_num
            if '.' in last_num:
                return
            if last_num == '':
                self.expression += '0.'
            else:
                self.expression += '.'
        else:
            self.expression += str(token)

        self._update_display()

    def _backspace(self):
        if self.expression:
            self.expression = self.expression[:-1]
            self._update_display()
        else:
            self.ans = "0"
            self.lbl_res.config(text=self.ans)

    def _clear_all(self):
        self.expression = ""
        self.ans = "0"
        self._update_display()

    def _toggle_sign(self):
        # 在当前最后一个数字段加/去负号
        if not self.expression:
            self.expression = '-'
            self._update_display()
            return
        # 找到最后一个运算符位置
        last_op = -1
        for i in range(len(self.expression)-1, -1, -1):
            if self.expression[i] in '+-*/%':
                last_op = i
                break
        last_num = self.expression[last_op+1:]
        if last_num.startswith('-'):
            # 去掉负号
            self.expression = self.expression[:last_op+1] + last_num[1:]
        else:
            # 插入负号
            self.expression = self.expression[:last_op+1] + '-' + last_num
        self._update_display()

    def _evaluate(self):
        if not self.expression:
            return
        expr = self.expression.replace('%', '/100')  # 支持百分号作为除以100
        try:
            # 安全评估（只允许数字和运算符）
            allowed = set("0123456789+-*/%.() ")
            if any(ch not in allowed for ch in expr):
                raise ValueError("非法字符")
            # 计算
            result = eval(expr, {"__builtins__": None}, {})
            # 格式化结果，防止长小数
            if isinstance(result, float):
                result_str = format(result, ".10g")
            else:
                result_str = str(result)
            self.ans = result_str
            # 保存历史
            self.history.appendleft(f"{self.expression} = {self.ans}")
            self._refresh_history()
            self.expression = ""
            self._update_display(result_override=self.ans)
        except Exception as e:
            self.lbl_res.config(text="错误")
            print("计算错误：", e)

    def _update_display(self, result_override=None):
        self.lbl_expr.config(text=self.expression)
        if result_override is not None:
            self.lbl_res.config(text=result_override)
        else:
            if self.expression == "":
                self.lbl_res.config(text=self.ans)
            else:
                # 尝试显示当前表达式的即时结果（非必须）
                try:
                    expr = self.expression.replace('%', '/100')
                    allowed = set("0123456789+-*/%.() ")
                    if all(ch in allowed for ch in expr):
                        val = eval(expr, {"__builtins__": None}, {})
                        if isinstance(val, float):
                            self.lbl_res.config(text=format(val, ".10g"))
                        else:
                            self.lbl_res.config(text=str(val))
                    else:
                        self.lbl_res.config(text=self.ans)
                except Exception:
                    self.lbl_res.config(text=self.ans)

    def _refresh_history(self):
        self.hist_listbox.delete(0, tk.END)
        for item in self.history:
            self.hist_listbox.insert(tk.END, item)

    def on_history_double(self, event):
        sel = self.hist_listbox.curselection()
        if not sel:
            return
        item = self.hist_listbox.get(sel[0])
        # 恢复表达式部分（= 前）
        if '=' in item:
            expr = item.split('=')[0].strip()
            self.expression = expr
            self._update_display()

if __name__ == "__main__":
    app = LuoXiaoHeiCalculator()
    app.mainloop()