import tkinter as tk
from tkinter import ttk, filedialog, messagebox, colorchooser
import os
import time
import subprocess
import platform
import json
import shutil

# ========== 全局配置 ==========
USERS_FILE = "users.json"
AVATAR_DIR = "avatars"
PRESET_COLORS = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7", "#DDA0DD", "#74b9ff", "#fdcb6e"]
os.makedirs(AVATAR_DIR, exist_ok=True)

# ========== 数据持久化工具 ==========
def load_users():
    if os.path.exists(USERS_FILE):
        try:
            with open(USERS_FILE, "r", encoding="utf-8") as f:
                return json.load(f)
        except:
            return {}
    return {}

def save_users(users):
    with open(USERS_FILE, "w", encoding="utf-8") as f:
        json.dump(users, f, ensure_ascii=False, indent=2)

# ========== 登录窗口 ==========
class LoginWindow:
    def __init__(self, root):
        self.root = root
        self.root.title("登录 - 朋友圈")
        self.root.geometry("400x300")
        self.root.configure(bg="#f0f2f5")
        self.users = load_users()
        self.center_window(400, 300)

        tk.Label(root, text="朋友圈", font=("微软雅黑", 20, "bold"), bg="#f0f2f5", fg="#07c160").pack(pady=30)

        form = tk.Frame(root, bg="#f0f2f5")
        form.pack(pady=10)

        tk.Label(form, text="用户名：", font=("微软雅黑", 11), bg="#f0f2f5").grid(row=0, column=0, pady=8, sticky="e")
        self.user_entry = tk.Entry(form, font=("微软雅黑", 11), width=18)
        self.user_entry.grid(row=0, column=1, pady=8)

        tk.Label(form, text="密  码：", font=("微软雅黑", 11), bg="#f0f2f5").grid(row=1, column=0, pady=8, sticky="e")
        self.pwd_entry = tk.Entry(form, font=("微软雅黑", 11), width=18, show="*")
        self.pwd_entry.grid(row=1, column=1, pady=8)

        btn_frame = tk.Frame(root, bg="#f0f2f5")
        btn_frame.pack(pady=20)
        tk.Button(btn_frame, text="登录", command=self.login, width=10, bg="#07c160", fg="white",
                  font=("微软雅黑", 10, "bold"), bd=0, cursor="hand2").grid(row=0, column=0, padx=10)
        tk.Button(btn_frame, text="注册", command=self.open_register, width=10, bg="#ffffff", fg="#333",
                  font=("微软雅黑", 10), bd=1, cursor="hand2").grid(row=0, column=1, padx=10)

    def center_window(self, w, h):
        sw, sh = self.root.winfo_screenwidth(), self.root.winfo_screenheight()
        self.root.geometry(f"{w}x{h}+{(sw-w)//2}+{(sh-h)//2}")

    def login(self):
        username = self.user_entry.get().strip()
        password = self.pwd_entry.get().strip()
        if not username or not password:
            messagebox.showwarning("提示", "用户名和密码不能为空")
            return
        if username not in self.users:
            messagebox.showerror("错误", "用户名不存在")
            return
        if self.users[username]["password"] != password:
            messagebox.showerror("错误", "密码错误")
            return

        # 登录成功，进入主界面
        self.root.destroy()
        main_root = tk.Tk()
        MomentsApp(main_root, username)
        main_root.mainloop()

    def open_register(self):
        RegisterWindow(tk.Toplevel(self.root), self)

