import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
from datetime import datetime, timedelta
import mysql.connector
from mysql.connector import Error

# ===================== DATABASE CONNECTION =====================
def get_db_connection():
    try:
        return mysql.connector.connect(
            host="localhost",
            user="root",
            password="root",  # Change to your MySQL password
            database="library"  # Change to your database name
        )
    except Error as e:
        messagebox.showerror("Database Error", f"Could not connect to the database: {e}")
        return None

# ===================== CUSTOM DIALOGS =====================
class AddOrUpdateBookDialog(tk.Toplevel):
    def __init__(self, parent, on_submit, title="Add Book", book_data=None):
        super().__init__(parent)
        self.title(title)
        self.configure(bg="#34495e")
        self.on_submit = on_submit
        self.book_data = book_data
        self.parent = parent

        self.geometry("400x320")
        self.resizable(False, False)

        self.grab_set()
        self.transient(parent)

        tk.Label(self, text=title, font=("Helvetica", 16, "bold"), fg="white", bg="#34495e").pack(pady=10)

        frame = tk.Frame(self, bg="#34495e")
        frame.pack(padx=20, pady=10)

        tk.Label(frame, text="Title:", fg="white", bg="#34495e").grid(row=0, column=0, sticky="w", pady=5)
        self.title_var = tk.StringVar(value=book_data['title'] if book_data else "")
        tk.Entry(frame, textvariable=self.title_var, width=35).grid(row=0, column=1)

        tk.Label(frame, text="Author:", fg="white", bg="#34495e").grid(row=1, column=0, sticky="w", pady=5)
        self.author_var = tk.StringVar(value=book_data['author'] if book_data else "")
        tk.Entry(frame, textvariable=self.author_var, width=35).grid(row=1, column=1)

        tk.Label(frame, text="Quantity:", fg="white", bg="#34495e").grid(row=2, column=0, sticky="w", pady=5)
        self.quantity_var = tk.StringVar(value=str(book_data['quantity']) if book_data else "0")
        tk.Entry(frame, textvariable=self.quantity_var, width=35).grid(row=2, column=1)

        tk.Label(frame, text="Category:", fg="white", bg="#34495e").grid(row=3, column=0, sticky="w", pady=5)
        self.category_var = tk.StringVar(value=book_data['category'] if book_data else "")
        tk.Entry(frame, textvariable=self.category_var, width=35).grid(row=3, column=1)

        btn_frame = tk.Frame(self, bg="#34495e")
        btn_frame.pack(pady=15)

        tk.Button(btn_frame, text="Submit", command=self.submit, bg="#2ecc71", fg="white",
                  font=("Helvetica", 12)).pack(side="left", padx=10)
        tk.Button(btn_frame, text="Cancel", command=self.destroy, bg="#e74c3c", fg="white",
                  font=("Helvetica", 12)).pack(side="left")

    def submit(self):
        title = self.title_var.get().strip()
        author = self.author_var.get().strip()
        quantity = self.quantity_var.get().strip()
        category = self.category_var.get().strip()

        if not title or not author or not quantity or not category:
            messagebox.showerror("Input Error", "All fields are required.", parent=self)
            return

        try:
            quantity_val = int(quantity)
            if quantity_val < 0:
                raise ValueError
        except ValueError:
            messagebox.showerror("Input Error", "Quantity must be a non-negative integer.", parent=self)
            return

        self.on_submit(title, author, quantity_val, category)
        self.destroy()

