import tkinter as tk
from tkinter import messagebox
import math
import random
import json
import os

COLORS_FILE = "saved_colors.json"

# ==================== 色彩工具 ====================
def hsv_to_rgb(h, s, v):
    h = h % 360
    s /= 100
    v /= 100

    c = v * s
    x = c * (1 - abs((h / 60) % 2 - 1))
    m = v - c

    if 0 <= h < 60:
        r, g, b = c, x, 0
    elif 60 <= h < 120:
        r, g, b = x, c, 0
    elif 120 <= h < 180:
        r, g, b = 0, c, x
    elif 180 <= h < 240:
        r, g, b = 0, x, c
    elif 240 <= h < 300:
        r, g, b = x, 0, c
    else:
        r, g, b = c, 0, x

    return int((r + m) * 255), int((g + m) * 255), int((b + m) * 255)


def rgb_to_hex(r, g, b):
    return f"#{r:02X}{g:02X}{b:02X}"


def luminance(r, g, b):
    rs = r / 255
    gs = g / 255
    bs = b / 255
    rs = rs / 12.92 if rs <= 0.03928 else ((rs + 0.055) / 1.055) ** 2.4
    gs = gs / 12.92 if gs <= 0.03928 else ((gs + 0.055) / 1.055) ** 2.4
    bs = bs / 12.92 if bs <= 0.03928 else ((bs + 0.055) / 1.055) ** 2.4
    return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs


def contrast_ratio(rgb1, rgb2):
    l1 = luminance(*rgb1)
    l2 = luminance(*rgb2)
    return (max(l1, l2) + 0.05) / (min(l1, l2) + 0.05)


# ==================== 配色方案 ====================
class PaletteGenerator:
    def random_color(self):
        return random.randint(0, 359)

    def complementary(self):
        h = self.random_color()
        return [h, (h + 180) % 360]

    def analogous(self):
        h = self.random_color()
        return [h, (h + 30) % 360, (h - 30) % 360]

    def triadic(self):
        h = self.random_color()
        return [h, (h + 120) % 360, (h + 240) % 360]

    def monochromatic(self, h):
        return [(h, s, v) for s in [30, 60, 90] for v in [40, 70]]