# ========== 注册窗口 ==========
class RegisterWindow:
    def __init__(self, root, login_win):
        self.root = root
        self.login_win = login_win
        self.root.title("注册账号")
        self.root.geometry("420x520")
        self.root.configure(bg="#f0f2f5")
        self.root.resizable(False, False)

        self.avatar_type = "color"
        self.avatar_value = PRESET_COLORS[0]
        self.avatar_img_path = ""

        tk.Label(root, text="注册新账号", font=("微软雅黑", 16, "bold"), bg="#f0f2f5", fg="#333").pack(pady=15)
        form = tk.Frame(root, bg="#f0f2f5")
        form.pack(pady=5)

        # 用户名
        tk.Label(form, text="用户名：", font=("微软雅黑", 10), bg="#f0f2f5").grid(row=0, column=0, pady=8, sticky="e")
        self.user_entry = tk.Entry(form, font=("微软雅黑", 10), width=22)
        self.user_entry.grid(row=0, column=1, pady=8, columnspan=2, sticky="w")

        # 密码
        tk.Label(form, text="密  码：", font=("微软雅黑", 10), bg="#f0f2f5").grid(row=1, column=0, pady=8, sticky="e")
        self.pwd_entry = tk.Entry(form, font=("微软雅黑", 10), width=22, show="*")
        self.pwd_entry.grid(row=1, column=1, pady=8, columnspan=2, sticky="w")
        tk.Label(form, text="(8-12位)", font=("微软雅黑", 9), bg="#f0f2f5", fg="#999").grid(row=1, column=3, sticky="w")

        # 确认密码
        tk.Label(form, text="确认密码：", font=("微软雅黑", 10), bg="#f0f2f5").grid(row=2, column=0, pady=8, sticky="e")
        self.pwd2_entry = tk.Entry(form, font=("微软雅黑", 10), width=22, show="*")
        self.pwd2_entry.grid(row=2, column=1, pady=8, columnspan=2, sticky="w")

        # 头像选择
        tk.Label(form, text="头  像：", font=("微软雅黑", 10), bg="#f0f2f5").grid(row=3, column=0, pady=8, sticky="ne")
        avatar_frame = tk.Frame(form, bg="#f0f2f5")
        avatar_frame.grid(row=3, column=1, columnspan=3, sticky="w", pady=8)

        self.avatar_canvas = tk.Canvas(avatar_frame, width=50, height=50, bg="#f0f2f5", bd=0, highlightthickness=0)
        self.avatar_canvas.pack(side="left", padx=(0, 10))
        self.draw_avatar_preview()

        tk.Button(avatar_frame, text="上传图片", command=self.upload_avatar, font=("微软雅黑", 9),
                  bg="#e8f0fe", fg="#1a73e8", bd=0, cursor="hand2", width=8).pack(side="left", padx=2)
        tk.Button(avatar_frame, text="自定义色", command=self.choose_color, font=("微软雅黑", 9),
                  bg="#e8f0fe", fg="#1a73e8", bd=0, cursor="hand2", width=8).pack(side="left", padx=2)

        # 预设快选色
        color_bar = tk.Frame(form, bg="#f0f2f5")
        color_bar.grid(row=4, column=1, columnspan=3, sticky="w", pady=2)
        tk.Label(color_bar, text="快速选色：", font=("微软雅黑", 9), bg="#f0f2f5", fg="#666").pack(side="left")
        for c in PRESET_COLORS:
            tk.Button(color_bar, bg=c, width=2, bd=0, cursor="hand2",
                      command=lambda col=c: self.set_preset_color(col)).pack(side="left", padx=2)

        # 性别
        tk.Label(form, text="性  别：", font=("微软雅黑", 10), bg="#f0f2f5").grid(row=5, column=0, pady=8, sticky="e")
        self.gender_var = tk.StringVar(value="")
        gender_frame = tk.Frame(form, bg="#f0f2f5")
        gender_frame.grid(row=5, column=1, columnspan=2, sticky="w")
        tk.Radiobutton(gender_frame, text="男", variable=self.gender_var, value="男", bg="#f0f2f5", font=("微软雅黑", 10)).pack(side="left", padx=5)
        tk.Radiobutton(gender_frame, text="女", variable=self.gender_var, value="女", bg="#f0f2f5", font=("微软雅黑", 10)).pack(side="left", padx=5)
        tk.Radiobutton(gender_frame, text="保密", variable=self.gender_var, value="", bg="#f0f2f5", font=("微软雅黑", 10)).pack(side="left", padx=5)

        # 电话
        tk.Label(form, text="电  话：", font=("微软雅黑", 10), bg="#f0f2f5").grid(row=6, column=0, pady=8, sticky="e")
        self.phone_entry = tk.Entry(form, font=("微软雅黑", 10), width=22)
        self.phone_entry.grid(row=6, column=1, pady=8, columnspan=2, sticky="w")
        tk.Label(form, text="(选填)", font=("微软雅黑", 9), bg="#f0f2f5", fg="#999").grid(row=6, column=3, sticky="w")

        tk.Button(root, text="完成注册", command=self.do_register, width=15, bg="#07c160", fg="white",
                  font=("微软雅黑", 11, "bold"), bd=0, cursor="hand2").pack(pady=20)

    def draw_avatar_preview(self):
        self.avatar_canvas.delete("all")
        if self.avatar_type == "color":
            self.avatar_canvas.create_oval(2, 2, 48, 48, fill=self.avatar_value, outline="")
        else:
            try:
                img = tk.PhotoImage(file=self.avatar_value)
                scale = max(img.width()//50, 1)
                img = img.subsample(scale, scale)
                self.avatar_canvas.image = img
                self.avatar_canvas.create_image(25, 25, image=img)
            except:
                self.avatar_canvas.create_oval(2, 2, 48, 48, fill="#cccccc", outline="")
                messagebox.showwarning("提示", "仅支持PNG/GIF格式头像，已自动切换为色块")
                self.avatar_type = "color"
                self.avatar_value = PRESET_COLORS[0]
                self.draw_avatar_preview()

    def upload_avatar(self):
        path = filedialog.askopenfilename(filetypes=[("图片文件", "*.png *.gif"), ("所有文件", "*.*")])
        if path:
            self.avatar_type = "image"
            self.avatar_value = path
            self.avatar_img_path = path
            self.draw_avatar_preview()

    def choose_color(self):
        color = colorchooser.askcolor(title="选择头像颜色")[1]
        if color:
            self.avatar_type = "color"
            self.avatar_value = color
            self.draw_avatar_preview()

    def set_preset_color(self, color):
        self.avatar_type = "color"
        self.avatar_value = color
        self.draw_avatar_preview()

    def do_register(self):
        username = self.user_entry.get().strip()
        pwd = self.pwd_entry.get().strip()
        pwd2 = self.pwd2_entry.get().strip()
        gender = self.gender_var.get()
        phone = self.phone_entry.get().strip()

        if not username:
            messagebox.showwarning("提示", "用户名不能为空")
            return
        if len(pwd) < 8 or len(pwd) > 12:
            messagebox.showwarning("提示", "密码长度必须为8-12位")
            return
        if pwd != pwd2:
            messagebox.showerror("错误", "两次输入的密码不一致")
            return

        users = load_users()
        if username in users:
            messagebox.showerror("错误", "用户名已存在，请换一个")
            return

        # 复制头像到本地目录
        avatar_final = self.avatar_value
        if self.avatar_type == "image" and self.avatar_img_path:
            ext = os.path.splitext(self.avatar_img_path)[1].lower()
            save_path = os.path.join(AVATAR_DIR, f"{username}{ext}")
            try:
                shutil.copy(self.avatar_img_path, save_path)
                avatar_final = save_path
            except:
                messagebox.showerror("错误", "头像保存失败，将使用默认色块")
                self.avatar_type = "color"
                avatar_final = PRESET_COLORS[0]

        users[username] = {
            "password": pwd,
            "avatar_type": self.avatar_type,
            "avatar_value": avatar_final,
            "gender": gender,
            "phone": phone,
            "moments": []
        }
        save_users(users)
        messagebox.showinfo("成功", "注册成功，请登录")
        self.root.destroy()
        self.login_win.users = load_users()

# ========== 朋友圈主界面 ==========
class MomentsApp:
    def __init__(self, root, username):
        self.root = root
        self.username = username
        self.users = load_users()
        self.user_data = self.users[username]

        self.root.title(f"朋友圈 - {username}")
        self.root.geometry("680x720")
        self.root.configure(bg="#f0f2f5")

        self.moments = self.user_data.get("moments", [])
        self.selected_files = []
        self.avatar_ref = None

        # 顶部用户栏
        user_bar = tk.Frame(root, bg="white", bd=1, relief="solid")
        user_bar.pack(fill="x", padx=15, pady=(10, 5))

        self.avatar_canvas = tk.Canvas(user_bar, width=50, height=50, bg="white", bd=0, highlightthickness=0, cursor="hand2")
        self.avatar_canvas.pack(side="left", padx=12, pady=10)
        self.avatar_canvas.bind("<Button-1>", lambda e: self.show_profile())
        self.draw_top_avatar()

        tk.Label(user_bar, text=username, bg="white", font=("微软雅黑", 13, "bold"), fg="#333").pack(side="left", padx=5)

        # 发布区
        pub_frame = tk.Frame(root, bg="#ffffff", bd=1, relief="solid")
        pub_frame.pack(fill="x", padx=15, pady=5)

        tk.Label(pub_frame, text="发布新动态", bg="#ffffff",
                 font=("微软雅黑", 12, "bold"), fg="#333").pack(anchor="w", padx=12, pady=(10, 5))

        self.text_input = tk.Text(pub_frame, height=4, font=("微软雅黑", 10),
                                  bd=1, relief="solid", wrap="word")
        self.text_input.pack(fill="x", padx=12, pady=5)
        self.text_input.insert("1.0", "分享新鲜事...")
        self.text_input.bind("<FocusIn>", self.clear_placeholder)

        self.file_show = tk.Frame(pub_frame, bg="#ffffff")
        self.file_show.pack(fill="x", padx=12, pady=3)

        btn_bar = tk.Frame(pub_frame, bg="#ffffff")
        btn_bar.pack(fill="x", padx=12, pady=(3, 10))
        tk.Button(btn_bar, text="📎 添加文件", command=self.add_files,
                  bg="#e8f0fe", fg="#1a73e8", bd=0, font=("微软雅黑", 10),
                  width=12, cursor="hand2").pack(side="left")
        tk.Button(btn_bar, text="发布", command=self.publish,
                  bg="#07c160", fg="white", bd=0, font=("微软雅黑", 10, "bold"),
                  width=10, cursor="hand2").pack(side="right")

        # 动态滚动区
        list_bg = tk.Frame(root, bg="#f0f2f5")
        list_bg.pack(fill="both", expand=True, padx=15, pady=(0, 10))

        self.canvas = tk.Canvas(list_bg, bg="#f0f2f5", bd=0, highlightthickness=0)
        scrollbar = ttk.Scrollbar(list_bg, orient="vertical", command=self.canvas.yview)
        self.scroll_frame = tk.Frame(self.canvas, bg="#f0f2f5")

        self.scroll_frame.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all")))
        self.canvas.create_window((0, 0), window=self.scroll_frame, anchor="nw")
        self.canvas.configure(yscrollcommand=scrollbar.set)
        self.canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        self.canvas.bind_all("<MouseWheel>", self.on_mousewheel)

        self.render_moments()

    def draw_top_avatar(self):
        self.avatar_canvas.delete("all")
        atype, aval = self.user_data["avatar_type"], self.user_data["avatar_value"]
        if atype == "color":
            self.avatar_canvas.create_oval(2, 2, 48, 48, fill=aval, outline="")
        else:
            try:
                img = tk.PhotoImage(file=aval)
                scale = max(img.width()//50, 1)
                img = img.subsample(scale, scale)
                self.avatar_ref = img
                self.avatar_canvas.create_image(25, 25, image=img)
            except:
                self.avatar_canvas.create_oval(2, 2, 48, 48, fill="#cccccc", outline="")

    def show_profile(self):
        win = tk.Toplevel(self.root)
        win.title("个人资料")
        win.geometry("320x400")
        win.configure(bg="#f0f2f5")
        win.resizable(False, False)

        # 大头像
        big_avt = tk.Canvas(win, width=100, height=100, bg="#f0f2f5", bd=0, highlightthickness=0)
        big_avt.pack(pady=20)
        atype, aval = self.user_data["avatar_type"], self.user_data["avatar_value"]
        if atype == "color":
            big_avt.create_oval(2, 2, 98, 98, fill=aval, outline="")
        else:
            try:
                img = tk.PhotoImage(file=aval)
                scale = max(img.width()//100, 1)
                img = img.subsample(scale, scale)
                win.avt_img = img
                big_avt.create_image(50, 50, image=img)
            except:
                big_avt.create_oval(2, 2, 98, 98, fill="#cccccc", outline="")

        tk.Label(win, text=self.username, font=("微软雅黑", 16, "bold"), bg="#f0f2f5", fg="#333").pack(pady=5)

        # 信息卡片
        card = tk.Frame(win, bg="white", bd=1, relief="solid")
        card.pack(fill="x", padx=30, pady=15)

        gender = self.user_data.get("gender", "")
        if gender:
            row = tk.Frame(card, bg="white")
            row.pack(fill="x", padx=15, pady=8)
            tk.Label(row, text="性别：", font=("微软雅黑", 10), bg="white", fg="#666").pack(side="left")
            tk.Label(row, text=gender, font=("微软雅黑", 10), bg="white", fg="#333").pack(side="right")

        phone = self.user_data.get("phone", "")
        if phone:
            row = tk.Frame(card, bg="white")
            row.pack(fill="x", padx=15, pady=8)
            tk.Label(row, text="电话：", font=("微软雅黑", 10), bg="white", fg="#666").pack(side="left")
            tk.Label(row, text=phone, font=("微软雅黑", 10), bg="white", fg="#333").pack(side="right")

        row = tk.Frame(card, bg="white")
        row.pack(fill="x", padx=15, pady=8)
        tk.Label(row, text="发布动态：", font=("微软雅黑", 10), bg="white", fg="#666").pack(side="left")
        tk.Label(row, text=f"{len(self.moments)} 条", font=("微软雅黑", 10), bg="white", fg="#333").pack(side="right")

        tk.Button(win, text="关闭", command=win.destroy, width=10, bg="#e8f0fe", fg="#1a73e8",
                  bd=0, font=("微软雅黑", 10), cursor="hand2").pack(pady=10)

    def clear_placeholder(self, event):
        if self.text_input.get("1.0", "end-1c") == "分享新鲜事...":
            self.text_input.delete("1.0", "end")

    def add_files(self):
        files = filedialog.askopenfilenames(title="选择文件（支持所有格式）", filetypes=[("所有文件", "*.*")])
        for path in files:
            if path not in [p for _, p in self.selected_files]:
                self.selected_files.append((os.path.basename(path), path))
        self.refresh_file_show()

    def refresh_file_show(self):
        for w in self.file_show.winfo_children():
            w.destroy()
        for idx, (name, path) in enumerate(self.selected_files):
            item = tk.Frame(self.file_show, bg="#f5f5f5")
            item.pack(side="left", padx=2, pady=2)
            tk.Label(item, text=f"📄 {name}", bg="#f5f5f5", font=("微软雅黑", 9), fg="#555").pack(side="left", padx=5)
            tk.Button(item, text="×", command=lambda i=idx: self.del_file(i),
                      bg="#f5f5f5", fg="#999", bd=0, font=("微软雅黑", 9), cursor="hand2").pack(side="right")

    def del_file(self, idx):
        del self.selected_files[idx]
        self.refresh_file_show()

    def publish(self):
        text = self.text_input.get("1.0", "end-1c").strip()
        if text == "分享新鲜事...":
            text = ""
        if not text and not self.selected_files:
            messagebox.showwarning("提示", "请输入文字或添加文件")
            return

        self.moments.insert(0, {"text": text, "files": self.selected_files.copy(), "time": time.time()})
        self.text_input.delete("1.0", "end")
        self.text_input.insert("1.0", "分享新鲜事...")
        self.selected_files = []
        self.refresh_file_show()
        self.save_data()
        self.render_moments()

    def save_data(self):
        self.user_data["moments"] = self.moments
        self.users[self.username] = self.user_data
        save_users(self.users)

    def render_moments(self):
        for w in self.scroll_frame.winfo_children():
            w.destroy()

        for idx, m in enumerate(self.moments):
            card = tk.Frame(self.scroll_frame, bg="white", bd=1, relief="solid")
            card.pack(fill="x", pady=6)

            head = tk.Frame(card, bg="white")
            head.pack(fill="x", padx=12, pady=(10, 5))

            # 动态头像
            avt = tk.Canvas(head, width=36, height=36, bg="white", bd=0, highlightthickness=0)
            avt.pack(side="left")
            atype, aval = self.user_data["avatar_type"], self.user_data["avatar_value"]
            if atype == "color":
                avt.create_oval(1, 1, 35, 35, fill=aval, outline="")
            else:
                try:
                    img = tk.PhotoImage(file=aval)
                    scale = max(img.width()//36, 1)
                    img = img.subsample(scale, scale)
                    card.avt_cache = img
                    avt.create_image(18, 18, image=img)
                except:
                    avt.create_oval(1, 1, 35, 35, fill="#cccccc", outline="")

            tk.Label(head, text=self.username, bg="white", font=("微软雅黑", 11, "bold"), fg="#333").pack(side="left", padx=6)
            tk.Label(head, text=time.strftime("%Y-%m-%d %H:%M", time.localtime(m["time"])),
                     bg="white", font=("微软雅黑", 9), fg="#999").pack(side="right")

            if m["text"]:
                tk.Label(card, text=m["text"], bg="white", font=("微软雅黑", 10),
                         fg="#333", wraplength=600, justify="left").pack(anchor="w", padx=12, pady=3)

            if m["files"]:
                file_box = tk.Frame(card, bg="white")
                file_box.pack(anchor="w", padx=12, pady=5)
                for name, path in m["files"]:
                    tk.Button(file_box, text=f"📎 {name}", command=lambda p=path: self.open_file(p),
                              bg="#f0f7ff", fg="#1a73e8", bd=0, font=("微软雅黑", 9),
                              cursor="hand2", anchor="w", padx=8).pack(fill="x", pady=2)

            bottom = tk.Frame(card, bg="#fafafa")
            bottom.pack(fill="x", pady=(5, 0))
            tk.Button(bottom, text="删除", command=lambda i=idx: self.del_moment(i),
                      bg="#fafafa", fg="#999", bd=0, font=("微软雅黑", 9), cursor="hand2").pack(side="left", padx=12, pady=5)
            tk.Label(bottom, text="💬 评论   👍 点赞", bg="#fafafa",
                     font=("微软雅黑", 9), fg="#888").pack(side="right", padx=12, pady=5)

    def del_moment(self, idx):
        if messagebox.askyesno("确认", "确定删除这条动态吗？"):
            del self.moments[idx]
            self.save_data()
            self.render_moments()

    def open_file(self, path):
        if not os.path.exists(path):
            messagebox.showerror("错误", "文件已不存在或路径已变更")
            return
        try:
            if platform.system() == "Windows":
                os.startfile(path)
            elif platform.system() == "Darwin":
                subprocess.run(["open", path])
            else:
                subprocess.run(["xdg-open", path])
        except Exception as e:
            messagebox.showerror("打开失败", str(e))

    def on_mousewheel(self, event):
        self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")

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