class IssueBookDialog(tk.Toplevel):
    def __init__(self, parent, on_submit):
        super().__init__(parent)
        self.title("Issue Book")
        self.configure(bg="#34495e")
        self.geometry("400x180")
        self.resizable(False, False)
        self.parent = parent

        self.grab_set()
        self.transient(parent)

        self.on_submit = on_submit

        tk.Label(self, text="Issue Book", font=("Helvetica", 16, "bold"), fg="white", bg="#34495e").pack(pady=10)

        frame = tk.Frame(self, bg="#34495e")
        frame.pack(padx=20, pady=10)

        tk.Label(frame, text="Book ID:", fg="white", bg="#34495e").grid(row=0, column=0, sticky="w", pady=5)
        self.book_id_var = tk.StringVar()
        tk.Entry(frame, textvariable=self.book_id_var, width=35).grid(row=0, column=1)

        tk.Label(frame, text="Student Username:", fg="white", bg="#34495e").grid(row=1, column=0, sticky="w", pady=5)
        self.username_var = tk.StringVar()
        tk.Entry(frame, textvariable=self.username_var, width=35).grid(row=1, column=1)

        btn_frame = tk.Frame(self, bg="#34495e")
        btn_frame.pack(pady=15)

        tk.Button(btn_frame, text="Issue", command=self.submit, bg="#2ecc71", fg="white", font=("Helvetica", 12)).pack(side="left", padx=10)
        tk.Button(btn_frame, text="Cancel", command=self.destroy, bg="#e74c3c", fg="white", font=("Helvetica", 12)).pack(side="left")

    def submit(self):
        book_id = self.book_id_var.get().strip()
        username = self.username_var.get().strip()

        if not book_id or not username:
            messagebox.showerror("Input Error", "Both Book ID and Student Username are required", parent=self)
            return
        if not book_id.isdigit():
            messagebox.showerror("Input Error", "Book ID must be an integer", parent=self)
            return

        self.on_submit(int(book_id), username)
        self.destroy()

class ReturnBookDialog(tk.Toplevel):
    def __init__(self, parent, on_submit):
        super().__init__(parent)
        self.title("Return Book")
        self.configure(bg="#34495e")
        self.geometry("350x150")
        self.resizable(False, False)
        self.parent = parent

        self.grab_set()
        self.transient(parent)

        self.on_submit = on_submit

        tk.Label(self, text="Return Book", font=("Helvetica", 16, "bold"), fg="white", bg="#34495e").pack(pady=10)

        frame = tk.Frame(self, bg="#34495e")
        frame.pack(padx=20, pady=10)

        tk.Label(frame, text="Issue ID:", fg="white", bg="#34495e").grid(row=0, column=0, sticky="w", pady=5)
        self.issue_id_var = tk.StringVar()
        tk.Entry(frame, textvariable=self.issue_id_var, width=30).grid(row=0, column=1)

        btn_frame = tk.Frame(self, bg="#34495e")
        btn_frame.pack(pady=15)

        tk.Button(btn_frame, text="Return", command=self.submit, bg="#2ecc71", fg="white", font=("Helvetica", 12)).pack(side="left", padx=10)
        tk.Button(btn_frame, text="Cancel", command=self.destroy, bg="#e74c3c", fg="white", font=("Helvetica", 12)).pack(side="left")

    def submit(self):
        issue_id = self.issue_id_var.get().strip()

        if not issue_id:
            messagebox.showerror("Input Error", "Issue ID is required", parent=self)
            return
        if not issue_id.isdigit():
            messagebox.showerror("Input Error", "Issue ID must be an integer", parent=self)
            return

        self.on_submit(int(issue_id))
        self.destroy()

# ===================== ADMIN FUNCTIONS =====================
def view_books_admin(parent):
    admin_books_win = tk.Toplevel(parent)
    admin_books_win.title("View All Books (Admin)")
    admin_books_win.geometry("900x600")
    admin_books_win.configure(bg="#ecf0f1")

    columns = ("ID", "Title", "Author", "Quantity", "Category")
    tree = ttk.Treeview(admin_books_win, columns=columns, show="headings")
    for col in columns:
        tree.heading(col, text=col)
        tree.column(col, anchor="center")
    tree.pack(fill="both", expand=True, padx=20, pady=20)

    # Scrollbar
    scrollbar = ttk.Scrollbar(admin_books_win, orient="vertical", command=tree.yview)
    tree.configure(yscroll=scrollbar.set)
    scrollbar.place(relx=0.97, rely=0.09, relheight=0.82)

    db = get_db_connection()
    if not db:
        return
    cursor = db.cursor()
    try:
        cursor.execute("SELECT id, title, author, quantity, category FROM books")
        rows = cursor.fetchall()
        for row in rows:
            tree.insert("", "end", values=row)
    except Error as e:
        messagebox.showerror("Database Error", f"Failed to fetch books: {e}", parent=admin_books_win)
    finally:
        cursor.close()
        db.close()

