import re
import tkinter as tk
from tkinter import messagebox


PALETTE = {
    "bg": "#f4efe7",
    "panel": "#fffaf3",
    "hero": "#16324f",
    "hero_muted": "#d5e5f7",
    "border": "#d8cfc1",
    "text": "#1f2a36",
    "muted": "#66717e",
    "accent": "#e67e22",
    "accent_dark": "#bf6313",
    "accent_soft": "#fff1df",
    "success": "#1f8a70",
    "success_soft": "#e7f6f2",
    "alert": "#b85042",
}

PRICING_RULES = [
    ("1 - 10 页", "0.5 元 / 页", "最低 1 元"),
    ("11 - 50 页", "0.4 元 / 页", "最低 5 元"),
    ("51 - 100 页", "0.35 元 / 页", "按页计算"),
    ("101 - 500 页", "0.25 元 / 页", "按页计算"),
    ("501 页以上", "0.2 元 / 页", "按页计算"),
]

RULE_COLUMNS = 3
INFO_COLUMNS = 4
DEFAULT_WINDOW_WIDTH = 900
DEFAULT_WINDOW_HEIGHT = 640
MIN_WINDOW_WIDTH = 820
MIN_WINDOW_HEIGHT = 520


def parse_pages(text):
    tokens = [item for item in re.split(r"[+,\s，、]+", text.strip()) if item]
    if not tokens:
        raise ValueError("请输入页数，例如 8+14+16")

    pages = []
    for token in tokens:
        if not token.isdigit():
            raise ValueError("页数只能输入正整数，并用 +、逗号或空格分隔")
        value = int(token)
        if value <= 0:
            raise ValueError("页数必须大于 0")
        pages.append(value)

    return pages


def custom_round(price):
    integer = int(price)
    decimal = round(price - integer, 2)
    if decimal < 0.2:
        return float(integer)
    if decimal <= 0.7:
        return integer + 0.5
    return float(integer + 1)


def fmt_price(value):
    return str(int(value)) if float(value).is_integer() else f"{value:.1f}"


def calculate_price(total_pages):
    if 1 <= total_pages <= 10:
        unit_price = 0.5
        raw_price = total_pages * unit_price
        final_before_round = max(raw_price, 1.0)
        note = "已按 1 元最低消费计算" if raw_price < 1 else "按基础单价计算"
        tier = "小批量"
    elif 11 <= total_pages <= 50:
        unit_price = 0.4
        raw_price = total_pages * unit_price
        final_before_round = max(raw_price, 5.0)
        note = "已按 5 元最低消费计算" if raw_price < 5 else "按基础单价计算"
        tier = "常规批量"
    elif 51 <= total_pages <= 100:
        unit_price = 0.35
        raw_price = total_pages * unit_price
        final_before_round = raw_price
        note = "按基础单价计算"
        tier = "进阶批量"
    elif 101 <= total_pages <= 500:
        unit_price = 0.25
        raw_price = total_pages * unit_price
        final_before_round = raw_price
        note = "按基础单价计算"
        tier = "大批量"
    else:
        unit_price = 0.2
        raw_price = total_pages * unit_price
        final_before_round = raw_price
        note = "按基础单价计算"
        tier = "超大批量"

    final_price = custom_round(final_before_round)
    return {
        "unit_price": unit_price,
        "raw_price": raw_price,
        "final_price": final_price,
        "note": note,
        "tier": tier,
    }


