import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from PIL import Image, ImageDraw, ImageFont, ImageTk
import os
import datetime


class StudentIDGenerator:
    def __init__(self, root):
        self.root = root
        self.root.title("学生证件生成器")
        self.root.geometry("800x600")
        self.root.resizable(True, True)

        # 存储上传的照片路径
        self.photo_path = None
        self.generated_id = None

        self.setup_ui()

    def setup_ui(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)

        # 输入区域
        input_frame = ttk.LabelFrame(main_frame, text="学生信息", padding="10")
        input_frame.grid(row=0, column=0, columnspan=2,
                         sticky=(tk.W, tk.E), pady=(0, 10))
        input_frame.columnconfigure(1, weight=1)

        # 姓名
        ttk.Label(input_frame, text="姓名:").grid(
            row=0, column=0, sticky=tk.W, padx=(0, 10))
        self.name_var = tk.StringVar()
        ttk.Entry(input_frame, textvariable=self.name_var, width=30).grid(
            row=0, column=1, sticky=(tk.W, tk.E))

        # 学号
        ttk.Label(input_frame, text="学号:").grid(
            row=1, column=0, sticky=tk.W, padx=(0, 10), pady=(5, 0))
        self.student_id_var = tk.StringVar()
        ttk.Entry(input_frame, textvariable=self.student_id_var, width=30).grid(
            row=1, column=1, sticky=(tk.W, tk.E), pady=(5, 0))

        # 专业
        ttk.Label(input_frame, text="专业:").grid(
            row=2, column=0, sticky=tk.W, padx=(0, 10), pady=(5, 0))
        self.major_var = tk.StringVar()
        ttk.Entry(input_frame, textvariable=self.major_var, width=30).grid(
            row=2, column=1, sticky=(tk.W, tk.E), pady=(5, 0))

        # 班级
        ttk.Label(input_frame, text="班级:").grid(
            row=3, column=0, sticky=tk.W, padx=(0, 10), pady=(5, 0))
        self.class_var = tk.StringVar()
        ttk.Entry(input_frame, textvariable=self.class_var, width=30).grid(
            row=3, column=1, sticky=(tk.W, tk.E), pady=(5, 0))

        # 入学年份
        ttk.Label(input_frame, text="入学年份:").grid(
            row=4, column=0, sticky=tk.W, padx=(0, 10), pady=(5, 0))
        self.year_var = tk.StringVar(value=str(datetime.datetime.now().year))
        year_frame = ttk.Frame(input_frame)
        year_frame.grid(row=4, column=1, sticky=(tk.W, tk.E), pady=(5, 0))
        ttk.Entry(year_frame, textvariable=self.year_var,
                  width=10).pack(side=tk.LEFT)
        ttk.Label(year_frame, text="年").pack(side=tk.LEFT, padx=(5, 0))

        # 上传照片按钮
        ttk.Button(input_frame, text="上传照片", command=self.upload_photo).grid(
            row=5, column=0, columnspan=2, pady=(10, 0))

        # 显示照片预览
        self.photo_label = ttk.Label(
            input_frame, text="未选择照片", foreground="gray")
        self.photo_label.grid(row=6, column=0, columnspan=2, pady=(5, 0))

        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=1, column=0, columnspan=2, pady=(0, 10))

        ttk.Button(button_frame, text="生成证件", command=self.generate_id_card).pack(
            side=tk.LEFT, padx=(0, 10))
        ttk.Button(button_frame, text="保存证件", command=self.save_id_card).pack(
            side=tk.LEFT, padx=(0, 10))
        ttk.Button(button_frame, text="清空",
                   command=self.clear_all).pack(side=tk.LEFT)

        # 预览区域
        preview_frame = ttk.LabelFrame(main_frame, text="证件预览", padding="10")
        preview_frame.grid(row=2, column=0, columnspan=2,
                           sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 10))
        preview_frame.columnconfigure(0, weight=1)
        preview_frame.rowconfigure(0, weight=1)

        self.preview_label = ttk.Label(preview_frame, text="点击'生成证件'查看预览")
        self.preview_label.pack(expand=True)

        # 配置主框架的权重
        main_frame.rowconfigure(2, weight=1)

    def upload_photo(self):
        file_path = filedialog.askopenfilename(
            title="选择学生照片",
            filetypes=[
                ("Image files", "*.jpg *.jpeg *.png *.bmp *.gif"),
                ("All files", "*.*")
            ]
        )

        if file_path:
            self.photo_path = file_path
            # 显示文件名
            filename = os.path.basename(file_path)
            self.photo_label.config(
                text=f"已选择: {filename}", foreground="black")

    def generate_id_card(self):
        # 验证输入
        if not self.name_var.get().strip():
            messagebox.showerror("错误", "请输入姓名")
            return

        if not self.student_id_var.get().strip():
            messagebox.showerror("错误", "请输入学号")
            return

        # 创建证件图片
        try:
            id_card = self.create_id_card()
            self.generated_id = id_card

            # 转换为tkinter可显示的格式
            photo_image = ImageTk.PhotoImage(id_card)
            self.preview_label.config(image=photo_image, text="")
            self.preview_label.image = photo_image  # 保持引用

        except Exception as e:
            messagebox.showerror("错误", f"生成证件时出错: {str(e)}")

    def create_id_card(self):
        # 创建证件底图 (标准尺寸 85.6mm x 54mm ≈ 1014 x 638 pixels at 300 DPI)
        card_width, card_height = 1014, 638
        card = Image.new('RGB', (card_width, card_height), 'white')
        draw = ImageDraw.Draw(card)

        # 添加边框
        border_width = 10
        draw.rectangle([border_width, border_width, card_width-border_width, card_height-border_width],
                       outline='black', width=3)

        # 添加学校名称（顶部）
        try:
            title_font = ImageFont.truetype("arial.ttf", 60)
        except:
            title_font = ImageFont.load_default()

        school_name = "XX大学"
        title_bbox = draw.textbbox((0, 0), school_name, font=title_font)
        title_width = title_bbox[2] - title_bbox[0]
        draw.text(((card_width - title_width) // 2, 30),
                  school_name, fill='black', font=title_font)

        # 添加"学生证"标题
        try:
            subtitle_font = ImageFont.truetype("arial.ttf", 40)
        except:
            subtitle_font = ImageFont.load_default()

        subtitle = "学生证"
        subtitle_bbox = draw.textbbox((0, 0), subtitle, font=subtitle_font)
        subtitle_width = subtitle_bbox[2] - subtitle_bbox[0]
        draw.text(((card_width - subtitle_width) // 2, 100),
                  subtitle, fill='black', font=subtitle_font)

        # 处理照片
        photo_x, photo_y = 50, 180
        photo_size = 300

        if self.photo_path:
            try:
                photo = Image.open(self.photo_path)
                # 调整照片大小并裁剪为正方形
                photo.thumbnail((photo_size, photo_size),
                                Image.Resampling.LANCZOS)
                # 创建正方形背景
                photo_square = Image.new(
                    'RGB', (photo_size, photo_size), 'white')
                # 居中粘贴照片
                photo_x_offset = (photo_size - photo.width) // 2
                photo_y_offset = (photo_size - photo.height) // 2
                photo_square.paste(photo, (photo_x_offset, photo_y_offset))

                # 在证件上粘贴照片
                card.paste(photo_square, (photo_x, photo_y))

                # 添加照片边框
                draw.rectangle([photo_x, photo_y, photo_x + photo_size, photo_y + photo_size],
                               outline='black', width=2)
            except Exception as e:
                print(f"加载照片失败: {e}")
                # 如果照片加载失败，显示占位符
                draw.rectangle([photo_x, photo_y, photo_x + photo_size, photo_y + photo_size],
                               outline='gray', width=2)
                draw.text((photo_x + 10, photo_y + photo_size //
                          2 - 10), "无照片", fill='gray')
        else:
            # 无照片时显示占位符
            draw.rectangle([photo_x, photo_y, photo_x + photo_size, photo_y + photo_size],
                           outline='gray', width=2)
            draw.text((photo_x + 10, photo_y + photo_size // 2 - 10),
                      "无照片", fill='gray')

        # 添加文字信息
        text_x = photo_x + photo_size + 50
        text_start_y = 200
        line_height = 50

        try:
            info_font = ImageFont.truetype("arial.ttf", 32)
            label_font = ImageFont.truetype("arial.ttf", 28)
        except:
            info_font = ImageFont.load_default()
            label_font = ImageFont.load_default()

        # 姓名
        draw.text((text_x, text_start_y), "姓名:", fill='black', font=label_font)
        draw.text((text_x + 100, text_start_y),
                  self.name_var.get(), fill='black', font=info_font)

        # 学号
        draw.text((text_x, text_start_y + line_height),
                  "学号:", fill='black', font=label_font)
        draw.text((text_x + 100, text_start_y + line_height),
                  self.student_id_var.get(), fill='black', font=info_font)

        # 专业
        draw.text((text_x, text_start_y + 2*line_height),
                  "专业:", fill='black', font=label_font)
        draw.text((text_x + 100, text_start_y + 2*line_height),
                  self.major_var.get(), fill='black', font=info_font)

        # 班级
        draw.text((text_x, text_start_y + 3*line_height),
                  "班级:", fill='black', font=label_font)
        draw.text((text_x + 100, text_start_y + 3*line_height),
                  self.class_var.get(), fill='black', font=info_font)

        # 有效期
        valid_from = self.year_var.get()
        valid_to = str(int(valid_from) + 4)
        validity = f"{valid_from}-{valid_to}"
        draw.text((text_x, text_start_y + 4*line_height),
                  "有效期:", fill='black', font=label_font)
        draw.text((text_x + 120, text_start_y + 4*line_height),
                  validity, fill='black', font=info_font)

        # 添加底部装饰线
        draw.line([(0, card_height - 60), (card_width,
                  card_height - 60)], fill='black', width=2)

        # 添加学校logo占位符（右下角）
        logo_text = "校徽"
        try:
            logo_font = ImageFont.truetype("arial.ttf", 24)
        except:
            logo_font = ImageFont.load_default()
        draw.text((card_width - 150, card_height - 50),
                  logo_text, fill='lightgray', font=logo_font)

        return card

    def save_id_card(self):
        if self.generated_id is None:
            messagebox.showwarning("警告", "请先生成证件")
            return

        file_path = filedialog.asksaveasfilename(
            title="保存学生证件",
            defaultextension=".png",
            filetypes=[
                ("PNG files", "*.png"),
                ("JPEG files", "*.jpg *.jpeg"),
                ("All files", "*.*")
            ],
            initialfile=f"{self.name_var.get()}_学生证.png"
        )

        if file_path:
            try:
                self.generated_id.save(file_path)
                messagebox.showinfo("成功", "证件保存成功！")
            except Exception as e:
                messagebox.showerror("错误", f"保存失败: {str(e)}")

    def clear_all(self):
        # 清空所有输入
        self.name_var.set("")
        self.student_id_var.set("")
        self.major_var.set("")
        self.class_var.set("")
        self.year_var.set(str(datetime.datetime.now().year))
        self.photo_path = None
        self.generated_id = None
        self.photo_label.config(text="未选择照片", foreground="gray")
        self.preview_label.config(image="", text="点击'生成证件'查看预览")


def main():
    root = tk.Tk()
    app = StudentIDGenerator(root)
    root.mainloop()


if __name__ == "__main__":
    main()