def add_book(parent):
    def on_submit(title, author, quantity, category):
        db = get_db_connection()
        if not db:
            messagebox.showerror("Database Error", "Cannot connect to DB.", parent=parent)
            return
        cursor = db.cursor()
        try:
            cursor.execute(
                "INSERT INTO books (title, author, quantity, category) VALUES (%s, %s, %s, %s)",
                (title, author, quantity, category)
            )
            db.commit()
            messagebox.showinfo("Success", "Book added successfully!", parent=parent)
        except Error as e:
            messagebox.showerror("Database Error", f"Failed to add book: {e}", parent=parent)
        finally:
            cursor.close()
            db.close()
    AddOrUpdateBookDialog(parent, on_submit, title="Add Book")

def update_book(parent):
    book_id = simpledialog.askinteger("Update Book", "Enter the Book ID to update:", parent=parent)
    if not book_id:
        return

    db = get_db_connection()
    if not db:
        messagebox.showerror("Database Error", "Cannot connect to DB.", parent=parent)
        return
    cursor = db.cursor()
    try:
        cursor.execute("SELECT title, author, quantity, category FROM books WHERE id = %s", (book_id,))
        book = cursor.fetchone()
        if not book:
            messagebox.showerror("Error", "Book not found.", parent=parent)
            cursor.close()
            db.close()
            return

        book_data = {'title': book[0], 'author': book[1], 'quantity': book[2], 'category': book[3]}
        def on_submit(title, author, quantity, category):
            cursor2 = db.cursor()
            try:
                cursor2.execute(
                    "UPDATE books SET title=%s, author=%s, quantity=%s, category=%s WHERE id=%s",
                    (title, author, quantity, category, book_id)
                )
                db.commit()
                messagebox.showinfo("Success", f"Book with ID {book_id} updated successfully!", parent=parent)
            except Error as e:
                messagebox.showerror("Database Error", f"Failed to update book: {e}", parent=parent)
            finally:
                cursor2.close()
                db.close()
        AddOrUpdateBookDialog(parent, on_submit, title="Update Book", book_data=book_data)
    except Error as e:
        messagebox.showerror("Database Error", f"Failed to fetch book details: {e}", parent=parent)
        cursor.close()
        db.close()

def delete_book(parent):
    book_id = simpledialog.askinteger("Delete Book", "Enter the Book ID to delete:", parent=parent)
    if not book_id:
        return
    if not messagebox.askyesno("Confirm Delete", f"Are you sure you want to delete book ID {book_id}?", parent=parent):
        return
    db = get_db_connection()
    if not db:
        messagebox.showerror("Database Error", "Cannot connect to DB.", parent=parent)
        return
    cursor = db.cursor()
    try:
        cursor.execute("DELETE FROM books WHERE id = %s", (book_id,))
        if cursor.rowcount == 0:
            messagebox.showwarning("Warning", "No book found with this ID.", parent=parent)
        else:
            db.commit()
            messagebox.showinfo("Success", f"Book with ID {book_id} deleted successfully!", parent=parent)
    except Error as e:
        messagebox.showerror("Database Error", f"Failed to delete book: {e}", parent=parent)
    finally:
        cursor.close()
        db.close()

