import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from PIL import Image, ImageTk, ImageDraw, ImageFont
import os
from datetime import datetime

class StudentCardGenerator:
    def __init__(self, root):
        self.root = root
        self.root.title("学生证生成器")
        self.root.geometry("900x700")
        self.root.configure(bg="#f0f0f0")
        
        # 默认学生照片路径
        self.default_photo_path = None
        self.current_image = None
        
        # 创建界面
        self.create_widgets()
        
    def create_widgets(self):
        # 创建主框架
        main_frame = tk.Frame(self.root, bg="#f0f0f0")
        main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
        
        # 左侧输入面板
        input_frame = tk.Frame(main_frame, bg="#ffffff", relief=tk.RAISED, bd=2)
        input_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10))
        
        # 标题
        title_label = tk.Label(input_frame, text="学生证信息录入", font=("Microsoft YaHei", 16, "bold"), 
                              bg="#ffffff", fg="#1a73e8")
        title_label.pack(pady=(20, 10))
        
        # 创建输入字段
        self.create_input_fields(input_frame)
        
        # 右侧预览面板
        preview_frame = tk.Frame(main_frame, bg="#ffffff", relief=tk.RAISED, bd=2)
        preview_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
        
        # 预览标题
        preview_title = tk.Label(preview_frame, text="学生证预览", font=("Microsoft YaHei", 16, "bold"), 
                                bg="#ffffff", fg="#1a73e8")
        preview_title.pack(pady=(20, 10))
        
        # 预览画布
        self.preview_canvas = tk.Canvas(preview_frame, width=400, height=500, bg="#f8f9fa", 
                                       relief=tk.SUNKEN, bd=2)
        self.preview_canvas.pack(pady=10, padx=20)
        
        # 按钮框架
        button_frame = tk.Frame(preview_frame, bg="#ffffff")
        button_frame.pack(fill=tk.X, pady=20, padx=20)
        
        # 生成按钮
        generate_btn = tk.Button(button_frame, text="生成学生证", command=self.generate_card, 
                                font=("Microsoft YaHei", 12), bg="#1a73e8", fg="white",
                                padx=20, pady=8)
        generate_btn.pack(side=tk.LEFT, padx=5)
        
        # 保存按钮
        save_btn = tk.Button(button_frame, text="保存为图片", command=self.save_as_image, 
                            font=("Microsoft YaHei", 12), bg="#34a853", fg="white",
                            padx=20, pady=8)
        save_btn.pack(side=tk.LEFT, padx=5)
        
        # 默认示例信息
        self.load_example_data()
    
    def create_input_fields(self, parent):
        # 创建表格布局
        fields = [
            ("姓名:", "name"),
            ("学号:", "student_id"),
            ("学院:", "college"),
            ("专业:", "major"),
            ("年级:", "grade"),
            ("班级:", "class_name"),
            ("入学日期:", "admission_date"),
            ("有效期限:", "valid_date"),
            ("联系电话:", "phone"),
            ("电子邮箱:", "email")
        ]
        
        self.entries = {}
        
        for i, (label_text, field_name) in enumerate(fields):
            frame = tk.Frame(parent, bg="#ffffff")
            frame.pack(fill=tk.X, padx=20, pady=8)
            
            label = tk.Label(frame, text=label_text, font=("Microsoft YaHei", 11), 
                           bg="#ffffff", width=10, anchor="w")
            label.pack(side=tk.LEFT)
            
            if field_name in ["grade", "class_name"]:
                entry = ttk.Combobox(frame, font=("Microsoft YaHei", 11), width=20)
                if field_name == "grade":
                    entry['values'] = ["2026级", "2025级", "2024级", "2023级", "2022级"]
                else:
                    entry['values'] = ["1班", "2班", "3班", "4班", "5班"]
            else:
                entry = tk.Entry(frame, font=("Microsoft YaHei", 11), width=25, relief=tk.SUNKEN, bd=1)
            
            entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(10, 0))
            self.entries[field_name] = entry
        
        # 照片上传按钮
        photo_frame = tk.Frame(parent, bg="#ffffff")
        photo_frame.pack(fill=tk.X, padx=20, pady=15)
        
        photo_label = tk.Label(photo_frame, text="学生照片:", font=("Microsoft YaHei", 11), 
                              bg="#ffffff", width=10, anchor="w")
        photo_label.pack(side=tk.LEFT)
        
        self.photo_path_label = tk.Label(photo_frame, text="未选择照片", font=("Microsoft YaHei", 10), 
                                        bg="#ffffff", fg="#666", width=20, anchor="w")
        self.photo_path_label.pack(side=tk.LEFT, padx=(10, 0))
        
        upload_btn = tk.Button(photo_frame, text="上传照片", command=self.upload_photo, 
                              font=("Microsoft YaHei", 10), bg="#4285f4", fg="white")
        upload_btn.pack(side=tk.LEFT, padx=(10, 0))
    
    def upload_photo(self):
        file_path = filedialog.askopenfilename(
            title="选择学生照片",
            filetypes=[("图片文件", "*.png *.jpg *.jpeg *.bmp"), ("所有文件", "*.*")]
        )
        if file_path:
            self.default_photo_path = file_path
            filename = os.path.basename(file_path)
            self.photo_path_label.config(text=filename[:20] + ("..." if len(filename) > 20 else ""))
    
    def load_example_data(self):
        # 加载示例数据
        example_data = {
            "name": "张三",
            "student_id": "20262021001",
            "college": "计算机科学与技术学院",
            "major": "软件工程",
            "grade": "2026级",
            "class_name": "1班",
            "admission_date": "2026-09-01",
            "valid_date": "2030-06-30",
            "phone": "13800138000",
            "email": "20262021001@university.edu.cn"
        }
        
        for field_name, value in example_data.items():
            if field_name in self.entries:
                if isinstance(self.entries[field_name], ttk.Combobox):
                    self.entries[field_name].set(value)
                else:
                    self.entries[field_name].delete(0, tk.END)
                    self.entries[field_name].insert(0, value)
    
    def generate_card(self):
        # 收集输入数据
        data = {}
        for field_name, entry in self.entries.items():
            if isinstance(entry, ttk.Combobox):
                data[field_name] = entry.get()
            else:
                data[field_name] = entry.get()
        
        # 验证必要字段
        if not data["name"] or not data["student_id"]:
            messagebox.showerror("错误", "姓名和学号为必填项！")
            return
        
        # 在画布上绘制学生证
        self.draw_student_card(data)
    
    def draw_student_card(self, data):
        # 清空画布
        self.preview_canvas.delete("all")
        
        # 学生证尺寸
        card_width = 360
        card_height = 450
        
        # 居中画布位置
        canvas_width = self.preview_canvas.winfo_width()
        canvas_height = self.preview_canvas.winfo_height()
        x_offset = (canvas_width - card_width) // 2
        y_offset = (canvas_height - card_height) // 2
        
        # 绘制学生证背景
        self.preview_canvas.create_rectangle(
            x_offset, y_offset, 
            x_offset + card_width, y_offset + card_height,
            fill="#ffffff", outline="#1a73e8", width=2
        )
        
        # 绘制标题区域
        title_y = y_offset + 20
        self.preview_canvas.create_text(
            x_offset + card_width//2, title_y,
            text="学 生 证", 
            font=("Microsoft YaHei", 24, "bold"),
            fill="#1a73e8"
        )
        
        # 绘制校徽/学校名称区域
        school_y = title_y + 40
        self.preview_canvas.create_oval(
            x_offset + card_width//2 - 40, school_y - 40,
            x_offset + card_width//2 + 40, school_y + 40,
            outline="#1a73e8", width=2
        )
        self.preview_canvas.create_text(
            x_offset + card_width//2, school_y,
            text="✎",  # 校徽占位符
            font=("Arial", 36),
            fill="#1a73e8"
        )
        
        # 绘制照片区域
        photo_y = school_y + 80
        photo_size = 100
        photo_x = x_offset + 30
        
        # 照片框
        self.preview_canvas.create_rectangle(
            photo_x, photo_y,
            photo_x + photo_size, photo_y + photo_size,
            fill="#f0f0f0", outline="#ccc", width=1
        )
        
        # 尝试加载并显示照片
        if self.default_photo_path and os.path.exists(self.default_photo_path):
            try:
                img = Image.open(self.default_photo_path)
                img = img.resize((photo_size, photo_size))
                photo_img = ImageTk.PhotoImage(img)
                self.current_image = photo_img  # 保持引用
                self.preview_canvas.create_image(
                    photo_x + photo_size//2, photo_y + photo_size//2,
                    image=photo_img
                )
            except:
                # 如果加载失败，显示占位符
                self.preview_canvas.create_text(
                    photo_x + photo_size//2, photo_y + photo_size//2,
                    text="照片", font=("Microsoft YaHei", 12), fill="#666"
                )
        else:
            self.preview_canvas.create_text(
                photo_x + photo_size//2, photo_y + photo_size//2,
                text="照片", font=("Microsoft YaHei", 12), fill="#666"
            )
        
        # 绘制学生信息
        info_start_x = photo_x + photo_size + 20
        info_y = photo_y
        
        info_lines = [
            f"姓名：{data['name']}",
            f"学号：{data['student_id']}",
            f"学院：{data['college']}",
            f"专业：{data['major']}",
            f"年级：{data['grade']}  班级：{data['class_name']}"
        ]
        
        for i, line in enumerate(info_lines):
            self.preview_canvas.create_text(
                    info_start_x, info_y + i * 25,
                    text=line, 
                    font=("Microsoft YaHei", 11),
                    fill="#333",
                    anchor="w"
                )
        
        # 绘制其他信息
        detail_y = photo_y + photo_size + 30
        detail_lines = [
            f"入学日期：{data['admission_date']}",
            f"有效期限：{data['valid_date']}",
            f"联系电话：{data['phone']}",
            f"电子邮箱：{data['email']}"
        ]
        
        for i, line in enumerate(detail_lines):
            self.preview_canvas.create_text(
                x_offset + 20, detail_y + i * 25,
                text=line, 
                font=("Microsoft YaHei", 10),
                fill="#555",
                anchor="w"
            )
        
        # 绘制底部信息
        bottom_y = y_offset + card_height - 30
        self.preview_canvas.create_text(
            x_offset + card_width//2, bottom_y,
            text="请妥善保管此证件", 
            font=("Microsoft YaHei", 10, "italic"),
            fill="#999"
        )
        
        # 绘制发证日期
        current_date = datetime.now().strftime("%Y-%m-%d")
        self.preview_canvas.create_text(
            x_offset + card_width - 20, bottom_y,
            text=f"发证日期：{current_date}", 
            font=("Microsoft YaHei", 9),
            fill="#666",
            anchor="e"
        )
        
        # 保存数据供保存图片时使用
        self.current_card_data = data
    
    def save_as_image(self):
        if not hasattr(self, 'current_card_data'):
            messagebox.showwarning("提示", "请先生成学生证预览！")
            return
        
        # 选择保存路径
        file_path = filedialog.asksaveasfilename(
            title="保存学生证",
            defaultextension=".png",
            filetypes=[("PNG图片", "*.png"), ("JPEG图片", "*.jpg"), ("所有文件", "*.*")]
        )
        
        if not file_path:
            return
        
        try:
            # 使用PIL创建更高分辨率的图片
            img_width = 800
            img_height = 1000
            img = Image.new('RGB', (img_width, img_height), color='white')
            draw = ImageDraw.Draw(img)
            
            # 设置字体（使用默认字体）
            try:
                title_font = ImageFont.truetype("msyh.ttc", 48)
                header_font = ImageFont.truetype("msyh.ttc", 24)
                info_font = ImageFont.truetype("msyh.ttc", 22)
                detail_font = ImageFont.truetype("msyh.ttc", 20)
            except:
                # 如果找不到字体，使用默认字体
                title_font = ImageFont.load_default()
                header_font = ImageFont.load_default()
                info_font = ImageFont.load_default()
                detail_font = ImageFont.load_default()
            
            # 绘制标题
            draw.text((img_width//2, 60), "学 生 证", font=title_font, fill="#1a73e8", anchor="mm")
            
            # 绘制校徽
            draw.ellipse([(img_width//2-60, 140), (img_width//2+60, 260)], outline="#1a73e8", width=3)
            draw.text((img_width//2, 200), "✎", font=title_font, fill="#1a73e8", anchor="mm")
            
            # 照片区域
            photo_x, photo_y = 60, 320
            photo_size = 200
            draw.rectangle([(photo_x, photo_y), (photo_x+photo_size, photo_y+photo_size)], 
                          fill="#f0f0f0", outline="#ccc", width=2)
            
            # 如果存在照片，加载并添加到学生证
            if self.default_photo_path and os.path.exists(self.default_photo_path):
                try:
                    student_img = Image.open(self.default_photo_path)
                    student_img = student_img.resize((photo_size-20, photo_size-20))
                    img.paste(student_img, (photo_x+10, photo_y+10))
                except:
                    draw.text((photo_x+photo_size//2, photo_y+photo_size//2), "照片", 
                             font=header_font, fill="#666", anchor="mm")
            else:
                draw.text((photo_x+photo_size//2, photo_y+photo_size//2), "照片", 
                         font=header_font, fill="#666", anchor="mm")
            
            # 学生信息
            info_x = photo_x + photo_size + 40
            info_y = photo_y + 20
            
            info_lines = [
                f"姓名：{self.current_card_data['name']}",
                f"学号：{self.current_card_data['student_id']}",
                f"学院：{self.current_card_data['college']}",
                f"专业：{self.current_card_data['major']}",
                f"年级：{self.current_card_data['grade']}  班级：{self.current_card_data['class_name']}"
            ]
            
            for i, line in enumerate(info_lines):
                draw.text((info_x, info_y + i*50), line, font=info_font, fill="#333")
            
            # 其他信息
            detail_y = photo_y + photo_size + 50
            
            detail_lines = [
                f"入学日期：{self.current_card_data['admission_date']}",
                f"有效期限：{self.current_card_data['valid_date']}",
                f"联系电话：{self.current_card_data['phone']}",
                f"电子邮箱：{self.current_card_data['email']}"
            ]
            
            for i, line in enumerate(detail_lines):
                draw.text((photo_x, detail_y + i*50), line, font=detail_font, fill="#555")
            
            # 底部信息
            current_date = datetime.now().strftime("%Y-%m-%d")
            draw.text((img_width//2, img_height-80), "请妥善保管此证件", 
                     font=detail_font, fill="#999", anchor="mm")
            draw.text((img_width-40, img_height-40), f"发证日期：{current_date}", 
                     font=detail_font, fill="#666", anchor="rm")
            
            # 保存图片
            img.save(file_path)
            messagebox.showinfo("成功", f"学生证已保存到：\n{file_path}")
            
        except Exception as e:
            messagebox.showerror("错误", f"保存失败：{str(e)}")

# 运行程序
if __name__ == "__main__":
    # 检查所需库
    try:
        root = tk.Tk()
        app = StudentCardGenerator(root)
        root.mainloop()
    except ImportError as e:
        print(f"缺少必要的库，请安装：{e}")
        print("使用以下命令安装所需库：")
        print("pip install pillow")