#!/usr/bin/env python3
"""
Integrated Modify Panel for PunimTag Dashboard
Embeds the full modify identified GUI functionality into the dashboard frame
"""

import os
import tkinter as tk
from tkinter import ttk, messagebox
from PIL import Image, ImageTk
from typing import List, Dict, Tuple, Optional

from src.core.config import DEFAULT_FACE_TOLERANCE
from src.core.database import DatabaseManager
from src.core.face_processing import FaceProcessor
from src.gui.gui_core import GUICore


class ToolTip:
    """Simple tooltip implementation"""
    def __init__(self, widget, text):
        self.widget = widget
        self.text = text
        self.tooltip_window = None
        self.widget.bind("<Enter>", self.on_enter)
        self.widget.bind("<Leave>", self.on_leave)

    def on_enter(self, event=None):
        if self.tooltip_window or not self.text:
            return
        x, y, _, _ = self.widget.bbox("insert") if hasattr(self.widget, 'bbox') else (0, 0, 0, 0)
        x += self.widget.winfo_rootx() + 25
        y += self.widget.winfo_rooty() + 25

        self.tooltip_window = tw = tk.Toplevel(self.widget)
        tw.wm_overrideredirect(True)
        tw.wm_geometry(f"+{x}+{y}")

        label = tk.Label(tw, text=self.text, justify=tk.LEFT,
                         background="#ffffe0", relief=tk.SOLID, borderwidth=1,
                         font=("tahoma", "8", "normal"))
        label.pack(ipadx=1)

    def on_leave(self, event=None):
        if self.tooltip_window:
            self.tooltip_window.destroy()
            self.tooltip_window = None