def issue_book(parent):
    def on_submit(book_id, username):
        db = get_db_connection()
        if not db:
            messagebox.showerror("Database Error", "Cannot connect to DB.", parent=parent)
            return
        cursor = db.cursor()
        try:
            cursor.execute("SELECT id FROM users WHERE username = %s AND role = 'student'", (username,))
            user = cursor.fetchone()
            if not user:
                messagebox.showerror("Error", "Student not found. Please enter a valid registered student username.", parent=parent)
                return

            cursor.execute("SELECT quantity FROM books WHERE id = %s", (book_id,))
            result = cursor.fetchone()
            if result and result[0] > 0:
                issue_date = datetime.now().date()
                due_date = issue_date + timedelta(days=14)

                cursor.execute(
                    "INSERT INTO issued_books (book_id, student_username, issue_date, due_date) VALUES (%s, %s, %s, %s)",
                    (book_id, username, issue_date, due_date)
                )
                cursor.execute("UPDATE books SET quantity = quantity - 1 WHERE id = %s", (book_id,))
                db.commit()
                messagebox.showinfo("Success", "Book issued successfully!", parent=parent)
            else:
                messagebox.showerror("Error", "Book not available.", parent=parent)
        except Error as e:
            messagebox.showerror("Database Error", f"Failed to issue book: {e}", parent=parent)
        finally:
            cursor.close()
            db.close()
    IssueBookDialog(parent, on_submit)

def return_book(parent):
    def on_submit(issue_id):
        db = get_db_connection()
        if not db:
            messagebox.showerror("Database Error", "Cannot connect to DB.", parent=parent)
            return
        cursor = db.cursor()
        try:
            cursor.execute("SELECT due_date FROM issued_books WHERE id = %s AND return_date IS NULL", (issue_id,))
            result = cursor.fetchone()
            if result:
                due_date = result[0]
                return_date = datetime.now().date()
                fine = max(0, (return_date - due_date).days)
                cursor.execute("UPDATE issued_books SET return_date = %s, fine = %s WHERE id = %s",
                               (return_date, fine, issue_id))
                cursor.execute(
                    "UPDATE books SET quantity = quantity + 1 WHERE id = (SELECT book_id FROM issued_books WHERE id = %s)",
                    (issue_id,))
                db.commit()
                messagebox.showinfo("Success", f"Book returned successfully! Fine: ${fine:.2f}", parent=parent)
            else:
                messagebox.showerror("Error", "Invalid issue ID or book already returned.", parent=parent)
        except Error as e:
            messagebox.showerror("Database Error", f"Failed to return book: {e}", parent=parent)
        finally:
            cursor.close()
            db.close()
    ReturnBookDialog(parent, on_submit)

def view_issued_books_admin(parent):
    win = tk.Toplevel(parent)
    win.title("Issued Books")
    win.geometry("900x600")
    win.configure(bg="#ecf0f1")

    columns = ("ID", "Title", "Student Username", "Issue Date", "Due Date", "Return Date", "Fine")
    tree = ttk.Treeview(win, columns=columns, show="headings")
    for col in columns:
        tree.heading(col, text=col)
        tree.column(col, anchor="center")
    tree.pack(fill="both", expand=True, padx=20, pady=20)

    scrollbar = ttk.Scrollbar(win, orient="vertical", command=tree.yview)
    tree.configure(yscroll=scrollbar.set)
    scrollbar.place(relx=0.97, rely=0.07, relheight=0.9)

    db = get_db_connection()
    if not db:
        return
    cursor = db.cursor()
    try:
        cursor.execute("""SELECT ib.id, b.title, ib.student_username, ib.issue_date, ib.due_date, ib.return_date, ib.fine
                          FROM issued_books ib JOIN books b ON ib.book_id = b.id""")
        rows = cursor.fetchall()
        for row in rows:
            tree.insert("", "end", values=row)
    except Error as e:
        messagebox.showerror("Database Error", f"Failed to fetch issued books: {e}", parent=win)
    finally:
        cursor.close()
        db.close()

