import tkinter as tk
from tkinter import ttk, filedialog, messagebox, colorchooser, font
from PIL import Image, ImageTk, ImageDraw, ImageFont, ImageFilter, ImageOps
import qrcode
import datetime
import os
import random
import json
from io import BytesIO

class StudentIDGenerator:
    def __init__(self, root):
        self.root = root
        self.root.title("酷炫学生证件生成器")
        self.root.geometry("1200x700")
        self.root.configure(bg='#2c3e50')
        
        # 设置窗口图标
        try:
            self.root.iconbitmap(default=self.get_default_icon())
        except:
            pass
        
        # 存储变量
        self.student_photo_path = None
        self.template_image = None
        self.current_preview = None
        self.student_data = {}
        self.themes = {}
        self.load_themes()
        
        # 设置样式
        self.setup_styles()
        
        # 创建界面
        self.create_widgets()
        
    def get_default_icon(self):
        """创建默认图标"""
        from PIL import Image, ImageDraw
        img = Image.new('RGB', (32, 32), color='#3498db')
        draw = ImageDraw.Draw(img)
        draw.ellipse([4, 4, 28, 28], fill='#2ecc71')
        draw.ellipse([12, 12, 20, 20], fill='white')
        img.save('temp_icon.ico')
        return 'temp_icon.ico'
    
    def load_themes(self):
        """加载主题配置"""
        self.themes = {
            '现代简约': {
                'bg_color': '#ffffff',
                'text_color': '#2c3e50',
                'accent_color': '#3498db',
                'secondary_color': '#ecf0f1',
                'border_color': '#bdc3c7'
            },
            '科技蓝': {
                'bg_color': '#0a192f',
                'text_color': '#64ffda',
                'accent_color': '#00b4d8',
                'secondary_color': '#112240',
                'border_color': '#233554'
            },
            '学院风': {
                'bg_color': '#f8f1e5',
                'text_color': '#2c1810',
                'accent_color': '#8b4513',
                'secondary_color': '#e6d5b8',
                'border_color': '#a0522d'
            },
            '青春活力': {
                'bg_color': '#f0f8ff',
                'text_color': '#333333',
                'accent_color': '#ff6b6b',
                'secondary_color': '#4ecdc4',
                'border_color': '#45b7d1'
            },
            '暗黑系': {
                'bg_color': '#1a1a1a',
                'text_color': '#ffffff',
                'accent_color': '#bb86fc',
                'secondary_color': '#333333',
                'border_color': '#444444'
            }
        }
    
    def setup_styles(self):
        """设置ttk样式"""
        style = ttk.Style()
        style.theme_use('clam')
        
        # 自定义样式
        style.configure('Title.TLabel', 
                       font=('Arial', 18, 'bold'),
                       background='#2c3e50',
                       foreground='white')
        
        style.configure('Card.TFrame',
                       background='#34495e',
                       relief='raised',
                       borderwidth=2)
        
        style.configure('Input.TLabel',
                       font=('Arial', 10, 'bold'),
                       background='#34495e',
                       foreground='#ecf0f1')
        
        style.configure('Action.TButton',
                       font=('Arial', 10, 'bold'),
                       padding=10)
        
        style.map('Action.TButton',
                 foreground=[('pressed', 'white'), ('active', 'white')],
                 background=[('pressed', '#2980b9'), ('active', '#3498db')])
    
    def create_widgets(self):
        """创建界面组件"""
        # 主容器
        main_container = ttk.Frame(self.root)
        main_container.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 标题
        title_frame = ttk.Frame(main_container, style='Card.TFrame')
        title_frame.pack(fill='x', pady=(0, 20))
        
        title_label = ttk.Label(title_frame, 
                               text="🎓 酷炫学生证件生成器",
                               style='Title.TLabel')
        title_label.pack(pady=20)
        
        # 主内容区
        content_frame = ttk.Frame(main_container)
        content_frame.pack(fill='both', expand=True)
        
        # 左侧输入面板
        left_panel = ttk.Frame(content_frame, style='Card.TFrame')
        left_panel.pack(side='left', fill='both', expand=True, padx=(0, 10))
        
        # 右侧预览面板
        right_panel = ttk.Frame(content_frame, style='Card.TFrame')
        right_panel.pack(side='right', fill='both', expand=True)
        
        # 创建输入表单
        self.create_input_form(left_panel)
        
        # 创建预览区域
        self.create_preview_area(right_panel)
        
        # 创建控制面板
        self.create_control_panel(main_container)
    
    def create_input_form(self, parent):
        """创建输入表单"""
        form_frame = ttk.Frame(parent)
        form_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 滚动区域
        canvas = tk.Canvas(form_frame, bg='#34495e', highlightthickness=0)
        scrollbar = ttk.Scrollbar(form_frame, 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")
        
        # 表单内容
        fields = [
            ("姓名:", "name", "text"),
            ("学号:", "student_id", "text"),
            ("学院:", "college", "text"),
            ("专业:", "major", "text"),
            ("班级:", "class_name", "text"),
            ("年级:", "grade", "text"),
            ("入学日期:", "enrollment_date", "date"),
            ("有效期至:", "expiry_date", "date"),
            ("出生日期:", "birth_date", "date"),
            ("性别:", "gender", "combo", ["男", "女", "其他"]),
            ("手机号:", "phone", "text"),
            ("邮箱:", "email", "text"),
            ("身份证号:", "id_card", "text")
        ]
        
        self.input_vars = {}
        
        for i, (label_text, field_name, field_type, *options) in enumerate(fields):
            frame = ttk.Frame(scrollable_frame)
            frame.pack(fill='x', pady=5)
            
            label = ttk.Label(frame, text=label_text, style='Input.TLabel', width=10)
            label.pack(side='left', padx=(0, 10))
            
            if field_type == "text":
                var = tk.StringVar()
                entry = ttk.Entry(frame, textvariable=var, font=('Arial', 10))
                entry.pack(side='left', fill='x', expand=True, ipady=5)
                self.input_vars[field_name] = var
                
            elif field_type == "date":
                var = tk.StringVar()
                entry = ttk.Entry(frame, textvariable=var, font=('Arial', 10))
                entry.insert(0, datetime.datetime.now().strftime("%Y-%m-%d"))
                entry.pack(side='left', fill='x', expand=True, ipady=5)
                self.input_vars[field_name] = var
                
            elif field_type == "combo":
                var = tk.StringVar()
                combo = ttk.Combobox(frame, textvariable=var, values=options[0], 
                                   state='readonly', font=('Arial', 10))
                combo.pack(side='left', fill='x', expand=True, ipady=5)
                combo.set(options[0][0] if options[0] else "")
                self.input_vars[field_name] = var
        
        # 照片上传区域
        photo_frame = ttk.Frame(scrollable_frame)
        photo_frame.pack(fill='x', pady=(20, 10))
        
        photo_label = ttk.Label(photo_frame, text="学生照片:", style='Input.TLabel', width=10)
        photo_label.pack(side='left', padx=(0, 10))
        
        self.photo_button = ttk.Button(photo_frame, text="上传照片", 
                                      command=self.upload_photo, style='Action.TButton')
        self.photo_button.pack(side='left')
        
        self.photo_path_label = ttk.Label(photo_frame, text="未选择", 
                                         foreground='#95a5a6', background='#34495e')
        self.photo_path_label.pack(side='left', padx=10)
        
        # 主题选择
        theme_frame = ttk.Frame(scrollable_frame)
        theme_frame.pack(fill='x', pady=(20, 10))
        
        theme_label = ttk.Label(theme_frame, text="主题风格:", style='Input.TLabel', width=10)
        theme_label.pack(side='left', padx=(0, 10))
        
        self.theme_var = tk.StringVar(value="现代简约")
        theme_combo = ttk.Combobox(theme_frame, textvariable=self.theme_var, 
                                  values=list(self.themes.keys()), state='readonly',
                                  font=('Arial', 10))
        theme_combo.pack(side='left', fill='x', expand=True, ipady=5)
        theme_combo.bind('<<ComboboxSelected>>', self.on_theme_change)
    
    def create_preview_area(self, parent):
        """创建预览区域"""
        preview_container = ttk.Frame(parent)
        preview_container.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 预览标题
        preview_title = ttk.Label(preview_container, 
                                 text="👁️ 证件预览",
                                 style='Input.TLabel',
                                 font=('Arial', 12, 'bold'))
        preview_title.pack(pady=(0, 20))
        
        # 预览画布
        self.preview_canvas = tk.Canvas(preview_container, 
                                       bg='#2c3e50',
                                       width=400,
                                       height=500,
                                       highlightthickness=0)
        self.preview_canvas.pack(expand=True)
        
        # 默认预览
        self.show_default_preview()
    
    def create_control_panel(self, parent):
        """创建控制面板"""
        control_frame = ttk.Frame(parent, style='Card.TFrame')
        control_frame.pack(fill='x', pady=(10, 0))
        
        buttons = [
            ("🎨 生成预览", self.generate_preview, "#2ecc71"),
            ("💾 保存为图片", self.save_id_card, "#3498db"),
            ("🖨️ 打印预览", self.print_preview, "#9b59b6"),
            ("🧹 清空表单", self.clear_form, "#e74c3c"),
            ("📤 导出数据", self.export_data, "#1abc9c"),
            ("📥 导入数据", self.import_data, "#f39c12")
        ]
        
        for i, (text, command, color) in enumerate(buttons):
            btn = tk.Button(control_frame,
                          text=text,
                          command=command,
                          bg=color,
                          fg='white',
                          font=('Arial', 10, 'bold'),
                          padx=20,
                          pady=10,
                          borderwidth=0,
                          cursor='hand2',
                          activebackground=color,
                          activeforeground='white')
            btn.pack(side='left', expand=True, padx=5, pady=10)
            
            # 添加悬停效果
            btn.bind("<Enter>", lambda e, b=btn: e.widget.configure(bg=self.lighten_color(b['bg'])))
            btn.bind("<Leave>", lambda e, b=btn: e.widget.configure(bg=color))
    
    def lighten_color(self, color, factor=0.2):
        """颜色变亮"""
        from colorsys import rgb_to_hls, hls_to_rgb
        import re
        
        # 解析颜色
        match = re.match(r'#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})', color.lower())
        if match:
            r, g, b = [int(x, 16) for x in match.groups()]
            
            # 转换为HLS
            h, l, s = rgb_to_hls(r/255, g/255, b/255)
            
            # 增加亮度
            l = min(1.0, l + factor)
            
            # 转换回RGB
            r, g, b = [int(x*255) for x in hls_to_rgb(h, l, s)]
            
            return f'#{r:02x}{g:02x}{b:02x}'
        return color
    
    def upload_photo(self):
        """上传学生照片"""
        file_path = filedialog.askopenfilename(
            title="选择学生照片",
            filetypes=[("图片文件", "*.png *.jpg *.jpeg *.bmp *.gif")]
        )
        
        if file_path:
            self.student_photo_path = file_path
            filename = os.path.basename(file_path)
            self.photo_path_label.config(text=filename[:20] + "..." if len(filename) > 20 else filename)
            
            # 自动更新预览
            self.generate_preview()
    
    def on_theme_change(self, event=None):
        """主题改变事件"""
        self.generate_preview()
    
    def show_default_preview(self):
        """显示默认预览"""
        self.preview_canvas.delete("all")
        
        # 绘制默认背景
        self.preview_canvas.create_rectangle(20, 20, 380, 480, 
                                           fill='#ffffff', outline='#3498db', width=2)
        
        # 添加标题
        self.preview_canvas.create_text(200, 50, 
                                       text="学生证件预览",
                                       font=('Arial', 16, 'bold'),
                                       fill='#2c3e50')
        
        # 添加说明
        self.preview_canvas.create_text(200, 250,
                                       text="请填写左侧表单并点击\n【生成预览】按钮",
                                       font=('Arial', 12),
                                       fill='#7f8c8d',
                                       justify='center')
        
        # 添加图标
        self.preview_canvas.create_text(200, 150,
                                       text="🎓",
                                       font=('Arial', 60),
                                       fill='#3498db')
    
    def generate_preview(self):
        """生成证件预览"""
        try:
            # 收集表单数据
            self.student_data = {}
            for field, var in self.input_vars.items():
                self.student_data[field] = var.get()
            
            # 检查必要字段
            if not self.student_data.get('name') or not self.student_data.get('student_id'):
                messagebox.showwarning("提示", "请至少填写姓名和学号")
                return
            
            # 生成证件图片
            id_card = self.create_id_card()
            
            # 转换为PhotoImage
            id_card_tk = ImageTk.PhotoImage(id_card)
            
            # 清除画布
            self.preview_canvas.delete("all")
            
            # 计算位置使其居中
            img_width = id_card.width
            img_height = id_card.height
            canvas_width = self.preview_canvas.winfo_width() or 400
            canvas_height = self.preview_canvas.winfo_height() or 500
            
            x = (canvas_width - img_width) // 2
            y = (canvas_height - img_height) // 2
            
            # 在画布上显示图片
            self.preview_canvas.create_image(x, y, anchor='nw', image=id_card_tk)
            self.current_preview = id_card_tk  # 保持引用
            
            messagebox.showinfo("成功", "证件预览已生成！")
            
        except Exception as e:
            messagebox.showerror("错误", f"生成预览时出错:\n{str(e)}")
    
    def create_id_card(self):
        """创建学生证件图片"""
        # 证件尺寸
        width, height = 400, 250
        
        # 获取当前主题
        theme_name = self.theme_var.get()
        theme = self.themes.get(theme_name, self.themes['现代简约'])
        
        # 创建背景
        img = Image.new('RGB', (width, height), color=theme['bg_color'])
        draw = ImageDraw.Draw(img)
        
        # 添加装饰边框
        border_width = 2
        draw.rectangle([0, 0, width-1, height-1], 
theme['accent_color'], width=border_width)
        
        # 添加内边框
        inner_padding = 10
        draw.rectangle([inner_padding, inner_padding, width-inner_padding-1, height-inner_padding-1],
                      outline=theme['border_color'], width=1)
        
        # 添加背景装饰
        self.add_background_decoration(img, theme)
        
        # 加载并处理学生照片
        photo = self.process_student_photo()
        
        if photo:
            # 调整照片大小
            photo_size = 100
            photo = photo.resize((photo_size, photo_size), Image.Resampling.LANCZOS)
            
            # 添加圆形蒙版
            mask = Image.new('L', (photo_size, photo_size), 0)
            mask_draw = ImageDraw.Draw(mask)
            mask_draw.ellipse([0, 0, photo_size, photo_size], fill=255)
            
            # 创建带边框的圆形照片
            photo_with_border = Image.new('RGB', (photo_size+4, photo_size+4), theme['accent_color'])
            photo_with_border.paste(photo, (2, 2), mask)
            
            # 粘贴照片
            img.paste(photo_with_border, (width-120, 20))
        
        # 添加标题
        title = "学生证"
        try:
            title_font = ImageFont.truetype("simhei.ttf", 24)
        except:
            title_font = ImageFont.load_default()
        
        draw.text((20, 20), title, font=title_font, fill=theme['accent_color'])
        
        # 添加学校信息
        school = "某某大学"
        try:
            school_font = ImageFont.truetype("simhei.ttf", 18)
        except:
            school_font = ImageFont.load_default()
        
        draw.text((20, 60), school, font=school_font, fill=theme['text_color'])
        
        # 添加学生信息
        y_offset = 100
        line_height = 25
        
        info_items = [
            ("姓 名:", self.student_data.get('name', '')),
            ("学 号:", self.student_data.get('student_id', '')),
            ("学 院:", self.student_data.get('college', '')),
            ("专 业:", self.student_data.get('major', '')),
            ("班 级:", self.student_data.get('class_name', ''))
        ]
        
        try:
            label_font = ImageFont.truetype("simhei.ttf", 12)
            value_font = ImageFont.truetype("simhei.ttf", 12)
        except:
            label_font = ImageFont.load_default()
            value_font = ImageFont.load_default()
        
        for label, value in info_items:
            if value:  # 只显示有值的项目
                draw.text((20, y_offset), label, font=label_font, fill=theme['text_color'])
                draw.text((80, y_offset), value, font=value_font, fill=theme['text_color'])
                y_offset += line_height
        
        # 添加有效期
        expiry = f"有效期至: {self.student_data.get('expiry_date', '')}"
        if self.student_data.get('expiry_date'):
            draw.text((20, height-40), expiry, font=value_font, fill=theme['accent_color'])
        
        # 添加二维码
        qr_data = f"学生:{self.student_data.get('name', '')}\n学号:{self.student_data.get('student_id', '')}"
        qr_img = self.create_qr_code(qr_data)
        img.paste(qr_img, (width-100, height-100))
        
        # 添加装饰元素
        self.add_decorative_elements(img, theme)
        
        return img
    
    def add_background_decoration(self, img, theme):
        """添加背景装饰"""
        draw = ImageDraw.Draw(img, 'RGBA')
        width, height = img.size
        
        # 添加渐变效果
        for i in range(height):
            alpha = int(20 * (1 - i/height))
            color = tuple(list(int(theme['accent_color'][1:][j:j+2], 16) for j in (0, 2, 4)) + [alpha])
            draw.line([(0, i), (width, i)], fill=color)
        
        # 添加图案
        pattern_size = 50
        for x in range(0, width, pattern_size):
            for y in range(0, height, pattern_size):
                if (x//pattern_size + y//pattern_size) % 2 == 0:
                    draw.rectangle([x, y, x+pattern_size, y+pattern_size], 
                                 fill=(*tuple(int(theme['secondary_color'][1:][j:j+2], 16) for j in (0, 2, 4)), 10))
    
    def add_decorative_elements(self, img, theme):
        """添加装饰元素"""
        draw = ImageDraw.Draw(img, 'RGBA')
        width, height = img.size
        
        # 添加装饰线条
        draw.line([(10, 10), (width-10, 10), (width-10, height-10), (10, height-10), (10, 10)], 
                 fill=theme['accent_color'], width=1)
        
        # 添加装饰点
        for i in range(5):
            x = random.randint(20, width-20)
            y = random.randint(20, height-20)
            r = random.randint(2, 5)
            color = (*tuple(int(theme['accent_color'][1:][j:j+2], 16) for j in (0, 2, 4)), 100)
            draw.ellipse([x-r, y-r, x+r, y+r], fill=color)
    
    def process_student_photo(self):
        """处理学生照片"""
        if not self.student_photo_path:
            return None
        
        try:
            img = Image.open(self.student_photo_path)
            
            # 确保是RGB模式
            if img.mode != 'RGB':
                img = img.convert('RGB')
            
            # 调整大小
            max_size = 200
            img.thumbnail((max_size, max_size))
            
            return img
            
        except Exception as e:
            messagebox.showwarning("警告", f"无法处理照片: {str(e)}")
            return None
    
    def create_qr_code(self, data):
        """创建二维码"""
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=4,
            border=1,
        )
        qr.add_data(data)
        qr.make(fit=True)
        
        qr_img = qr.make_image(fill_color="black", back_color="white")
        qr_img = qr_img.resize((80, 80), Image.Resampling.LANCZOS)
        
        return qr_img
    
    def save_id_card(self):
        """保存证件为图片"""
        if not hasattr(self, 'current_preview'):
            messagebox.showwarning("提示", "请先生成预览")
            return
        
        file_path = filedialog.asksaveasfilename(
            defaultextension=".png",
            filetypes=[("PNG文件", "*.png"), ("JPEG文件", "*.jpg"), ("所有文件", "*.*")]
        )
        
        if file_path:
            try:
                # 重新生成高分辨率版本
                width, height = 800, 500
                theme = self.themes.get(self.theme_var.get(), self.themes['现代简约'])
                
                # 创建高分辨率版本
                high_res_img = Image.new('RGB', (width, height), color=theme['bg_color'])
                draw = ImageDraw.Draw(high_res_img)
                
                # 缩放并粘贴原图
                temp_img = self.create_id_card()
                temp_img = temp_img.resize((width, height), Image.Resampling.LANCZOS)
                high_res_img.paste(temp_img, (0, 0))
                
                # 保存
                high_res_img.save(file_path, quality=95)
                messagebox.showinfo("成功", f"证件已保存到:\n{file_path}")
                
            except Exception as e:
                messagebox.showerror("错误", f"保存失败:\n{str(e)}")
    
    def print_preview(self):
        """打印预览"""
        if not hasattr(self, 'current_preview'):
            messagebox.showwarning("提示", "请先生成预览")
            return
        
        messagebox.showinfo("打印预览", "打印功能已调用\n(实际打印需要连接打印机)")
    
    def clear_form(self):
        """清空表单"""
        for var in self.input_vars.values():
            var.set("")
        
        self.student_photo_path = None
        self.photo_path_label.config(text="未选择")
        self.show_default_preview()
        
        messagebox.showinfo("提示", "表单已清空")
    
    def export_data(self):
        """导出数据"""
        if not self.student_data:
            messagebox.showwarning("提示", "没有数据可导出")
            return
        
        file_path = filedialog.asksaveasfilename(
            defaultextension=".json",
            filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")]
        )
        
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    json.dump(self.student_data, f, ensure_ascii=False, indent=2)
                messagebox.showinfo("成功", f"数据已导出到:\n{file_path}")
            except Exception as e:
                messagebox.showerror("错误", f"导出失败:\n{str(e)}")
    
    def import_data(self):
        """导入数据"""
        file_path = filedialog.askopenfilename(
            filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")]
        )
        
        if file_path:
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                
                # 更新表单
                for field, value in data.items():
                    if field in self.input_vars:
                        self.input_vars[field].set(value)
                
                messagebox.showinfo("成功", "数据导入成功")
                self.generate_preview()
                
            except Exception as e:
                messagebox.showerror("错误", f"导入失败:\n{str(e)}")

def main():
    """主函数"""
    root = tk.Tk()
    app = StudentIDGenerator(root)
    
    # 添加关于菜单
    menubar = tk.Menu(root)
    help_menu = tk.Menu(menubar, tearoff=0)
    help_menu.add_command(label="使用说明", command=lambda: messagebox.showinfo("使用说明", 
        "1. 填写学生信息\n"
        "2. 上传学生照片\n"
        "3. 选择主题风格\n"
        "4. 点击【生成预览】\n"
        "5. 保存或打印证件"))
    help_menu.add_command(label="关于", command=lambda: messagebox.showinfo("关于", 
        "酷炫学生证件生成器 v1.0\n\n"
        "功能特点：\n"
        "• 多种主题风格\n"
        "• 支持照片上传\n"
        "• 自动生成二维码\n"
        "• 数据导入导出\n"
        "• 高分辨率输出"))
    menubar.add_cascade(label="帮助", menu=help_menu)
    root.config(menu=menubar)
    
    root.mainloop()

if __name__ == "__main__":
    # 检查依赖
    try:
        from PIL import Image, ImageTk, ImageDraw, ImageFont
    except ImportError:
        print("请先安装必要的依赖库：")
        print("pip install pillow qrcode")
        input("按回车键退出...")
        exit(1)
    
    main()