class ModifyPanel:
    """Integrated modify panel that embeds the full modify identified GUI functionality into the dashboard"""
    
    def __init__(self, parent_frame: ttk.Frame, db_manager: DatabaseManager, 
                 face_processor: FaceProcessor, gui_core: GUICore, on_navigate_home=None, verbose: int = 0):
        """Initialize the modify panel"""
        self.parent_frame = parent_frame
        self.db = db_manager
        self.face_processor = face_processor
        self.gui_core = gui_core
        self.on_navigate_home = on_navigate_home
        self.verbose = verbose
        
        # Panel state
        self.is_active = False
        self.temp_crops = []
        self.right_panel_images = []  # Keep PhotoImage refs alive
        self.selected_person_id = None
        
        # Track unmatched faces (temporary changes)
        self.unmatched_faces = set()  # All face IDs unmatched across people (for global save)
        self.unmatched_by_person = {}  # person_id -> set(face_id) for per-person undo
        self.original_faces_data = []  # store original faces data for potential future use
        
        # People data
        self.people_data = []  # list of dicts: {id, name, count, first_name, last_name}
        self.people_filtered = None  # filtered subset based on last name search
        self.current_person_id = None
        self.current_person_name = ""
        self.resize_job = None
        
        # GUI components
        self.components = {}
        self.main_frame = None
        
    def create_panel(self) -> ttk.Frame:
        """Create the modify panel with all GUI components"""
        self.main_frame = ttk.Frame(self.parent_frame)
        
        # Configure grid weights for full screen responsiveness
        self.main_frame.columnconfigure(0, weight=1)  # Left panel
        self.main_frame.columnconfigure(1, weight=2)  # Right panel
        self.main_frame.rowconfigure(1, weight=1)     # Main panels row - expandable
        
        # Create all GUI components
        self._create_gui_components()
        
        # Create main content panels
        self._create_main_panels()
        
        return self.main_frame
    
    def _create_gui_components(self):
        """Create all GUI components for the modify interface"""
        # Search controls (Last Name) with label under the input (match auto-match style)
        self.components['last_name_search_var'] = tk.StringVar()
        
        # Control buttons
        self.components['quit_btn'] = None
        self.components['save_btn_bottom'] = None
        
    def _create_main_panels(self):
        """Create the main left and right panels"""
        # Left panel: People list
        self.components['people_frame'] = ttk.LabelFrame(self.main_frame, text="People", padding="10")
        self.components['people_frame'].grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 8))
        self.components['people_frame'].columnconfigure(0, weight=1)

        # Right panel: Faces for selected person
        self.components['faces_frame'] = ttk.LabelFrame(self.main_frame, text="Faces", padding="10")
        self.components['faces_frame'].grid(row=1, column=1, sticky=(tk.W, tk.E, tk.N, tk.S))
        self.components['faces_frame'].columnconfigure(0, weight=1)
        self.components['faces_frame'].rowconfigure(0, weight=1)
        
        # Create left panel content
        self._create_left_panel_content()
        
        # Create right panel content
        self._create_right_panel_content()
        
        # Create control buttons
        self._create_control_buttons()
    
    def _create_left_panel_content(self):
        """Create the left panel content for people list"""
        people_frame = self.components['people_frame']
        
        # Search controls
        search_frame = ttk.Frame(people_frame)
        search_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 6))

        # Entry on the left
        search_entry = ttk.Entry(search_frame, textvariable=self.components['last_name_search_var'], width=20)
        search_entry.grid(row=0, column=0, sticky=tk.W)

        # Buttons to the right of the entry
        buttons_row = ttk.Frame(search_frame)
        buttons_row.grid(row=0, column=1, sticky=tk.W, padx=(6, 0))
        search_btn = ttk.Button(buttons_row, text="Search", width=8, command=self.apply_last_name_filter)
        search_btn.pack(side=tk.LEFT, padx=(0, 5))
        clear_btn = ttk.Button(buttons_row, text="Clear", width=6, command=self.clear_last_name_filter)
        clear_btn.pack(side=tk.LEFT)

        # Helper label directly under the entry
        last_name_label = ttk.Label(search_frame, text="Type Last Name", font=("Arial", 8), foreground="gray")
        last_name_label.grid(row=1, column=0, sticky=tk.W, pady=(2, 0))

        # People list with scrollbar
        people_canvas = tk.Canvas(people_frame, bg='white')
        people_scrollbar = ttk.Scrollbar(people_frame, orient="vertical", command=people_canvas.yview)
        self.components['people_list_inner'] = ttk.Frame(people_canvas)
        people_canvas.create_window((0, 0), window=self.components['people_list_inner'], anchor="nw")
        people_canvas.configure(yscrollcommand=people_scrollbar.set)

        self.components['people_list_inner'].bind(
            "<Configure>",
            lambda e: people_canvas.configure(scrollregion=people_canvas.bbox("all"))
        )

        people_canvas.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        people_scrollbar.grid(row=1, column=1, sticky=(tk.N, tk.S))
        people_frame.rowconfigure(1, weight=1)
        
        # Store canvas reference
        self.components['people_canvas'] = people_canvas
        
        # Bind Enter key for search
        search_entry.bind('<Return>', lambda e: self.apply_last_name_filter())
    
    def _create_right_panel_content(self):
        """Create the right panel content for faces display"""
        faces_frame = self.components['faces_frame']
        
        # Style configuration
        style = ttk.Style()
        canvas_bg_color = style.lookup('TFrame', 'background') or '#d9d9d9'
        
        self.components['faces_canvas'] = tk.Canvas(faces_frame, bg=canvas_bg_color, highlightthickness=0)
        faces_scrollbar = ttk.Scrollbar(faces_frame, orient="vertical", command=self.components['faces_canvas'].yview)
        self.components['faces_inner'] = ttk.Frame(self.components['faces_canvas'])
        self.components['faces_canvas'].create_window((0, 0), window=self.components['faces_inner'], anchor="nw")
        self.components['faces_canvas'].configure(yscrollcommand=faces_scrollbar.set)

        self.components['faces_inner'].bind(
            "<Configure>",
            lambda e: self.components['faces_canvas'].configure(scrollregion=self.components['faces_canvas'].bbox("all"))
        )

        # Bind resize handler for responsive face grid
        self.components['faces_canvas'].bind("<Configure>", self.on_faces_canvas_resize)

        self.components['faces_canvas'].grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        faces_scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
    
    def _create_control_buttons(self):
        """Create control buttons at the bottom"""
        # Control buttons
        control_frame = ttk.Frame(self.main_frame)
        control_frame.grid(row=2, column=0, columnspan=2, pady=(10, 0), sticky=tk.E)

        self.components['quit_btn'] = ttk.Button(control_frame, text="❌ Exit Edit Identified", command=self.on_quit)
        self.components['quit_btn'].pack(side=tk.RIGHT)
        self.components['save_btn_bottom'] = ttk.Button(control_frame, text="💾 Save changes", command=self.on_save_all_changes, state="disabled")
        self.components['save_btn_bottom'].pack(side=tk.RIGHT, padx=(0, 10))
        self.components['undo_btn'] = ttk.Button(control_frame, text="↶ Undo changes", command=self.undo_changes, state="disabled")
        self.components['undo_btn'].pack(side=tk.RIGHT, padx=(0, 10))
    
    def on_faces_canvas_resize(self, event):
        """Handle canvas resize for responsive face grid"""
        if self.current_person_id is None:
            return
        # Debounce re-render on resize
        try:
            if self.resize_job is not None:
                self.main_frame.after_cancel(self.resize_job)
        except Exception:
            pass
        self.resize_job = self.main_frame.after(150, lambda: self.show_person_faces(self.current_person_id, self.current_person_name))

    def load_people(self):
        """Load people from database with counts"""
        with self.db.get_db_connection() as conn:
            cursor = conn.cursor()
            cursor.execute(
                """
                SELECT p.id, p.first_name, p.last_name, p.middle_name, p.maiden_name, p.date_of_birth, COUNT(f.id) as face_count
                FROM people p
                JOIN faces f ON f.person_id = p.id
                GROUP BY p.id, p.last_name, p.first_name, p.middle_name, p.maiden_name, p.date_of_birth
                HAVING face_count > 0
                ORDER BY p.last_name, p.first_name COLLATE NOCASE
                """
            )
            self.people_data = []
            for (pid, first_name, last_name, middle_name, maiden_name, date_of_birth, count) in cursor.fetchall():
                # Create full name display with all available information
                name_parts = []
                if first_name:
                    name_parts.append(first_name)
                if middle_name:
                    name_parts.append(middle_name)
                if last_name:
                    name_parts.append(last_name)
                if maiden_name:
                    name_parts.append(f"({maiden_name})")

                full_name = ' '.join(name_parts) if name_parts else "Unknown"

                # Create detailed display with date of birth if available
                display_name = full_name
                if date_of_birth:
                    display_name += f" - Born: {date_of_birth}"

                self.people_data.append({
                    'id': pid,
                    'name': display_name,
                    'full_name': full_name,
                    'first_name': first_name or "",
                    'last_name': last_name or "",
                    'middle_name': middle_name or "",
                    'maiden_name': maiden_name or "",
                    'date_of_birth': date_of_birth or "",
                    'count': count
                })
        # Re-apply filter (if any) after loading
        try:
            self.apply_last_name_filter()
        except Exception:
            pass

    def apply_last_name_filter(self):
        """Apply last name filter to people list"""
        query = self.components['last_name_search_var'].get().strip().lower()
        if query:
            self.people_filtered = [p for p in self.people_data if p.get('last_name', '').lower().find(query) != -1]
        else:
            self.people_filtered = None
        self.populate_people_list()

    def clear_last_name_filter(self):
        """Clear the last name filter"""
        self.components['last_name_search_var'].set("")
        self.people_filtered = None
        self.populate_people_list()

    def populate_people_list(self):
        """Populate the people list with current data"""
        # Clear existing widgets
        for widget in self.components['people_list_inner'].winfo_children():
            widget.destroy()

        # Use filtered data if available, otherwise use all data
        people_to_show = self.people_filtered if self.people_filtered is not None else self.people_data

        for i, person in enumerate(people_to_show):
            row_frame = ttk.Frame(self.components['people_list_inner'])
            row_frame.pack(fill=tk.X, padx=2, pady=1)

            # Edit button (on the left)
            edit_btn = ttk.Button(row_frame, text="✏️", width=3, 
                                command=lambda p=person: self.start_edit_person(p))
            edit_btn.pack(side=tk.LEFT, padx=(0, 5))
            # Add tooltip to edit button
            ToolTip(edit_btn, "Update name")

            # Label (clickable) - takes remaining space
            name_lbl = ttk.Label(row_frame, text=f"{person['name']} ({person['count']})", font=("Arial", 10))
            name_lbl.pack(side=tk.LEFT, fill=tk.X, expand=True)
            name_lbl.bind("<Button-1>", lambda e, p=person: self.show_person_faces(p['id'], p['name']))
            name_lbl.config(cursor="hand2")

            # Bold if selected
            if (self.selected_person_id is None and i == 0) or (self.selected_person_id == person['id']):
                name_lbl.config(font=("Arial", 10, "bold"))

    def start_edit_person(self, person_record):
        """Start editing a person's information"""
        # Create a new window for editing
        edit_window = tk.Toplevel(self.main_frame)
        edit_window.title(f"Edit {person_record['name']}")
        edit_window.geometry("500x400")
        edit_window.transient(self.main_frame)
        edit_window.grab_set()

        # Center the window
        edit_window.update_idletasks()
        x = (edit_window.winfo_screenwidth() // 2) - (edit_window.winfo_width() // 2)
        y = (edit_window.winfo_screenheight() // 2) - (edit_window.winfo_height() // 2)
        edit_window.geometry(f"+{x}+{y}")

        # Create form fields
        form_frame = ttk.Frame(edit_window, padding="20")
        form_frame.pack(fill=tk.BOTH, expand=True)

        # First name
        ttk.Label(form_frame, text="First name:").grid(row=0, column=0, sticky=tk.W, pady=5)
        first_name_var = tk.StringVar(value=person_record.get('first_name', ''))
        first_entry = ttk.Entry(form_frame, textvariable=first_name_var, width=30)
        first_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5)

        # Last name
        ttk.Label(form_frame, text="Last name:").grid(row=1, column=0, sticky=tk.W, pady=5)
        last_name_var = tk.StringVar(value=person_record.get('last_name', ''))
        last_entry = ttk.Entry(form_frame, textvariable=last_name_var, width=30)
        last_entry.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=5)

        # Middle name
        ttk.Label(form_frame, text="Middle name:").grid(row=2, column=0, sticky=tk.W, pady=5)
        middle_name_var = tk.StringVar(value=person_record.get('middle_name', ''))
        middle_entry = ttk.Entry(form_frame, textvariable=middle_name_var, width=30)
        middle_entry.grid(row=2, column=1, sticky=(tk.W, tk.E), pady=5)

        # Maiden name
        ttk.Label(form_frame, text="Maiden name:").grid(row=3, column=0, sticky=tk.W, pady=5)
        maiden_name_var = tk.StringVar(value=person_record.get('maiden_name', ''))
        maiden_entry = ttk.Entry(form_frame, textvariable=maiden_name_var, width=30)
        maiden_entry.grid(row=3, column=1, sticky=(tk.W, tk.E), pady=5)

        # Date of birth
        ttk.Label(form_frame, text="Date of birth:").grid(row=4, column=0, sticky=tk.W, pady=5)
        dob_var = tk.StringVar(value=person_record.get('date_of_birth', ''))
        dob_entry = ttk.Entry(form_frame, textvariable=dob_var, width=30, state='readonly')
        dob_entry.grid(row=4, column=1, sticky=(tk.W, tk.E), pady=5)

        # Calendar button for date of birth
        def open_dob_calendar():
            selected_date = self.gui_core.create_calendar_dialog(edit_window, "Select Date of Birth", dob_var.get())
            if selected_date is not None:
                dob_var.set(selected_date)

        dob_calendar_btn = ttk.Button(form_frame, text="📅", width=3, command=open_dob_calendar)
        dob_calendar_btn.grid(row=4, column=2, padx=(5, 0), pady=5)

        # Configure grid weights
        form_frame.columnconfigure(1, weight=1)

        # Buttons
        button_frame = ttk.Frame(edit_window)
        button_frame.pack(fill=tk.X, padx=20, pady=10)

        def save_rename():
            """Save the renamed person"""
            try:
                with self.db.get_db_connection() as conn:
                    cursor = conn.cursor()
                    cursor.execute("""
                        UPDATE people 
                        SET first_name = ?, last_name = ?, middle_name = ?, maiden_name = ?, date_of_birth = ?
                        WHERE id = ?
                    """, (
                        first_name_var.get().strip(),
                        last_name_var.get().strip(),
                        middle_name_var.get().strip(),
                        maiden_name_var.get().strip(),
                        dob_var.get().strip(),
                        person_record['id']
                    ))
                    conn.commit()
                
                # Refresh the people list
                self.load_people()
                self.populate_people_list()
                
                # Close the edit window
                edit_window.destroy()
                
                messagebox.showinfo("Success", "Person information updated successfully.")
                
            except Exception as e:
                messagebox.showerror("Error", f"Failed to update person: {e}")

        def cancel_edit():
            """Cancel editing"""
            edit_window.destroy()

        save_btn = ttk.Button(button_frame, text="Save", command=save_rename)
        save_btn.pack(side=tk.LEFT, padx=(0, 10))
        cancel_btn = ttk.Button(button_frame, text="Cancel", command=cancel_edit)
        cancel_btn.pack(side=tk.LEFT)

        # Focus on first name field
        first_entry.focus_set()
        
        # Add keyboard shortcuts
        def try_save():
            if save_btn.cget('state') == 'normal':
                save_rename()

        first_entry.bind('<Return>', lambda e: try_save())
        last_entry.bind('<Return>', lambda e: try_save())
        middle_entry.bind('<Return>', lambda e: try_save())
        maiden_entry.bind('<Return>', lambda e: try_save())
        dob_entry.bind('<Return>', lambda e: try_save())
        first_entry.bind('<Escape>', lambda e: cancel_edit())
        last_entry.bind('<Escape>', lambda e: cancel_edit())
        middle_entry.bind('<Escape>', lambda e: cancel_edit())
        maiden_entry.bind('<Escape>', lambda e: cancel_edit())
        dob_entry.bind('<Escape>', lambda e: cancel_edit())
        
        # Add validation
        def validate_save_button():
            first_name = first_name_var.get().strip()
            last_name = last_name_var.get().strip()
            if first_name and last_name:
                save_btn.config(state='normal')
            else:
                save_btn.config(state='disabled')
        
        # Bind validation to all fields
        first_name_var.trace('w', lambda *args: validate_save_button())
        last_name_var.trace('w', lambda *args: validate_save_button())
        middle_name_var.trace('w', lambda *args: validate_save_button())
        maiden_name_var.trace('w', lambda *args: validate_save_button())
        dob_var.trace('w', lambda *args: validate_save_button())
        
        # Initial validation
        validate_save_button()

    def show_person_faces(self, person_id, person_name):
        """Show faces for the selected person"""
        self.current_person_id = person_id
        self.current_person_name = person_name
        self.selected_person_id = person_id
        
        # Clear existing face widgets
        for widget in self.components['faces_inner'].winfo_children():
            widget.destroy()
        
        # Load faces for this person
        with self.db.get_db_connection() as conn:
            cursor = conn.cursor()
            cursor.execute("""
                SELECT f.id, f.photo_id, p.path, p.filename, f.location,
                       f.face_confidence, f.quality_score, f.detector_backend, f.model_name
                FROM faces f
                JOIN photos p ON f.photo_id = p.id
                WHERE f.person_id = ?
                ORDER BY p.filename
            """, (person_id,))
            
            faces = cursor.fetchall()
        
        # Filter out unmatched faces
        visible_faces = [face for face in faces if face[0] not in self.unmatched_faces]
        
        if not visible_faces:
            if not faces:
                no_faces_label = ttk.Label(self.components['faces_inner'], 
                                         text="No faces found for this person", 
                                         font=("Arial", 12))
            else:
                no_faces_label = ttk.Label(self.components['faces_inner'], 
                                         text="All faces unmatched", 
                                         font=("Arial", 12))
            no_faces_label.pack(pady=20)
            return
        
        # Display faces in a grid
        self._display_faces_grid(visible_faces)
        
        # Update people list to show selection
        self.populate_people_list()
        
        # Update button states based on unmatched faces
        self._update_undo_button_state()
        self._update_save_button_state()

    def _display_faces_grid(self, faces):
        """Display faces in a responsive grid layout"""
        # Calculate grid dimensions based on canvas width
        canvas_width = self.components['faces_canvas'].winfo_width()
        if canvas_width < 100:  # Canvas not yet rendered
            canvas_width = 400  # Default width
        
        face_size = 80
        padding = 10
        faces_per_row = max(1, (canvas_width - padding) // (face_size + padding))
        
        # Clear existing images
        self.right_panel_images.clear()
        
        for i, (face_id, photo_id, photo_path, filename, location, face_conf, quality, detector, model) in enumerate(faces):
            row = i // faces_per_row
            col = i % faces_per_row
            
            # Create face frame
            face_frame = ttk.Frame(self.components['faces_inner'])
            face_frame.grid(row=row, column=col, padx=5, pady=5, sticky=(tk.W, tk.E, tk.N, tk.S))
            
            # Face image
            try:
                face_crop_path = self.face_processor._extract_face_crop(photo_path, location, face_id)
                if face_crop_path and os.path.exists(face_crop_path):
                    self.temp_crops.append(face_crop_path)
                    
                    image = Image.open(face_crop_path)
                    image.thumbnail((face_size, face_size), Image.Resampling.LANCZOS)
                    photo = ImageTk.PhotoImage(image)
                    self.right_panel_images.append(photo)  # Keep reference
                    
                    # Create canvas for face image
                    face_canvas = tk.Canvas(face_frame, width=face_size, height=face_size, highlightthickness=0)
                    face_canvas.pack()
                    face_canvas.create_image(face_size//2, face_size//2, image=photo, anchor=tk.CENTER)
                    
                    # Add photo icon
                    self.gui_core.create_photo_icon(face_canvas, photo_path, icon_size=15,
                                                  face_x=0, face_y=0, 
                                                  face_width=face_size, face_height=face_size,
                                                  canvas_width=face_size, canvas_height=face_size)
                    
                    # Unmatch button
                    unmatch_btn = ttk.Button(face_frame, text="Unmatch", 
                                           command=lambda fid=face_id: self.unmatch_face(fid))
                    unmatch_btn.pack(pady=2)
                    
                else:
                    # Placeholder for missing face crop
                    placeholder_label = ttk.Label(face_frame, text=f"Face {face_id}", 
                                                font=("Arial", 8))
                    placeholder_label.pack()
                    
            except Exception as e:
                print(f"Error displaying face {face_id}: {e}")
                # Placeholder for error
                error_label = ttk.Label(face_frame, text=f"Error {face_id}", 
                                      font=("Arial", 8), foreground="red")
                error_label.pack()

    def unmatch_face(self, face_id):
        """Unmatch a face from its person"""
        if face_id not in self.unmatched_faces:
            self.unmatched_faces.add(face_id)
            if self.current_person_id not in self.unmatched_by_person:
                self.unmatched_by_person[self.current_person_id] = set()
            self.unmatched_by_person[self.current_person_id].add(face_id)
            print(f"Face {face_id} marked for unmatching")
            # Immediately refresh the display to hide the unmatched face
            if self.current_person_id:
                self.show_person_faces(self.current_person_id, self.current_person_name)
                # Update button states
                self._update_undo_button_state()
                self._update_save_button_state()

    def _update_undo_button_state(self):
        """Update the undo button state based on unmatched faces for current person"""
        if 'undo_btn' in self.components:
            current_has_unmatched = bool(self.unmatched_by_person.get(self.current_person_id))
            if current_has_unmatched:
                self.components['undo_btn'].config(state="normal")
            else:
                self.components['undo_btn'].config(state="disabled")

    def _update_save_button_state(self):
        """Update the save button state based on whether there are any unmatched faces to save"""
        if 'save_btn_bottom' in self.components:
            if self.unmatched_faces:
                self.components['save_btn_bottom'].config(state="normal")
            else:
                self.components['save_btn_bottom'].config(state="disabled")

    def undo_changes(self):
        """Undo all unmatched faces for the current person"""
        if self.current_person_id and self.current_person_id in self.unmatched_by_person:
            # Remove faces for current person from unmatched sets
            person_faces = self.unmatched_by_person[self.current_person_id]
            self.unmatched_faces -= person_faces
            del self.unmatched_by_person[self.current_person_id]
            
            # Refresh the display to show the restored faces
            if self.current_person_id:
                self.show_person_faces(self.current_person_id, self.current_person_name)
                # Update button states
                self._update_undo_button_state()
                self._update_save_button_state()
            
            messagebox.showinfo("Undo", f"Undid changes for {len(person_faces)} face(s).")
        else:
            messagebox.showinfo("No Changes", "No changes to undo for this person.")


    def on_quit(self):
        """Handle quit button click"""
        # Check for unsaved changes
        if self.unmatched_faces:
            result = self.gui_core.create_large_messagebox(
                self.main_frame,
                "Unsaved Changes",
                f"You have {len(self.unmatched_faces)} unsaved changes.\n\n"
                "Do you want to save them before quitting?\n\n"
                "• Yes: Save changes and quit\n"
                "• No: Quit without saving\n"
                "• Cancel: Return to modify",
                "askyesnocancel"
            )
            
            if result is True:  # Yes - Save and quit
                self.on_save_all_changes()
            elif result is False:  # No - Quit without saving
                pass
            else:  # Cancel - Don't quit
                return
        
        # Clean up and deactivate
        self._cleanup()
        self.is_active = False
        
        # Navigate to home if callback is available (dashboard mode)
        if self.on_navigate_home:
            self.on_navigate_home()

    def on_save_all_changes(self):
        """Save all unmatched faces to database"""
        if not self.unmatched_faces:
            messagebox.showinfo("No Changes", "No changes to save.")
            return
        
        try:
            with self.db.get_db_connection() as conn:
                cursor = conn.cursor()
                count = 0
                for face_id in self.unmatched_faces:
                    cursor.execute("UPDATE faces SET person_id = NULL WHERE id = ?", (face_id,))
                    count += 1
                conn.commit()
            
            # Clear the unmatched faces
            self.unmatched_faces.clear()
            self.unmatched_by_person.clear()
            
            # Refresh the display
            if self.current_person_id:
                self.show_person_faces(self.current_person_id, self.current_person_name)
            
            # Update button states
            self._update_undo_button_state()
            self._update_save_button_state()
            
            messagebox.showinfo("Changes Saved", f"Successfully unlinked {count} face(s).")
            
        except Exception as e:
            messagebox.showerror("Error", f"Failed to save changes: {e}")

    def _cleanup(self):
        """Clean up resources"""
        # Clear temporary crops
        for crop_path in self.temp_crops:
            try:
                if os.path.exists(crop_path):
                    os.remove(crop_path)
            except Exception:
                pass
        self.temp_crops.clear()
        
        # Clear right panel images
        self.right_panel_images.clear()
        
        # Clear state
        self.unmatched_faces.clear()
        self.unmatched_by_person.clear()
        self.original_faces_data.clear()
        self.people_data.clear()
        self.people_filtered = None
        self.current_person_id = None
        self.current_person_name = ""
        self.selected_person_id = None

    def activate(self):
        """Activate the panel"""
        self.is_active = True
        # Initial load
        self.load_people()
        self.populate_people_list()
        
        # Show first person's faces by default and mark selected
        if self.people_data:
            self.selected_person_id = self.people_data[0]['id']
            self.show_person_faces(self.people_data[0]['id'], self.people_data[0]['name'])

    def deactivate(self):
        """Deactivate the panel"""
        if self.is_active:
            self._cleanup()
            self.is_active = False

    def update_layout(self):
        """Update panel layout for responsiveness"""
        if hasattr(self, 'components') and 'faces_canvas' in self.components:
            # Update faces canvas scroll region
            canvas = self.components['faces_canvas']
            canvas.update_idletasks()
            canvas.configure(scrollregion=canvas.bbox("all"))