# ===================== STUDENT DASHBOARD and functions =====================
def view_books_student(parent):
    win = tk.Toplevel(parent)
    win.title("Available Books")
    win.geometry("900x600")
    win.configure(bg="#ecf0f1")

    columns = ("ID", "Title", "Author", "Quantity", "Category")
    tree = ttk.Treeview(win, columns=columns, show="headings")
    for col in columns:
        tree.heading(col, text=col)
        tree.column(col, anchor="center")
    tree.pack(fill="both", expand=True, padx=20, pady=20)

    scrollbar = ttk.Scrollbar(win, orient="vertical", command=tree.yview)
    tree.configure(yscroll=scrollbar.set)
    scrollbar.place(relx=0.97, rely=0.07, relheight=0.9)

    db = get_db_connection()
    if not db:
        return
    cursor = db.cursor()
    try:
        cursor.execute("SELECT id, title, author, quantity, category FROM books WHERE quantity > 0")
        rows = cursor.fetchall()
        for row in rows:
            tree.insert("", "end", values=row)
    except Error as e:
        messagebox.showerror("Database Error", f"Failed to fetch available books: {e}", parent=win)
    finally:
        cursor.close()
        db.close()

def search_books_student(parent):
    query = simpledialog.askstring("Search Books", "Enter title, author, or category:", parent=parent)
    if not query or query.strip() == "":
        return
    db = get_db_connection()
    if not db:
        return
    cursor = db.cursor()
    try:
        cursor.execute("""SELECT id, title, author, quantity, category FROM books
                          WHERE title LIKE %s OR author LIKE %s OR category LIKE %s""",
                       (f'%{query}%', f'%{query}%', f'%{query}%'))
        rows = cursor.fetchall()
        if rows:
            win = tk.Toplevel(parent)
            win.title("Search Results")
            win.geometry("900x600")
            win.configure(bg="#ecf0f1")

            columns = ("ID", "Title", "Author", "Quantity", "Category")
            tree = ttk.Treeview(win, columns=columns, show="headings")
            for col in columns:
                tree.heading(col, text=col)
                tree.column(col, anchor="center")
            tree.pack(fill="both", expand=True, padx=20, pady=20)

            scrollbar = ttk.Scrollbar(win, orient="vertical", command=tree.yview)
            tree.configure(yscroll=scrollbar.set)
            scrollbar.place(relx=0.97, rely=0.07, relheight=0.9)

            for row in rows:
                tree.insert("", "end", values=row)
        else:
            messagebox.showinfo("No Results", "No books found matching your search.", parent=parent)
    except Error as e:
        messagebox.showerror("Database Error", f"Failed to search books: {e}", parent=parent)
    finally:
        cursor.close()
        db.close()

def reserve_book_student(parent):
    book_id = simpledialog.askinteger("Reserve Book", "Enter the Book ID to reserve:", parent=parent)
    if not book_id:
        return
    student_username = simpledialog.askstring("Reserve Book", "Enter your Student Username:", parent=parent)
    if not student_username:
        messagebox.showerror("Error", "Student Username is required.", parent=parent)
        return

    db = get_db_connection()
    if not db:
        return
    cursor = db.cursor()
    try:
        cursor.execute("SELECT quantity FROM books WHERE id = %s", (book_id,))
        result = cursor.fetchone()
        if result and result[0] == 0:
            cursor.execute("SELECT * FROM reserved_books WHERE book_id = %s AND student_username = %s",
                           (book_id, student_username))
            existing_reservation = cursor.fetchone()
            if existing_reservation:
                messagebox.showinfo("Info", "You have already reserved this book.", parent=parent)
                return

            cursor.execute("INSERT INTO reserved_books (book_id, student_username) VALUES (%s, %s)",
                           (book_id, student_username))
            db.commit()
            messagebox.showinfo("Reservation Success", "Book reserved successfully!", parent=parent)
        else:
            messagebox.showerror("Error", "Book is available, no need to reserve.", parent=parent)
    except Error as e:
        messagebox.showerror("Database Error", f"Failed to reserve book: {e}", parent=parent)
    finally:
        cursor.close()
        db.close()