class PrintPricingApp:
    def __init__(self, root):
        self.root = root
        self.root.title("打印价格计算器")
        self.root.configure(bg=PALETTE["bg"])

        self.input_var = tk.StringVar()
        self.status_var = tk.StringVar(value="输入页数后点击“立即计算”，支持 8+14+16 这种格式。")
        self.file_count_var = tk.StringVar(value="0 份文件")
        self.total_pages_var = tk.StringVar(value="0 页")
        self.input_preview_var = tk.StringVar(value="等待输入")
        self.tier_var = tk.StringVar(value="未计算")
        self.unit_price_var = tk.StringVar(value="0 元 / 页")
        self.raw_price_var = tk.StringVar(value="0 元")
        self.rounding_var = tk.StringVar(value="按规则取整")
        self.note_var = tk.StringVar(value="暂无说明")
        self.final_price_var = tk.StringVar(value="0 元")

        self.latest_summary = ""

        self.build_ui()
        self.auto_fit_window()
        self.root.bind("<Return>", lambda event: self.calculate())

    def auto_fit_window(self):
        self.root.update_idletasks()

        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        max_width = screen_width - 72 if screen_width > 72 else screen_width
        max_height = screen_height - 72 if screen_height > 72 else screen_height

        if max_width < MIN_WINDOW_WIDTH or max_height < MIN_WINDOW_HEIGHT:
            self.root.state("zoomed")
            return

        width = min(DEFAULT_WINDOW_WIDTH, max_width)
        height = min(DEFAULT_WINDOW_HEIGHT, max_height)

        x = max((screen_width - width) // 2, 0)
        y = max((screen_height - height) // 2, 0)

        self.root.geometry(f"{width}x{height}+{x}+{y}")
        self.root.minsize(min(MIN_WINDOW_WIDTH, max_width), min(MIN_WINDOW_HEIGHT, max_height))

    def build_ui(self):
        outer = tk.Frame(self.root, bg=PALETTE["bg"])
        outer.pack(fill="both", expand=True, padx=18, pady=16)

        self.build_hero(outer)

        content = tk.Frame(outer, bg=PALETTE["bg"])
        content.pack(fill="both", expand=True, pady=(12, 0))
        content.grid_columnconfigure(0, weight=11)
        content.grid_columnconfigure(1, weight=10)
        content.grid_rowconfigure(0, weight=1)

        left = tk.Frame(content, bg=PALETTE["panel"], highlightbackground=PALETTE["border"], highlightthickness=1)
        left.grid(row=0, column=0, sticky="nsew", padx=(0, 8))

        right = tk.Frame(content, bg=PALETTE["panel"], highlightbackground=PALETTE["border"], highlightthickness=1)
        right.grid(row=0, column=1, sticky="nsew", padx=(8, 0))

        self.build_input_panel(left)
        self.build_result_panel(right)

    def build_hero(self, parent):
        hero = tk.Frame(parent, bg=PALETTE["hero"], height=110)
        hero.pack(fill="x")
        hero.pack_propagate(False)

        stripe = tk.Frame(hero, bg=PALETTE["accent"], height=4)
        stripe.pack(fill="x", side="top")

        top = tk.Frame(hero, bg=PALETTE["hero"])
        top.pack(fill="both", expand=True, padx=22, pady=16)
        top.grid_columnconfigure(0, weight=1)

        text_block = tk.Frame(top, bg=PALETTE["hero"])
        text_block.grid(row=0, column=0, sticky="w")

        tk.Label(
            text_block,
            text="打印价格计算器",
            bg=PALETTE["hero"],
            fg="white",
            font=("Microsoft YaHei UI", 22, "bold"),
        ).pack(anchor="w")

        tk.Label(
            text_block,
            text="把命令行脚本升级成更清晰、更体面的报价界面，适合直接给同学或客户使用。",
            bg=PALETTE["hero"],
            fg=PALETTE["hero_muted"],
            font=("Microsoft YaHei UI", 9),
        ).pack(anchor="w", pady=(6, 0))

        badge = tk.Frame(top, bg=PALETTE["accent_soft"], padx=12, pady=8)
        badge.grid(row=0, column=1, sticky="e")

        tk.Label(
            badge,
            text="规则自动取整",
            bg=PALETTE["accent_soft"],
            fg=PALETTE["accent_dark"],
            font=("Bahnschrift", 9, "bold"),
        ).pack(anchor="e")

        tk.Label(
            badge,
            text="支持多文件合计、结果复制",
            bg=PALETTE["accent_soft"],
            fg=PALETTE["accent_dark"],
            font=("Microsoft YaHei UI", 9),
        ).pack(anchor="e", pady=(2, 0))

    def build_input_panel(self, parent):
        body = tk.Frame(parent, bg=PALETTE["panel"])
        body.pack(fill="both", expand=True, padx=18, pady=16)

        tk.Label(
            body,
            text="输入页数",
            bg=PALETTE["panel"],
            fg=PALETTE["text"],
            font=("Microsoft YaHei UI", 15, "bold"),
        ).pack(anchor="w")

        tk.Label(
            body,
            text="支持多个文件一起计算，可用 +、逗号、空格分隔。",
            bg=PALETTE["panel"],
            fg=PALETTE["muted"],
            font=("Microsoft YaHei UI", 9),
        ).pack(anchor="w", pady=(4, 12))

        input_card = tk.Frame(body, bg="white", highlightbackground=PALETTE["border"], highlightthickness=1)
        input_card.pack(fill="x")
        input_card.bind("<Button-3>", self.paste_into_entry)

        self.entry = tk.Entry(
            input_card,
            textvariable=self.input_var,
            relief="flat",
            bd=0,
            bg="white",
            fg=PALETTE["text"],
            insertbackground=PALETTE["text"],
            font=("Bahnschrift", 16),
        )
        self.entry.pack(fill="x", padx=14, pady=12)
        self.entry.bind("<Button-3>", self.paste_into_entry)
        self.entry.focus_set()

        tk.Label(
            body,
            text="示例：12+14+16    或    5, 8, 10",
            bg=PALETTE["panel"],
            fg=PALETTE["muted"],
            font=("Bahnschrift", 9),
        ).pack(anchor="w", pady=(8, 14))

        button_row = tk.Frame(body, bg=PALETTE["panel"])
        button_row.pack(fill="x")

        self.make_button(button_row, "立即计算", PALETTE["accent"], "white", self.calculate).pack(side="left")
        self.make_button(button_row, "重新复制", PALETTE["success"], "white", self.copy_result).pack(side="left", padx=8)
        self.make_button(button_row, "清空重填", "#e9dfd2", PALETTE["text"], self.reset).pack(side="left")

        status_frame = tk.Frame(body, bg=PALETTE["accent_soft"], padx=10, pady=8)
        status_frame.pack(fill="x", pady=(16, 14))

        tk.Label(
            status_frame,
            textvariable=self.status_var,
            bg=PALETTE["accent_soft"],
            fg=PALETTE["accent_dark"],
            justify="left",
            wraplength=290,
            font=("Microsoft YaHei UI", 9),
        ).pack(anchor="w")

        tk.Label(
            body,
            text="计价规则",
            bg=PALETTE["panel"],
            fg=PALETTE["text"],
            font=("Microsoft YaHei UI", 14, "bold"),
        ).pack(anchor="w", pady=(4, 10))

        rules_panel = tk.Frame(body, bg=PALETTE["panel"])
        rules_panel.pack(fill="x")

        for column in range(RULE_COLUMNS):
            rules_panel.grid_columnconfigure(column, weight=1)

        for idx, (page_range, price, note) in enumerate(PRICING_RULES, start=1):
            row = (idx - 1) // RULE_COLUMNS
            column = (idx - 1) % RULE_COLUMNS
            self.make_rule_tile(rules_panel, idx, page_range, price, note, row, column)

    def build_result_panel(self, parent):
        body = tk.Frame(parent, bg=PALETTE["panel"])
        body.pack(fill="both", expand=True, padx=18, pady=16)

        tk.Label(
            body,
            text="计算结果",
            bg=PALETTE["panel"],
            fg=PALETTE["text"],
            font=("Microsoft YaHei UI", 15, "bold"),
        ).pack(anchor="w")

        tk.Label(
            body,
            text="右侧会展示汇总页数、计价档位、原始金额和最终报价。",
            bg=PALETTE["panel"],
            fg=PALETTE["muted"],
            font=("Microsoft YaHei UI", 9),
        ).pack(anchor="w", pady=(4, 12))

        total_card = tk.Frame(body, bg=PALETTE["hero"], padx=16, pady=14)
        total_card.pack(fill="x")

        tk.Label(
            total_card,
            text="最终应付总价",
            bg=PALETTE["hero"],
            fg=PALETTE["hero_muted"],
            font=("Microsoft YaHei UI", 9),
        ).pack(anchor="w")

        tk.Label(
            total_card,
            textvariable=self.final_price_var,
            bg=PALETTE["hero"],
            fg="white",
            font=("Bahnschrift", 24, "bold"),
        ).pack(anchor="w", pady=(8, 0))

        info_grid = tk.Frame(body, bg=PALETTE["panel"])
        info_grid.pack(fill="x", pady=(12, 0))
        for column in range(INFO_COLUMNS):
            info_grid.grid_columnconfigure(column, weight=1)

        info_items = [
            ("输入预览", self.input_preview_var),
            ("文件数量", self.file_count_var),
            ("总页数", self.total_pages_var),
            ("计价档位", self.tier_var),
            ("适用单价", self.unit_price_var),
            ("原始金额", self.raw_price_var),
            ("取整结果", self.rounding_var),
            ("备注说明", self.note_var),
        ]

        for idx, (title, variable) in enumerate(info_items):
            row = idx // INFO_COLUMNS
            column = idx % INFO_COLUMNS
            self.make_info_tile(info_grid, title, variable, row, column)

        footer = tk.Frame(body, bg=PALETTE["success_soft"], padx=12, pady=10)
        footer.pack(fill="x", pady=(14, 0))

        tk.Label(
            footer,
            text="取整规则：小数低于 0.2 直接舍去，0.2 到 0.7 记为 0.5，高于 0.7 进 1。",
            bg=PALETTE["success_soft"],
            fg=PALETTE["success"],
            wraplength=300,
            justify="left",
            font=("Microsoft YaHei UI", 9),
        ).pack(anchor="w")

    def make_rule_tile(self, parent, idx, page_range, price, note, row, column):
        card = tk.Frame(
            parent,
            bg=PALETTE["bg"],
            highlightbackground=PALETTE["border"],
            highlightthickness=1,
            padx=10,
            pady=8,
        )
        card.grid(row=row, column=column, sticky="nsew", padx=4, pady=4)

        head = tk.Frame(card, bg=PALETTE["bg"])
        head.pack(fill="x")

        tk.Label(
            head,
            text=f"{idx:02d}",
            bg=PALETTE["accent_soft"],
            fg=PALETTE["accent_dark"],
            font=("Bahnschrift", 8, "bold"),
            padx=6,
            pady=2,
        ).pack(side="left")

        tk.Label(
            head,
            text=page_range,
            bg=PALETTE["bg"],
            fg=PALETTE["text"],
            font=("Microsoft YaHei UI", 9, "bold"),
        ).pack(side="left", padx=(6, 0))

        tk.Label(
            card,
            text=price,
            bg=PALETTE["bg"],
            fg=PALETTE["accent_dark"],
            font=("Bahnschrift", 10, "bold"),
        ).pack(anchor="w", pady=(8, 2))

        tk.Label(
            card,
            text=note,
            bg=PALETTE["bg"],
            fg=PALETTE["muted"],
            font=("Microsoft YaHei UI", 7),
        ).pack(anchor="w")

    def make_info_tile(self, parent, title, variable, row, column):
        tile = tk.Frame(parent, bg=PALETTE["bg"], padx=10, pady=10)
        tile.grid(row=row, column=column, sticky="nsew", padx=4, pady=4)

        tk.Label(
            tile,
            text=title,
            bg=PALETTE["bg"],
            fg=PALETTE["muted"],
            font=("Microsoft YaHei UI", 8),
        ).pack(anchor="w")

        tk.Label(
            tile,
            textvariable=variable,
            bg=PALETTE["bg"],
            fg=PALETTE["text"],
            wraplength=110,
            justify="left",
            font=("Microsoft YaHei UI", 10, "bold"),
        ).pack(anchor="w", pady=(6, 0))

    def make_button(self, parent, text, bg, fg, command):
        button = tk.Button(
            parent,
            text=text,
            command=command,
            relief="flat",
            bd=0,
            padx=14,
            pady=8,
            bg=bg,
            fg=fg,
            activebackground=bg if bg == "#e9dfd2" else self.darken(bg),
            activeforeground=fg,
            cursor="hand2",
            font=("Microsoft YaHei UI", 9, "bold"),
        )
        return button

    def darken(self, color):
        color = color.lstrip("#")
        rgb = [max(0, int(color[i:i + 2], 16) - 18) for i in (0, 2, 4)]
        return "#{:02x}{:02x}{:02x}".format(*rgb)

    def paste_into_entry(self, event=None):
        try:
            clipboard_text = self.root.clipboard_get()
        except tk.TclError:
            self.status_var.set("剪贴板里没有可粘贴的内容。")
            return "break"

        clipboard_text = re.sub(r"[\r\n\t]+", " ", clipboard_text).strip()
        if not clipboard_text:
            self.status_var.set("剪贴板里没有可粘贴的内容。")
            return "break"

        self.entry.focus_set()
        self.input_var.set(clipboard_text)
        self.entry.icursor(tk.END)
        self.calculate()
        return "break"

    def calculate(self):
        user_input = self.input_var.get()

        try:
            pages = parse_pages(user_input)
        except ValueError as exc:
            self.status_var.set(str(exc))
            self.input_preview_var.set("输入无效")
            self.file_count_var.set("0 份文件")
            self.total_pages_var.set("0 页")
            self.tier_var.set("未计算")
            self.unit_price_var.set("0 元 / 页")
            self.raw_price_var.set("0 元")
            self.rounding_var.set("按规则取整")
            self.note_var.set("输入有误")
            self.final_price_var.set("0 元")
            self.latest_summary = ""
            return

        total_pages = sum(pages)
        file_count = len(pages)
        result = calculate_price(total_pages)

        preview = " + ".join(str(page) for page in pages)
        final_price = fmt_price(result["final_price"])

        self.input_preview_var.set(preview)
        self.file_count_var.set(f"{file_count} 份文件")
        self.total_pages_var.set(f"{total_pages} 页")
        self.tier_var.set(result["tier"])
        self.unit_price_var.set(f"{result['unit_price']} 元 / 页")
        self.raw_price_var.set(f"{total_pages} × {result['unit_price']} = {result['raw_price']:.2f} 元")
        self.rounding_var.set(f"{final_price} 元")
        self.note_var.set(result["note"])
        self.final_price_var.set(f"{final_price} 元")
        self.status_var.set("计算完成，可以直接复制报价内容发给对方。")

        self.latest_summary = (
            f"文件数量：{file_count} 份\n"
            f"总打印页数：{total_pages} 页\n\n"
            f"最终应付总价：{final_price} 元"
        )
        if self.copy_result(show_prompt=False):
            self.status_var.set("计算完成，报价内容已自动复制到剪贴板。")
        else:
            self.status_var.set("计算完成，但自动复制失败，请点击“重新复制”。")

    def copy_result(self, show_prompt=True):
        if not self.latest_summary:
            if show_prompt:
                messagebox.showinfo("提示", "请先完成一次计算，再复制报价。")
            return False

        try:
            self.root.clipboard_clear()
            self.root.clipboard_append(self.latest_summary)
            self.root.update()
        except tk.TclError:
            if show_prompt:
                messagebox.showerror("提示", "复制失败，请稍后再试。")
            return False

        if show_prompt:
            self.status_var.set("报价内容已复制到剪贴板。")
        return True

    def reset(self):
        self.input_var.set("")
        self.status_var.set("输入页数后点击“立即计算”，支持 8+14+16 这种格式。")
        self.file_count_var.set("0 份文件")
        self.total_pages_var.set("0 页")
        self.input_preview_var.set("等待输入")
        self.tier_var.set("未计算")
        self.unit_price_var.set("0 元 / 页")
        self.raw_price_var.set("0 元")
        self.rounding_var.set("按规则取整")
        self.note_var.set("暂无说明")
        self.final_price_var.set("0 元")
        self.latest_summary = ""
        self.entry.focus_set()


def main():
    root = tk.Tk()
    PrintPricingApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()
