import tkinter as tk
from tkinter import messagebox
import math

class FractionReducerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("038. 分数化简 / 约分工具")
        self.root.geometry("520x460")
        self.root.resizable(False, False)

        self.history = []
        self.build_ui()

    # ========== UI ==========
    def build_ui(self):
        # 标题
        tk.Label(
            self.root, text="✏️ 分数化简 / 约分工具",
            font=("微软雅黑", 18, "bold")
        ).pack(pady=12)

        # ===== 输入区 =====
        input_frame = tk.LabelFrame(self.root, text="输入分数", font=("微软雅黑", 10))
        input_frame.pack(padx=25, pady=5, fill=tk.X)

        tk.Label(input_frame, text="分子：").grid(row=0, column=0, padx=10, pady=12, sticky="e")
        self.numerator_entry = tk.Entry(input_frame, width=12, font=("Consolas", 12))
        self.numerator_entry.grid(row=0, column=1, padx=5, pady=12)
        self.numerator_entry.insert(0, "12")

        tk.Label(input_frame, text="分母：").grid(row=0, column=2, padx=10, pady=12, sticky="e")
        self.denominator_entry = tk.Entry(input_frame, width=12, font=("Consolas", 12))
        self.denominator_entry.grid(row=0, column=3, padx=5, pady=12)
        self.denominator_entry.insert(0, "18")

        # ===== 结果区 =====
        result_frame = tk.LabelFrame(self.root, text="化简结果", font=("微软雅黑", 10))
        result_frame.pack(padx=25, pady=10, fill=tk.X)

        self.result_label = tk.Label(
            result_frame, text="等待计算...",
            font=("Consolas", 16), fg="#1565C0"
        )
        self.result_label.pack(pady=10)

        self.detail_label = tk.Label(
            result_frame, text="",
            font=("微软雅黑", 10), fg="#555"
        )
        self.detail_label.pack(pady=(0, 10))

        # ===== 历史记录 =====
        history_frame = tk.LabelFrame(self.root, text="化简历史", font=("微软雅黑", 10))
        history_frame.pack(padx=25, pady=5, fill=tk.BOTH, expand=True)

        self.history_list = tk.Listbox(history_frame, font=("Consolas", 10), height=6)
        self.history_list.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # ===== 按钮区 =====
        btn_frame = tk.Frame(self.root)
        btn_frame.pack(pady=10)

        tk.Button(
            btn_frame, text="约 分",
            width=12, height=2,
            bg="#4CAF50", fg="white",
            font=("微软雅黑", 11, "bold"),
            command=self.reduce_fraction
        ).pack(side=tk.LEFT, padx=8)

        tk.Button(
            btn_frame, text="求倒数",
            width=12, height=2,
            bg="#2196F3", fg="white",
            font=("微软雅黑", 11),
            command=self.reciprocal
        ).pack(side=tk.LEFT, padx=8)

        tk.Button(
            btn_frame, text="清 空",
            width=12, height=2,
            bg="#FF9800", fg="white",
            font=("微软雅黑", 11),
            command=self.clear
        ).pack(side=tk.LEFT, padx=8)

        tk.Button(
            btn_frame, text="重置历史",
            width=12, height=2,
            bg="#f44336", fg="white",
            font=("微软雅黑", 11),
            command=self.reset_history
        ).pack(side=tk.LEFT, padx=8)

        # 回车绑定
        self.root.bind("<Return>", lambda e: self.reduce_fraction())

    # ========== 核心逻辑 ==========
    def reduce_fraction(self):
        try:
            numerator = int(self.numerator_entry.get().strip())
            denominator = int(self.denominator_entry.get().strip())
        except ValueError:
            messagebox.showwarning("输入错误", "请输入整数！")
            return

        if denominator == 0:
            messagebox.showwarning("数学错误", "分母不能为 0！")
            return

        original = f"{numerator}/{denominator}"

        # 处理负数
        sign = 1
        if numerator * denominator < 0:
            sign = -1
        num = abs(numerator)
        den = abs(denominator)

        # 求最大公约数
        gcd = math.gcd(num, den)

        reduced_num = sign * (num // gcd)
        reduced_den = den // gcd

        # 显示最简分数
        if reduced_den == 1:
            result = f"{reduced_num}"
        else:
            result = f"{reduced_num}/{reduced_den}"

        # 带分数（仅对假分数）
        mixed = ""
        if abs(reduced_num) > reduced_den and reduced_den != 0:
            whole = abs(reduced_num) // reduced_den
            rem = abs(reduced_num) % reduced_den
            if rem != 0:
                if sign < 0:
                    mixed = f"-{whole} {rem}/{reduced_den}"
                else:
                    mixed = f"{whole} {rem}/{reduced_den}"

        detail = f"计算过程：\nGCD({num}, {den}) = {gcd}\n"
        detail += f"{numerator}/{denominator} = {result}"
        if mixed:
            detail += f"\n带分数形式：{mixed}"

        self.result_label.config(text=result)
        self.detail_label.config(text=detail)

        # 历史记录
        record = f"{original} → {result}"
        self.history.append(record)
        self.history_list.insert(tk.END, record)
        self.history_list.see(tk.END)

    def reciprocal(self):
        try:
            numerator = int(self.numerator_entry.get().strip())
            denominator = int(self.denominator_entry.get().strip())
        except ValueError:
            messagebox.showwarning("输入错误", "请输入整数！")
            return

        if numerator == 0:
            messagebox.showwarning("数学错误", "0 没有倒数！")
            return

        self.numerator_entry.delete(0, tk.END)
        self.denominator_entry.delete(0, tk.END)
        self.numerator_entry.insert(0, str(denominator))
        self.denominator_entry.insert(0, str(numerator))

        self.reduce_fraction()

    def clear(self):
        self.numerator_entry.delete(0, tk.END)
        self.denominator_entry.delete(0, tk.END)
        self.numerator_entry.insert(0, "0")
        self.denominator_entry.insert(0, "1")
        self.result_label.config(text="等待计算...")
        self.detail_label.config(text="")

    def reset_history(self):
        if messagebox.askyesno("确认", "清空历史记录？"):
            self.history.clear()
            self.history_list.delete(0, tk.END)

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