def view_fine_student(username, parent):
    db = get_db_connection()
    if not db:
        return
    cursor = db.cursor()
    try:
        cursor.execute("SELECT SUM(fine) FROM issued_books WHERE student_username = %s", (username,))
        result = cursor.fetchone()
        fine_amount = result[0] if result[0] else 0
        messagebox.showinfo("Fine", f"Your total fine till now: ${fine_amount:.2f}", parent=parent)
    except Error as e:
        messagebox.showerror("Database Error", f"Failed to fetch fines: {e}", parent=parent)
    finally:
        cursor.close()
        db.close()

def view_issued_books_student(username, parent):
    win = tk.Toplevel(parent)
    win.title("Issued Books")
    win.geometry("900x600")
    win.configure(bg="#ecf0f1")

    columns = ("ID", "Title", "Issue Date", "Due Date", "Return Date", "Fine")
    tree = ttk.Treeview(win, columns=columns, show="headings")
    for col in columns:
        tree.heading(col, text=col)
        tree.column(col, anchor="center")
    tree.pack(fill="both", expand=True, padx=20, pady=20)

    scrollbar = ttk.Scrollbar(win, orient="vertical", command=tree.yview)
    tree.configure(yscroll=scrollbar.set)
    scrollbar.place(relx=0.97, rely=0.07, relheight=0.9)

    db = get_db_connection()
    if not db:
        return
    cursor = db.cursor()
    try:
        cursor.execute("""SELECT ib.id, b.title, ib.issue_date, ib.due_date, ib.return_date, ib.fine
                          FROM issued_books ib
                          JOIN books b ON ib.book_id = b.id
                          WHERE ib.student_username = %s""", (username,))
        rows = cursor.fetchall()
        for row in rows:
            tree.insert("", "end", values=row)
    except Error as e:
        messagebox.showerror("Database Error", f"Failed to fetch issued books: {e}", parent=win)
    finally:
        cursor.close()
        db.close()


# ===================== REGISTRATION =====================
def register():
    reg_win = tk.Toplevel(root)
    reg_win.title("Register")
    reg_win.geometry("400x450")
    reg_win.configure(bg="#34495e")
    reg_win.resizable(False, False)
    reg_win.grab_set()
    reg_win.transient(root)

    tk.Label(reg_win, text="Register", font=("Helvetica", 16), fg="white", bg="#34495e").pack(pady=10)
    frame = tk.Frame(reg_win, bg="#34495e")
    frame.pack(padx=20, pady=10)

    tk.Label(frame, text="Username:", fg="white", bg="#34495e").grid(row=0, column=0, sticky="w", pady=5)
    reg_username_entry = tk.Entry(frame, width=30)
    reg_username_entry.grid(row=0, column=1)

    tk.Label(frame, text="Password:", fg="white", bg="#34495e").grid(row=1, column=0, sticky="w", pady=5)
    reg_password_entry = tk.Entry(frame, show="*", width=30)
    reg_password_entry.grid(row=1, column=1)

    tk.Label(frame, text="Confirm Password:", fg="white", bg="#34495e").grid(row=2, column=0, sticky="w", pady=5)
    reg_confirm_password_entry = tk.Entry(frame, show="*", width=30)
    reg_confirm_password_entry.grid(row=2, column=1)

    tk.Label(frame, text="Email:", fg="white", bg="#34495e").grid(row=3, column=0, sticky="w", pady=5)
    reg_email_entry = tk.Entry(frame, width=30)
    reg_email_entry.grid(row=3, column=1)

    tk.Label(frame, text="Role:", fg="white", bg="#34495e").grid(row=4, column=0, sticky="w", pady=5)
    reg_role_combo = ttk.Combobox(frame, values=["admin", "student"], state="readonly", width=28)
    reg_role_combo.grid(row=4, column=1)

    def submit_registration():
        username = reg_username_entry.get().strip()
        password = reg_password_entry.get().strip()
        confirm_password = reg_confirm_password_entry.get().strip()
        email = reg_email_entry.get().strip()
        role = reg_role_combo.get().strip()
        if not all([username, password, confirm_password, email, role]):
            messagebox.showerror("Error", "All fields are required.", parent=reg_win)
            return
        if password != confirm_password:
            messagebox.showerror("Error", "Passwords do not match.", parent=reg_win)
            return
        db = get_db_connection()
        if not db:
            return
        cursor = db.cursor()
        try:
            cursor.execute("INSERT INTO users (username, password, email, role) VALUES (%s, %s, %s, %s)",
                           (username, password, email, role))
            db.commit()
            messagebox.showinfo("Success", "Registration successful!", parent=reg_win)
            reg_win.destroy()
        except mysql.connector.errors.IntegrityError:
            messagebox.showerror("Error", "Username already exists.", parent=reg_win)
        except Error as e:
            messagebox.showerror("Database Error", f"Failed to register: {e}", parent=reg_win)
        finally:
            cursor.close()
            db.close()
    tk.Button(reg_win, text="Submit", command=submit_registration, bg="#2ecc71", fg="white", font=("Helvetica", 12)).pack(pady=20)