# ==================== 主程序 ====================
class ColorPaletteApp:
    def __init__(self, root):
        self.root = root
        self.root.title("041. 配色练习")
        self.root.geometry("720x580")
        self.root.resizable(False, False)

        self.gen = PaletteGenerator()
        self.saved = []
        self.current_colors = []

        self.load_colors()
        self.build_ui()
        self.generate("互补色")

    def load_colors(self):
        if os.path.exists(COLORS_FILE):
            try:
                with open(COLORS_FILE, "r", encoding="utf-8") as f:
                    self.saved = json.load(f)
            except:
                self.saved = []

    def save_colors(self):
        with open(COLORS_FILE, "w", encoding="utf-8") as f:
            json.dump(self.saved, f, ensure_ascii=False, indent=2)

    def build_ui(self):
        tk.Label(
            self.root, text="🎨 配色练习工具",
            font=("微软雅黑", 18, "bold")
        ).pack(pady=10)

        # ===== 方案选择 =====
        scheme_frame = tk.Frame(self.root)
        scheme_frame.pack(pady=5)

        schemes = ["互补色", "类似色", "三角色", "随机"]
        for s in schemes:
            tk.Button(
                scheme_frame, text=s, width=10,
                command=lambda sc=s: self.generate(sc)
            ).pack(side=tk.LEFT, padx=5)

        # ===== 配色展示 =====
        self.palette_frame = tk.LabelFrame(self.root, text="配色方案", font=("微软雅黑", 10))
        self.palette_frame.pack(padx=20, pady=10, fill=tk.X)

        self.color_blocks = []
        self.color_labels = []

        for i in range(5):
            block = tk.Label(self.palette_frame, width=12, height=6, relief=tk.RAISED, bd=3)
            block.grid(row=0, column=i, padx=5, pady=10)
            block.bind("<Button-1>", self.show_detail)
            self.color_blocks.append(block)

            label = tk.Label(self.palette_frame, font=("Consolas", 9))
            label.grid(row=1, column=i, padx=5)
            self.color_labels.append(label)

        # ===== 文字可读性测试 =====
        self.text_test = tk.Label(
            self.root, text="AaBbCc 文字可读性测试",
            font=("微软雅黑", 16, "bold")
        )
        self.text_test.pack(pady=10)

        # ===== 操作按钮 =====
        btn_frame = tk.Frame(self.root)
        btn_frame.pack(pady=5)

        tk.Button(
            btn_frame, text="收藏此配色",
            width=14, bg="#4CAF50", fg="white",
            command=self.save_palette
        ).pack(side=tk.LEFT, padx=8)

        tk.Button(
            btn_frame, text="查看收藏",
            width=14, bg="#2196F3", fg="white",
            command=self.show_saved
        ).pack(side=tk.LEFT, padx=8)

        tk.Button(
            btn_frame, text="清空收藏",
            width=14, bg="#f44336", fg="white",
            command=self.clear_saved
        ).pack(side=tk.LEFT, padx=8)

        # ===== 详情区 =====
        self.detail_label = tk.Label(
            self.root, text="点击色块查看详细信息",
            font=("Consolas", 10), fg="#555"
        )
        self.detail_label.pack(pady=10)

    def generate(self, scheme):
        self.current_colors.clear()

        if scheme == "互补色":
            hues = self.gen.complementary()
        elif scheme == "类似色":
            hues = self.gen.analogous()
        elif scheme == "三角色":
            hues = self.gen.triadic()
        else:
            hues = [self.gen.random_color() for _ in range(5)]

        # 补全到 5 个
        while len(hues) < 5:
            hues.append(self.gen.random_color())

        for h in hues[:5]:
            s = random.randint(40, 90)
            v = random.randint(50, 95)
            self.current_colors.append((h, s, v))

        self.render_palette()

    def render_palette(self):
        for i, (h, s, v) in enumerate(self.current_colors):
            r, g, b = hsv_to_rgb(h, s, v)
            hex_color = rgb_to_hex(r, g, b)

            self.color_blocks[i].config(bg=hex_color)
            self.color_labels[i].config(text=f"{hex_color}\nHSV({h:.0f},{s:.0f},{v:.0f})")

        # 文字可读性测试（用第一个颜色）
        r, g, b = hsv_to_rgb(*self.current_colors[0])
        contrast = contrast_ratio((r, g, b), (255, 255, 255))
        self.text_test.config(
            bg=rgb_to_hex(r, g, b),
            fg="#FFFFFF" if contrast >= 4.5 else "#000000"
        )
        self.detail_label.config(text="点击色块查看详细信息")

    def show_detail(self, e):
        widget = e.widget
        idx = self.color_blocks.index(widget)
        h, s, v = self.current_colors[idx]
        r, g, b = hsv_to_rgb(h, s, v)
        hex_color = rgb_to_hex(r, g, b)

        contrast_w = contrast_ratio((r, g, b), (255, 255, 255))
        contrast_b = contrast_ratio((r, g, b), (0, 0, 0))

        self.detail_label.config(
            text=f"HEX: {hex_color}\n"
                 f"RGB: {r}, {g}, {b}\n"
                 f"HSV: {h:.1f}°, {s:.1f}%, {v:.1f}%\n"
                 f"对比度(白): {contrast_w:.2f}\n"
                 f"对比度(黑): {contrast_b:.2f}"
        )

    def save_palette(self):
        hex_colors = [
            rgb_to_hex(*hsv_to_rgb(h, s, v))
            for h, s, v in self.current_colors
        ]
        self.saved.append(hex_colors)
        self.save_colors()
        messagebox.showinfo("已保存", "配色方案已收藏！")

    def show_saved(self):
        if not self.saved:
            messagebox.showinfo("提示", "暂无收藏的配色")
            return

        win = tk.Toplevel(self.root)
        win.title("收藏的配色")
        win.geometry("600x400")

        for row, palette in enumerate(self.saved):
            for col, hex_color in enumerate(palette):
                lbl = tk.Label(win, bg=hex_color, width=10, height=3, relief=tk.RAISED)
                lbl.grid(row=row, column=col, padx=3, pady=3)
                lbl.bind("<Button-1>", lambda e, h=hex_color: self.apply_hex(h))

    def apply_hex(self, hex_color):
        # 简单应用：用第一个颜色生成类似色
        r = int(hex_color[1:3], 16)
        g = int(hex_color[3:5], 16)
        b = int(hex_color[5:7], 16)

        # 粗略估算 HSV（演示用）
        h = (r + g + b) % 360
        self.current_colors = [
            (h, 70, 80),
            ((h + 30) % 360, 60, 70),
            ((h + 60) % 360, 50, 60),
            ((h + 90) % 360, 40, 50),
            ((h + 120) % 360, 30, 40)
        ]
        self.render_palette()

    def clear_saved(self):
        if messagebox.askyesno("确认", "清空所有收藏的配色？"):
            self.saved.clear()
            self.save_colors()


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