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

class StudentCardGenerator:
    def __init__(self, root):
        self.root = root
        self.root.title("学生证生成器 v1.0")
        self.root.geometry("1200x700")
        self.root.configure(bg='#f0f8ff')
        
        # 设置图标
        try:
            self.root.iconbitmap('icon.ico')
        except:
            pass
        
        # 学生信息变量
        self.info = {
            'name': tk.StringVar(value="张三"),
            'student_id': tk.StringVar(value="20230001"),
            'college': tk.StringVar(value="计算机学院"),
            'major': tk.StringVar(value="计算机科学与技术"),
            'class': tk.StringVar(value="2023级1班"),
            'phone': tk.StringVar(value="13800000000"),
            'email': tk.StringVar(value="student@school.edu.cn"),
            'enrollment_date': tk.StringVar(value="2023-09-01"),
            'school_name': tk.StringVar(value="某某大学"),
            'valid_until': tk.StringVar(value="2029-06-30")
        }
        
        # 样式变量
        self.style_vars = {
            'bg_color': tk.StringVar(value="#f8fdff"),
            'title_color': tk.StringVar(value="#01579b"),
            'border_color': tk.StringVar(value="#0277bd"),
            'text_color': tk.StringVar(value="#263238")
        }
        
        # 加载配置
        self.load_config()
        
        # 初始化界面
        self.setup_ui()
        
        # 初始化预览
        self.update_preview()
        
    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)
        main_frame.rowconfigure(0, weight=1)
        
        # 左侧：控制面板
        control_panel = ttk.LabelFrame(main_frame, text="学生信息输入", padding="15")
        control_panel.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.W), padx=(0, 10))
        
        # 右侧：预览区域
        preview_panel = ttk.LabelFrame(main_frame, text="学生证预览", padding="15")
        preview_panel.grid(row=0, column=1, sticky=(tk.N, tk.S, tk.E, tk.W))
        preview_panel.columnconfigure(0, weight=1)
        preview_panel.rowconfigure(1, weight=1)
        
        # 创建控制面板内容
        self.create_control_panel(control_panel)
        
        # 创建预览面板
        self.create_preview_panel(preview_panel)
        
    def create_control_panel(self, parent):
        """创建控制面板"""
        # 创建滚动区域
        canvas = tk.Canvas(parent, height=500)
        scrollbar = ttk.Scrollbar(parent, orient="vertical", command=canvas.yview)
        scrollable_frame = ttk.Frame(canvas)
        
        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        
        # 基本信息部分
        info_frame = ttk.LabelFrame(scrollable_frame, text="基本信息", padding="10")
        info_frame.grid(row=0, column=0, sticky=(tk.W, tk.E), pady=(0, 10))
        
        fields = [
            ("姓名", "name", "请输入姓名"),
            ("学号", "student_id", "请输入学号"),
            ("学院", "college", "请输入学院名称"),
            ("专业", "major", "请输入专业名称"),
            ("班级", "class", "请输入班级"),
            ("电话", "phone", "请输入联系电话"),
            ("邮箱", "email", "请输入电子邮箱"),
            ("入学日期", "enrollment_date", "YYYY-MM-DD"),
            ("学校名称", "school_name", "请输入学校名称"),
            ("有效期至", "valid_until", "YYYY-MM-DD")
        ]
        
        for i, (label_text, var_name, placeholder) in enumerate(fields):
            frame = ttk.Frame(info_frame)
            frame.grid(row=i, column=0, sticky=(tk.W, tk.E), pady=5)
            
            label = ttk.Label(frame, text=label_text, width=10, anchor=tk.W)
            label.pack(side=tk.LEFT, padx=(0, 10))
            
            entry = ttk.Entry(frame, textvariable=self.info[var_name], width=25)
            entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
            entry.bind('<KeyRelease>', lambda e: self.update_preview())
            
        # 样式设置部分
        style_frame = ttk.LabelFrame(scrollable_frame, text="样式设置", padding="10")
        style_frame.grid(row=1, column=0, sticky=(tk.W, tk.E), pady=(10, 10))
        
        style_fields = [
            ("背景颜色", "bg_color"),
            ("标题颜色", "title_color"),
            ("边框颜色", "border_color"),
            ("文字颜色", "text_color")
        ]
        
        for i, (label_text, var_name) in enumerate(style_fields):
            frame = ttk.Frame(style_frame)
            frame.grid(row=i, column=0, sticky=(tk.W, tk.E), pady=5)
            
            label = ttk.Label(frame, text=label_text, width=10, anchor=tk.W)
            label.pack(side=tk.LEFT, padx=(0, 10))
            
            color_frame = ttk.Frame(frame)
            color_frame.pack(side=tk.LEFT, fill=tk.X, expand=True)
            
            entry = ttk.Entry(color_frame, textvariable=self.style_vars[var_name], width=20)
            entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
            
            color_btn = ttk.Button(color_frame, text="选择", width=6,
                                  command=lambda v=var_name: self.choose_color(v))
            color_btn.pack(side=tk.LEFT, padx=(5, 0))
            
            entry.bind('<KeyRelease>', lambda e: self.update_preview())
        
        # 照片上传
        photo_frame = ttk.LabelFrame(scrollable_frame, text="照片设置", padding="10")
        photo_frame.grid(row=2, column=0, sticky=(tk.W, tk.E), pady=(10, 10))
        
        self.photo_path = tk.StringVar(value="")
        
        photo_btn_frame = ttk.Frame(photo_frame)
        photo_btn_frame.grid(row=0, column=0, sticky=(tk.W, tk.E), pady=5)
        
        upload_btn = ttk.Button(photo_btn_frame, text="上传照片", 
                                command=self.upload_photo, width=15)
        upload_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        clear_btn = ttk.Button(photo_btn_frame, text="清除照片", 
                               command=self.clear_photo, width=15)
        clear_btn.pack(side=tk.LEFT)
        
        photo_info = ttk.Label(photo_frame, textvariable=self.photo_path, 
                              wraplength=300, foreground="gray")
        photo_info.grid(row=1, column=0, sticky=(tk.W, tk.E), pady=(5, 0))
        
        # 按钮区域
        button_frame = ttk.Frame(scrollable_frame)
        button_frame.grid(row=3, column=0, sticky=(tk.W, tk.E), pady=(20, 0))
        
        buttons = [
            ("生成图片", self.generate_image, "#4CAF50"),
            ("保存配置", self.save_config, "#2196F3"),
            ("重置", self.reset_fields, "#FF9800"),
            ("退出", self.root.quit, "#F44336")
        ]
        
        for i, (text, command, color) in enumerate(buttons):
            btn = tk.Button(button_frame, text=text, command=command,
                           bg=color, fg="white", font=("微软雅黑", 10, "bold"),
                           width=12, height=2, relief=tk.RAISED,
                           cursor="hand2")
            btn.grid(row=0, column=i, padx=5)
            btn.bind("<Enter>", lambda e, b=btn: b.config(bg=self.lighten_color(b.cget('bg'))))
            btn.bind("<Leave>", lambda e, b=btn, c=color: b.config(bg=c))
    
    def create_preview_panel(self, parent):
        """创建预览面板"""
        # 预览标签
        preview_label = tk.Label(parent, text="实时预览", 
                                font=("微软雅黑", 12, "bold"),
                                bg='#f0f8ff')
        preview_label.grid(row=0, column=0, sticky=tk.W, pady=(0, 10))
        
        # 预览画布
        self.preview_canvas = tk.Canvas(parent, width=700, height=500, 
                                       bg="white", bd=2, relief=tk.SUNKEN)
        self.preview_canvas.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 预览控制按钮
        control_frame = ttk.Frame(parent)
        control_frame.grid(row=2, column=0, sticky=tk.E, pady=(10, 0))
        
        zoom_in_btn = ttk.Button(control_frame, text="放大", 
                                command=self.zoom_in, width=10)
        zoom_in_btn.pack(side=tk.LEFT, padx=(0, 5))
        
        zoom_out_btn = ttk.Button(control_frame, text="缩小", 
                                 command=self.zoom_out, width=10)
        zoom_out_btn.pack(side=tk.LEFT, padx=(0, 5))
        
        save_preview_btn = ttk.Button(control_frame, text="保存预览", 
                                     command=self.save_preview, width=10)
        save_preview_btn.pack(side=tk.LEFT)
        
        # 缩放级别
        self.zoom_level = 1.0
    
    def choose_color(self, var_name):
        """选择颜色"""
        from tkinter import colorchooser
        color = colorchooser.askcolor(title=f"选择{var_name}颜色")
        if color[1]:
            self.style_vars[var_name].set(color[1])
            self.update_preview()
    
    def upload_photo(self):
        """上传照片"""
        filetypes = [
            ("图片文件", "*.png *.jpg *.jpeg *.bmp *.gif"),
            ("所有文件", "*.*")
        ]
        filename = filedialog.askopenfilename(
            title="选择照片",
            filetypes=filetypes
        )
        if filename:
            self.photo_path.set(os.path.basename(filename))
            self.update_preview()
    
    def clear_photo(self):
        """清除照片"""
        self.photo_path.set("")
        self.update_preview()
    
    def update_preview(self):
        """更新预览"""
        try:
            # 创建预览图片
            preview_img = self.create_card_image(preview_mode=True)
            
            # 应用缩放
            width = int(700 * self.zoom_level)
            height = int(500 * self.zoom_level)
            preview_img = preview_img.resize((width, height), Image.Resampling.LANCZOS)
            
            # 转换为PhotoImage
            self.preview_photo = ImageTk.PhotoImage(preview_img)
            
            # 清空画布并显示新图片
            self.preview_canvas.delete("all")
            self.preview_canvas.create_image(350, 250, image=self.preview_photo)
            
        except Exception as e:
            print(f"预览更新失败: {e}")
    
    def create_card_image(self, preview_mode=False):
        """创建学生证图片"""
        # 图片尺寸
        width, height = 900, 600
        
        # 创建画布
        img = Image.new('RGB', (width, height), self.style_vars['bg_color'].get())
        draw = ImageDraw.Draw(img)
        
        # 尝试加载字体
        try:
            font_paths = [
                'C:/Windows/Fonts/msyh.ttc',  # Windows
                'C:/Windows/Fonts/simhei.ttf',  # Windows
                '/System/Library/Fonts/PingFang.ttc',  # Mac
                '/usr/share/fonts/truetype/wqy/wqy-microhei.ttc'  # Linux
            ]
            
            title_font = None
            for path in font_paths:
                if os.path.exists(path):
                    title_font = ImageFont.truetype(path, 60)
                    info_font = ImageFont.truetype(path, 28)
                    small_font = ImageFont.truetype(path, 22)
                    break
            
            if title_font is None:
                title_font = ImageFont.load_default()
                info_font = ImageFont.load_default()
                small_font = ImageFont.load_default()
        except:
            title_font = ImageFont.load_default()
            info_font = ImageFont.load_default()
            small_font = ImageFont.load_default()
        
        # 获取颜色
        border_color = self.style_vars['border_color'].get()
        title_color = self.style_vars['title_color'].get()
        text_color = self.style_vars['text_color'].get()
        
        # 绘制边框
        draw.rounded_rectangle([20, 20, width-20, height-20], 
                              radius=25, outline=border_color, width=4)
        
        # 绘制标题
        title = "学 生 证"
        if hasattr(draw, 'textbbox'):
            bbox = draw.textbbox((0, 0), title, font=title_font)
            title_width = bbox[2] - bbox[0]
        else:
            title_width = 180
        draw.text(((width - title_width)//2, 40), title, 
                  font=title_font, fill=title_color)
        
        # 学校名称
        school = self.info['school_name'].get()
        if hasattr(draw, 'textbbox'):
            bbox = draw.textbbox((0, 0), school, font=info_font)
            school_width = bbox[2] - bbox[0]
        else:
            school_width = 120
        draw.text(((width - school_width)//2, 110), school, 
                  font=info_font, fill=border_color)
        
        # 绘制照片区域
        photo_box = [width-220, 180, width-50, 410]
        draw.rounded_rectangle(photo_box, radius=15, 
                              outline=border_color, width=3, fill='#f5f5f5')
        
        # 如果上传了照片
        if self.photo_path.get() and not preview_mode:
            try:
                photo = Image.open(self.photo_path.get())
                photo = photo.resize((photo_box[2]-photo_box[0], photo_box[3]-photo_box[1]))
                img.paste(photo, (photo_box[0], photo_box[1]))
            except:
                pass
        
        # 照片文字
        photo_text = "2寸照片"
        if hasattr(draw, 'textbbox'):
            bbox = draw.textbbox((0, 0), photo_text, font=small_font)
            photo_text_width = bbox[2] - bbox[0]
        else:
            photo_text_width = 60
        draw.text(((photo_box[0] + photo_box[2] - photo_text_width)//2, 430), 
                  photo_text, font=small_font, fill='#757575')
        
        # 绘制学生信息
        info_start_y = 180
        line_height = 60
        
        info_items = [
            ("姓名", self.info['name'].get()),
            ("学号", self.info['student_id'].get()),
            ("学院", self.info['college'].get()),
            ("专业", self.info['major'].get()),
            ("班级", self.info['class'].get()),
            ("电话", self.info['phone'].get()),
            ("邮箱", self.info['email'].get()),
            ("入学日期", self.info['enrollment_date'].get())
        ]
        
        for i, (label, value) in enumerate(info_items):
            y = info_start_y + i * line_height
            if y + line_height > photo_box[1]:
                y += 30
            
            # 标签
            draw.text((60, y), f"{label}:", font=info_font, fill=text_color)
            # 值
            draw.text((200, y), str(value), font=info_font, fill='#212121')
        
        # 绘制学号条形码区域
        barcode_y = 480
        draw.rectangle([60, barcode_y, 400, barcode_y+50], 
                      outline='#b0bec5', fill='#fafafa')
        
        # 条形码文字
        barcode_text = f"ID: {self.info['student_id'].get()}"
        draw.text((70, barcode_y+15), barcode_text, 
                  font=info_font, fill='#455a64')
        
        # 绘制底部信息
        bottom_text = f"有效期至: {self.info['valid_until'].get()} | 发证日期: {datetime.now().strftime('%Y-%m-%d')}"
        bottom_y = height - 60
        draw.text((width//2 - 200, bottom_y), bottom_text, 
                  font=small_font, fill='#78909c')
        
        # 水印
        watermark = f"{self.info['school_name'].get()} - 学生证生成器"
        if hasattr(draw, 'textbbox'):
            bbox = draw.textbbox((0, 0), watermark, font=small_font)
            watermark_width = bbox[2] - bbox[0]
        else:
            watermark_width = 150
        draw.text((width - watermark_width - 40, height - 40), watermark, 
                  font=small_font, fill='#e0e0e0')
        
        return img
    
    def zoom_in(self):
        """放大预览"""
        if self.zoom_level < 2.0:
            self.zoom_level *= 1.2
            self.update_preview()
    
    def zoom_out(self):
        """缩小预览"""
        if self.zoom_level > 0.5:
            self.zoom_level /= 1.2
            self.update_preview()
    
    def generate_image(self):
        """生成并保存图片"""
        try:
            # 验证必填字段
            required_fields = ['name', 'student_id', 'college', 'major', 'class']
            for field in required_fields:
                if not self.info[field].get().strip():
                    messagebox.showerror("错误", f"请填写{field}字段！")
                    return
            
            # 创建图片
            img = self.create_card_image()
            
            # 选择保存路径
            default_name = f"学生证_{self.info['name'].get()}_{datetime.now().strftime('%Y%m%d%H%M%S')}.png"
            file_path = filedialog.asksaveasfilename(
                title="保存学生证",
                defaultextension=".png",
                filetypes=[("PNG图片", "*.png"), ("所有文件", "*.*")],
                initialfile=default_name
            )
            
            if file_path:
                img.save(file_path, 'PNG', quality=95)
                messagebox.showinfo("成功", f"学生证已保存到:\n{file_path}")
                
        except Exception as e:
            messagebox.showerror("错误", f"生成图片失败:\n{str(e)}")
    
    def save_preview(self):
        """保存预览图片"""
        try:
            img = self.create_card_image(preview_mode=False)
            
            default_name = f"学生证预览_{datetime.now().strftime('%Y%m%d%H%M%S')}.png"
            file_path = filedialog.asksaveasfilename(
                title="保存预览",
                defaultextension=".png",
                filetypes=[("PNG图片", "*.png"), ("所有文件", "*.*")],
                initialfile=default_name
            )
            
            if file_path:
                img.save(file_path, 'PNG', quality=95)
                messagebox.showinfo("成功", f"预览已保存到:\n{file_path}")
                
        except Exception as e:
            messagebox.showerror("错误", f"保存预览失败:\n{str(e)}")
    
    def save_config(self):
        """保存配置"""
        try:
            config = {
                'info': {k: v.get() for k, v in self.info.items()},
                'style': {k: v.get() for k, v in self.style_vars.items()},
                'photo_path': self.photo_path.get()
            }
            
            file_path = filedialog.asksaveasfilename(
                title="保存配置",
                defaultextension=".json",
                filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")],
                initialfile="student_card_config.json"
            )
            
            if file_path:
                with open(file_path, 'w', encoding='utf-8') as f:
                    json.dump(config, f, ensure_ascii=False, indent=2)
                messagebox.showinfo("成功", "配置已保存")
                
        except Exception as e:
            messagebox.showerror("错误", f"保存配置失败:\n{str(e)}")
    
    def load_config(self):
        """加载配置"""
        try:
            config_path = "student_card_config.json"
            if os.path.exists(config_path):
                with open(config_path, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                
                for k, v in config.get('info', {}).items():
                    if k in self.info:
                        self.info[k].set(v)
                
                for k, v in config.get('style', {}).items():
                    if k in self.style_vars:
                        self.style_vars[k].set(v)
                
                if 'photo_path' in config:
                    self.photo_path.set(config['photo_path'])
                    
        except:
            pass  # 如果加载失败，使用默认值
    
    def reset_fields(self):
        """重置所有字段"""
        if messagebox.askyesno("确认", "确定要重置所有字段吗？"):
            default_values = {
                'name': "张三",
                'student_id': "20230001",
                'college': "计算机学院",
                'major': "计算机科学与技术",
                'class': "2023级1班",
                'phone': "13800000000",
                'email': "student@school.edu.cn",
                'enrollment_date': "2023-09-01",
                'school_name': "某某大学",
                'valid_until': "2029-06-30"
            }
            
            for k, v in default_values.items():
                self.info[k].set(v)
            
            default_styles = {
                'bg_color': "#f8fdff",
                'title_color': "#01579b",
                'border_color': "#0277bd",
                'text_color': "#263238"
            }
            
            for k, v in default_styles.items():
                self.style_vars[k].set(v)
            
            self.photo_path.set("")
            self.zoom_level = 1.0
            self.update_preview()
    
    def lighten_color(self, color, amount=30):
        """使颜色变亮"""
        if color.startswith('#'):
            r = int(color[1:3], 16)
            g = int(color[3:5], 16)
            b = int(color[5:7], 16)
            r = min(255, r + amount)
            g = min(255, g + amount)
            b = min(255, b + amount)
            return f'#{r:02x}{g:02x}{b:02x}'
        return color

def main():
    root = tk.Tk()
    
    # 设置窗口样式
    try:
        root.tk.call('lappend', 'auto_path', '{PATH_TO_TTK_THEME}')
        root.tk.call('package', 'require', 'ttk::theme::azure')
        ttk.Style().theme_use('azure')
    except:
        pass
    
    app = StudentCardGenerator(root)
    
    # 设置关闭事件
    def on_closing():
        if messagebox.askokcancel("退出", "确定要退出吗？"):
            root.quit()
    
    root.protocol("WM_DELETE_WINDOW", on_closing)
    
    root.mainloop()

if __name__ == "__main__":
    main()