# ===================== LOGIN =====================
def login():
    login_win = tk.Toplevel(root)
    login_win.title("Login")
    login_win.geometry("400x300")
    login_win.configure(bg="#34495e")
    login_win.resizable(False, False)
    login_win.grab_set()
    login_win.transient(root)
    tk.Label(login_win, text="Login", font=("Helvetica", 16, "bold"), fg="white", bg="#34495e").pack(pady=20)
    frame = tk.Frame(login_win, bg="#34495e")
    frame.pack(padx=20, pady=10)
    tk.Label(frame, text="Username:", fg="white", bg="#34495e").grid(row=0, column=0, sticky="w", pady=5)
    username_entry = tk.Entry(frame, width=30)
    username_entry.grid(row=0, column=1)
    tk.Label(frame, text="Password:", fg="white", bg="#34495e").grid(row=1, column=0, sticky="w", pady=5)
    password_entry = tk.Entry(frame, show="*", width=30)
    password_entry.grid(row=1, column=1)
    def submit_login():
        username = username_entry.get().strip()
        password = password_entry.get().strip()
        if not username or not password:
            messagebox.showerror("Error", "Username and Password are required.", parent=login_win)
            return
        db = get_db_connection()
        if not db:
            return
        cursor = db.cursor()
        try:
            cursor.execute("SELECT id, username, role FROM users WHERE username = %s AND password = %s", (username, password))
            user = cursor.fetchone()
            if user:
                messagebox.showinfo("Login Successful", f"Welcome, {user[1]}!", parent=login_win)
                login_win.destroy()
                if user[2] == "admin":
                    admin_dashboard(root)
                else:
                    student_dashboard(user[1], root)
            else:
                messagebox.showerror("Error", "Invalid username or password.", parent=login_win)
        except Error as e:
            messagebox.showerror("Database Error", f"Failed to login: {e}", parent=login_win)
        finally:
            cursor.close()
            db.close()
    tk.Button(login_win, text="Login", command=submit_login, bg="#2980b9", fg="white", font=("Helvetica", 12, "bold")).pack(pady=20)

# ===================== ADMIN DASHBOARD =====================
def admin_dashboard(parent):
    win = tk.Toplevel(parent)
    win.title("Admin Dashboard")
    win.geometry("650x450")
    win.configure(bg="#ecf0f1")
    tk.Label(win, text="Admin Dashboard", font=("Helvetica", 20, "bold"), bg="#ecf0f1").pack(pady=15)
    book_frame = tk.LabelFrame(win, text="Book Management", font=("Helvetica", 14, "bold"), padx=15, pady=15)
    book_frame.pack(fill="x", padx=40, pady=10)
    btn_opts = {
        "font": ("Helvetica", 12),
        "width": 15,
        "height": 2,
        "bg": "#2980b9",
        "fg": "white",
        "relief": "raised",
        "activebackground": "#3498db",
        "bd": 3,
    }
    tk.Button(book_frame, text="View Books", command=lambda: view_books_admin(win), **btn_opts).grid(row=0, column=0, padx=10, pady=5)
    tk.Button(book_frame, text="Add Book", command=lambda: add_book(win), **btn_opts).grid(row=0, column=1, padx=10, pady=5)
    tk.Button(book_frame, text="Update Book", command=lambda: update_book(win), **btn_opts).grid(row=0, column=2, padx=10, pady=5)
    tk.Button(book_frame, text="Delete Book", command=lambda: delete_book(win), **btn_opts).grid(row=1, column=0, padx=10, pady=5)
    issue_frame = tk.LabelFrame(win, text="Issue / Return Books", font=("Helvetica", 14, "bold"), padx=15, pady=15)
    issue_frame.pack(fill="x", padx=40, pady=10)
    tk.Button(issue_frame, text="Issue Book", command=lambda: issue_book(win), **btn_opts).grid(row=0, column=0, padx=10, pady=5)
    tk.Button(issue_frame, text="Return Book", command=lambda: return_book(win), **btn_opts).grid(row=0, column=1, padx=10, pady=5)
    tk.Button(issue_frame, text="View Issued Books", command=lambda: view_issued_books_admin(win), **btn_opts).grid(row=1, column=0, padx=10, pady=5)
    bottom_frame = tk.Frame(win, bg="#ecf0f1")
    bottom_frame.pack(fill="x", pady=20)
    tk.Button(bottom_frame, text="Logout", command=win.destroy, font=("Helvetica", 12), bg="#f1c40f", fg="black", width=15).pack(side="left", padx=50)
    tk.Button(bottom_frame, text="Exit", command=root.quit, font=("Helvetica", 12), bg="#e74c3c", fg="white", width=15).pack(side="right", padx=50)

# ===================== STUDENT DASHBOARD =====================
def student_dashboard(username, parent):
    win = tk.Toplevel(parent)
    win.title("Student Dashboard")
    win.geometry("600x450")
    win.configure(bg="#ecf0f1")
    tk.Label(win, text=f"Welcome, {username}", font=("Helvetica", 20, "bold"), bg="#ecf0f1").pack(pady=20)
    btn_opts = {
        "font": ("Helvetica", 12),
        "width": 25,
        "height": 2,
        "bg": "#27ae60",
        "fg": "white",
        "relief": "raised",
        "activebackground": "#2ecc71",
        "bd": 3,
    }
    tk.Button(win, text="View Available Books", command=lambda: view_books_student(win), **btn_opts).pack(pady=8)
    tk.Button(win, text="Search Books", command=lambda: search_books_student(win), **btn_opts).pack(pady=8)
    tk.Button(win, text="View Issued Books", command=lambda: view_issued_books_student(username, win), **btn_opts).pack(pady=8)
    tk.Button(win, text="View Fine", command=lambda: view_fine_student(username, win), **btn_opts).pack(pady=8)
    tk.Button(win, text="Reserve Book", command=lambda: reserve_book_student(win), **btn_opts).pack(pady=8)
    tk.Button(win, text="Logout", command=win.destroy, font=("Helvetica", 12), bg="#f1c40f", fg="black", width=20, relief="raised", bd=3).pack(pady=15)
    tk.Button(win, text="Exit", command=root.quit, font=("Helvetica", 12), bg="#e74c3c", fg="white", width=20, relief="raised", bd=3).pack(pady=5)

# ===================== MAIN WINDOW =====================
root = tk.Tk()
root.title("Library Management System")
root.geometry("600x450")
root.configure(bg="#34495e")
tk.Label(root, text="Library Management System", font=("Helvetica", 24, "bold"), fg="white", bg="#34495e").pack(pady=40)
tk.Button(root, text="Login", command=login, font=("Helvetica", 14, "bold"), bg="#2980b9", fg="white", width=20).pack(pady=15)
tk.Button(root, text="Register", command=register, font=("Helvetica", 14, "bold"), bg="#27ae60", fg="white", width=20).pack(pady=15)
tk.Button(root, text="Exit", command=root.quit, font=("Helvetica", 14, "bold"), bg="#c0392b", fg="white", width=20).pack(pady=15)
root.mainloop()   can you give all this python code in java