import csv
import tkinter as tk
from tkinter import ttk, messagebox, filedialog

# ==========================================
# 🟢 BLACK & GREEN PALETTE ONLY
# ==========================================
COLOR_BG_DARKEST    = "#0A0D0B"  # Absolute Deep Black
COLOR_SIDEBAR_BG    = "#111713"  # Carbon Black
COLOR_CARD_BG       = "#161F19"  # Dark Slate Green/Black
COLOR_CARD_BORDER   = "#1F2E24"  # Subtle Emerald Border
COLOR_ACCENT_GREEN  = "#00FF66"  # Vivid Neon / Terminal Green
COLOR_MUTED_GREEN   = "#10B981"  # Emerald Green
COLOR_DARK_GREEN    = "#064E3B"  # Deep Forest Green
COLOR_TEXT_WHITE    = "#E5E7EB"  # Bright Off-white
COLOR_TEXT_MUTED    = "#6EE7B7"  # Soft Mint Gray
COLOR_INPUT_BG      = "#0E1410"  # Input Box Dark Surface

# ==========================================
# 📦 IN-MEMORY STATE (Functional)
# ==========================================
books_db = [
    {"id": 1, "title": "Clean Code", "author": "Robert C. Martin", "year": "2008", "isbn": "9780132350884", "status": "Available"},
    {"id": 2, "title": "The Pragmatic Programmer", "author": "Andrew Hunt", "year": "1999", "isbn": "9780201616224", "status": "Borrowed"},
    {"id": 3, "title": "Design Patterns", "author": "Erich Gamma", "year": "1994", "isbn": "9780201633610", "status": "Available"},
    {"id": 4, "title": "Introduction to Algorithms", "author": "Thomas H. Cormen", "year": "2009", "isbn": "9780262033848", "status": "Available"},
    {"id": 5, "title": "Refactoring", "author": "Martin Fowler", "year": "2018", "isbn": "9780134757599", "status": "Borrowed"},
]
next_id = 6
active_filter = "ALL"  # "ALL", "Available", "Borrowed"


# ==========================================
# ⚙️ HELPER FUNCTIONS
# ==========================================
def get_selected_id(tree):
    selected = tree.selection()
    if not selected:
        return None
    val = tree.item(selected[0], "values")[0]
    return int(val.replace("#", ""))


def update_dashboard_stats(stat_vars):
    total = len(books_db)
    borrowed = sum(1 for b in books_db if b["status"] == "Borrowed")
    available = total - borrowed

    stat_vars["total"].set(str(total))
    stat_vars["available"].set(str(available))
    stat_vars["borrowed"].set(str(borrowed))


def refresh_table(tree, stat_vars, search_box=None):
    for row in tree.get_children():
        tree.delete(row)

    q = ""
    if search_box:
        raw_val = search_box.get()
        if raw_val != "Search catalog...":
            q = raw_val.strip().lower()

    for b in books_db:
        # Status Filter Check
        if active_filter != "ALL" and b["status"] != active_filter:
            continue

        # Search Query Check
        if (q in b["title"].lower() or 
            q in b["author"].lower() or 
            q in b["isbn"].lower() or 
            q in b["status"].lower()):
            
            tag = "available" if b["status"] == "Available" else "borrowed"
            tree.insert("", "end", values=(
                f"#{b['id']}",
                b["title"],
                b["author"],
                b["year"],
                b["isbn"],
                b["status"]
            ), tags=(tag,))

    update_dashboard_stats(stat_vars)


# ==========================================
# 🟢 ACTION HANDLERS (Add, Edit, Delete, etc.)
# ==========================================
def handle_filter_click(filter_type, tree, stat_vars, search_box):
    global active_filter
    active_filter = filter_type
    refresh_table(tree, stat_vars, search_box)


def open_book_modal(parent, title_text, initial_data, on_save_callback):
    modal = tk.Toplevel(parent)
    modal.title(title_text)
    modal.geometry("400x380")
    modal.configure(bg=COLOR_CARD_BG)
    modal.resizable(False, False)
    modal.transient(parent)
    modal.grab_set()

    modal.update_idletasks()
    x = parent.winfo_x() + (parent.winfo_width() // 2) - 200
    y = parent.winfo_y() + (parent.winfo_height() // 2) - 190
    modal.geometry(f"+{x}+{y}")

    tk.Label(modal, text=title_text, font=("Consolas", 13, "bold"),
             bg=COLOR_CARD_BG, fg=COLOR_ACCENT_GREEN).pack(anchor="w", padx=25, pady=(20, 15))

    fields = {}
    keys = [("Title", "title"), ("Author", "author"), ("Year", "year"), ("ISBN", "isbn")]

    for label_name, key in keys:
        frame = tk.Frame(modal, bg=COLOR_CARD_BG)
        frame.pack(fill="x", padx=25, pady=4)
        tk.Label(frame, text=label_name, font=("Consolas", 9), fg=COLOR_TEXT_MUTED,
                 bg=COLOR_CARD_BG, width=8, anchor="w").pack(side="left")
        entry = tk.Entry(frame, font=("Consolas", 10), bg=COLOR_INPUT_BG, fg=COLOR_TEXT_WHITE,
                         insertbackground=COLOR_ACCENT_GREEN, relief="flat",
                         highlightbackground=COLOR_CARD_BORDER, highlightthickness=1)
        entry.pack(side="right", fill="x", expand=True, ipady=4)
        if initial_data and key in initial_data:
            entry.insert(0, initial_data[key])
        fields[key] = entry

    def save_action():
        data = {k: v.get().strip() for k, v in fields.items()}
        if not data["title"] or not data["author"]:
            messagebox.showwarning("Validation Error", "Title and Author are required!", parent=modal)
            return
        if on_save_callback(data, modal):
            modal.destroy()

    btn_frame = tk.Frame(modal, bg=COLOR_CARD_BG)
    btn_frame.pack(fill="x", padx=25, pady=(25, 10))

    cancel_btn = tk.Button(btn_frame, text="Cancel", font=("Consolas", 9), relief="flat",
                           bg=COLOR_INPUT_BG, fg=COLOR_TEXT_MUTED, padx=14, pady=5, cursor="hand2", command=modal.destroy)
    cancel_btn.pack(side="right", padx=(8, 0))

    save_btn = tk.Button(btn_frame, text="Save Record", font=("Consolas", 9, "bold"), relief="flat",
                         bg=COLOR_ACCENT_GREEN, fg=COLOR_BG_DARKEST, activebackground=COLOR_MUTED_GREEN,
                         padx=16, pady=5, cursor="hand2", command=save_action)
    save_btn.pack(side="right")


def handle_add(parent, tree, stat_vars, search_box):
    global next_id
    def save_cb(data, modal):
        global next_id
        if data["isbn"] and any(b["isbn"] == data["isbn"] for b in books_db):
            messagebox.showerror("Error", "ISBN already exists!", parent=modal)
            return False
        
        books_db.append({
            "id": next_id,
            "title": data["title"],
            "author": data["author"],
            "year": data["year"] or "N/A",
            "isbn": data["isbn"] or "N/A",
            "status": "Available"
        })
        next_id += 1
        refresh_table(tree, stat_vars, search_box)
        return True

    open_book_modal(parent, "[+] Add New Book", None, save_cb)


def handle_edit(parent, tree, stat_vars, search_box):
    b_id = get_selected_id(tree)
    if b_id is None:
        messagebox.showinfo("Select", "Please select a book from the table first.")
        return

    book = next(b for b in books_db if b["id"] == b_id)

    def save_cb(data, modal):
        if data["isbn"] and any(b["isbn"] == data["isbn"] and b["id"] != b_id for b in books_db):
            messagebox.showerror("Error", "Another book has this ISBN!", parent=modal)
            return False

        book["title"] = data["title"]
        book["author"] = data["author"]
        book["year"] = data["year"] or "N/A"
        book["isbn"] = data["isbn"] or "N/A"
        refresh_table(tree, stat_vars, search_box)
        return True

    open_book_modal(parent, f"[*] Edit Book #{b_id}", book, save_cb)


def handle_delete(tree, stat_vars, search_box):
    b_id = get_selected_id(tree)
    if b_id is None:
        messagebox.showinfo("Select", "Please select a book from the table first.")
        return

    if messagebox.askyesno("Confirm Delete", f"Delete book #{b_id} from database?"):
        global books_db
        books_db = [b for b in books_db if b["id"] != b_id]
        refresh_table(tree, stat_vars, search_box)


def handle_toggle_status(tree, stat_vars, search_box):
    b_id = get_selected_id(tree)
    if b_id is None:
        messagebox.showinfo("Select", "Please select a book first.")
        return

    book = next(b for b in books_db if b["id"] == b_id)
    book["status"] = "Borrowed" if book["status"] == "Available" else "Available"
    refresh_table(tree, stat_vars, search_box)


def handle_export_csv():
    file_path = filedialog.asksaveasfilename(defaultextension=".csv",
                                             filetypes=[("CSV Files", "*.csv")],
                                             initialfile="library_catalog.csv")
    if file_path:
        with open(file_path, mode="w", newline="", encoding="utf-8") as f:
            writer = csv.DictWriter(f, fieldnames=["id", "title", "author", "year", "isbn", "status"])
            writer.writeheader()
            writer.writerows(books_db)
        messagebox.showinfo("Export Successful", f"Saved {len(books_db)} books to CSV!")


# ==========================================
# 📑 NAVIGATION TABS SWITCHER
# ==========================================
def switch_view(view_name, views, nav_buttons):
    for name, frame in views.items():
        if name == view_name:
            frame.pack(fill="both", expand=True)
        else:
            frame.pack_forget()

    for name, btn in nav_buttons.items():
        if name == view_name:
            btn.config(bg=COLOR_CARD_BG, fg=COLOR_ACCENT_GREEN)
        else:
            btn.config(bg=COLOR_SIDEBAR_BG, fg=COLOR_TEXT_MUTED)


# ==========================================
# 🖥️ APPLICATION UI BUILDER
# ==========================================
def create_app():
    root = tk.Tk()
    root.title("Library Terminal Manager")
    root.geometry("1100x650")
    root.minsize(980, 580)
    root.configure(bg=COLOR_BG_DARKEST)

    stat_vars = {
        "total": tk.StringVar(value="0"),
        "available": tk.StringVar(value="0"),
        "borrowed": tk.StringVar(value="0"),
    }

    # 1. SIDEBAR (Pure Black / Forest Accents)
    sidebar = tk.Frame(root, bg=COLOR_SIDEBAR_BG, width=220)
    sidebar.pack(side="left", fill="y")
    sidebar.pack_propagate(False)

    brand = tk.Frame(sidebar, bg=COLOR_SIDEBAR_BG)
    brand.pack(fill="x", padx=20, pady=(25, 30))
    tk.Label(brand, text=">_ LIBRARY.SYS", font=("Consolas", 12, "bold"), fg=COLOR_ACCENT_GREEN, bg=COLOR_SIDEBAR_BG).pack(anchor="w")
    tk.Label(brand, text="Catalog & Circulation", font=("Consolas", 8), fg=COLOR_TEXT_MUTED, bg=COLOR_SIDEBAR_BG).pack(anchor="w")

    views = {}
    nav_buttons = {}

    main_container = tk.Frame(root, bg=COLOR_BG_DARKEST)
    main_container.pack(side="right", fill="both", expand=True, padx=20, pady=20)

    # 2. DEFINING SUB-PAGES (For all sidebar buttons to work)
    # Page A: Books Directory (Main)
    books_view = tk.Frame(main_container, bg=COLOR_BG_DARKEST)
    views["Books"] = books_view

    # Page B: Dashboard Stats View
    dash_view = tk.Frame(main_container, bg=COLOR_BG_DARKEST)
    views["Dashboard"] = dash_view
    tk.Label(dash_view, text="DASHBOARD OVERVIEW", font=("Consolas", 16, "bold"), fg=COLOR_ACCENT_GREEN, bg=COLOR_BG_DARKEST).pack(anchor="w", pady=(10, 20))
    tk.Label(dash_view, text="Real-time analytics and statistics will show here.", font=("Consolas", 10), fg=COLOR_TEXT_MUTED, bg=COLOR_BG_DARKEST).pack(anchor="w")

    # Page C: Borrowing Log View
    borrow_view = tk.Frame(main_container, bg=COLOR_BG_DARKEST)
    views["Borrowing"] = borrow_view
    tk.Label(borrow_view, text="BORROWING & RETURNS LOG", font=("Consolas", 16, "bold"), fg=COLOR_ACCENT_GREEN, bg=COLOR_BG_DARKEST).pack(anchor="w", pady=(10, 20))
    tk.Label(borrow_view, text="Click 'Toggle Status' in the Books table to lend or return copies.", font=("Consolas", 10), fg=COLOR_TEXT_MUTED, bg=COLOR_BG_DARKEST).pack(anchor="w")

    # Page D: Settings View
    settings_view = tk.Frame(main_container, bg=COLOR_BG_DARKEST)
    views["Settings"] = settings_view
    tk.Label(settings_view, text="SYSTEM SETTINGS", font=("Consolas", 16, "bold"), fg=COLOR_ACCENT_GREEN, bg=COLOR_BG_DARKEST).pack(anchor="w", pady=(10, 20))
    tk.Button(settings_view, text="Export Library Database (CSV)", font=("Consolas", 10, "bold"),
              bg=COLOR_CARD_BG, fg=COLOR_ACCENT_GREEN, activebackground=COLOR_MUTED_GREEN, relief="flat",
              padx=15, pady=8, cursor="hand2", command=handle_export_csv).pack(anchor="w", pady=10)

    # Create Navigation Buttons
    nav_list = [("📊  Dashboard", "Dashboard"), ("📚  Books", "Books"), ("🔄  Borrowing", "Borrowing"), ("⚙️  Settings", "Settings")]
    for text, key in nav_list:
        btn = tk.Button(sidebar, text=text, font=("Consolas", 10, "bold"),
                        bg=COLOR_SIDEBAR_BG, fg=COLOR_TEXT_MUTED, activebackground=COLOR_CARD_BG, activeforeground=COLOR_ACCENT_GREEN,
                        anchor="w", padx=16, pady=10, relief="flat", cursor="hand2")
        btn.config(command=lambda k=key: switch_view(k, views, nav_buttons))
        btn.pack(fill="x", padx=10, pady=3)
        nav_buttons[key] = btn

    # Bottom badge
    tk.Label(sidebar, text="● SYSTEM ONLINE\nGreen & Black v2.0", font=("Consolas", 8),
             fg=COLOR_MUTED_GREEN, bg=COLOR_SIDEBAR_BG, justify="left").pack(side="bottom", anchor="w", padx=20, pady=20)

    # ==========================================
    # 📚 BUILDING MAIN BOOKS VIEW
    # ==========================================
    # Header
    header = tk.Frame(books_view, bg=COLOR_BG_DARKEST)
    header.pack(fill="x", pady=(0, 15))
    tk.Label(header, text="CATALOG INVENTORY", font=("Consolas", 16, "bold"), fg=COLOR_ACCENT_GREEN, bg=COLOR_BG_DARKEST).pack(anchor="w")
    tk.Label(header, text="Search, update, toggle and organize records", font=("Consolas", 9), fg=COLOR_TEXT_MUTED, bg=COLOR_BG_DARKEST).pack(anchor="w")

    # 3 Interactive Dashboard Cards (Clicking them filters the table!)
    stats_bar = tk.Frame(books_view, bg=COLOR_BG_DARKEST)
    stats_bar.pack(fill="x", pady=(0, 15))

    card_defs = [
        ("TOTAL BOOKS (Click to show all)", stat_vars["total"], COLOR_TEXT_WHITE, "ALL"),
        ("AVAILABLE (Click to filter)", stat_vars["available"], COLOR_ACCENT_GREEN, "Available"),
        ("BORROWED (Click to filter)", stat_vars["borrowed"], COLOR_TEXT_MUTED, "Borrowed"),
    ]

    for title, var, color, f_type in card_defs:
        card = tk.Button(stats_bar, bg=COLOR_CARD_BG, relief="flat", highlightbackground=COLOR_CARD_BORDER,
                         highlightthickness=1, cursor="hand2", activebackground=COLOR_DARK_GREEN)
        card.pack(side="left", fill="x", expand=True, padx=(0, 10) if f_type != "Borrowed" else 0)

        inner = tk.Frame(card, bg=COLOR_CARD_BG)
        inner.pack(fill="both", padx=12, pady=8)
        tk.Label(inner, text=title, font=("Consolas", 8, "bold"), fg=COLOR_TEXT_MUTED, bg=COLOR_CARD_BG).pack(anchor="w")
        tk.Label(inner, textvariable=var, font=("Consolas", 18, "bold"), fg=color, bg=COLOR_CARD_BG).pack(anchor="w")

    # Action Bar (Search + Buttons)
    action_bar = tk.Frame(books_view, bg=COLOR_BG_DARKEST)
    action_bar.pack(fill="x", pady=(0, 12))

    search_box = tk.Entry(action_bar, font=("Consolas", 10), bg=COLOR_INPUT_BG, fg=COLOR_TEXT_MUTED,
                          insertbackground=COLOR_ACCENT_GREEN, relief="flat",
                          highlightbackground=COLOR_CARD_BORDER, highlightthickness=1, width=28)
    search_box.pack(side="left", ipady=6, padx=(0, 10))
    search_box.insert(0, "Search catalog...")

    # Wire cards click filter
    for btn_card, (_, _, _, f_type) in zip(stats_bar.winfo_children(), card_defs):
        btn_card.config(command=lambda ft=f_type: handle_filter_click(ft, tree, stat_vars, search_box))

    def on_search_focus_in(e):
        if search_box.get() == "Search catalog...":
            search_box.delete(0, "end")
            search_box.config(fg=COLOR_TEXT_WHITE)
    def on_search_focus_out(e):
        if not search_box.get():
            search_box.insert(0, "Search catalog...")
            search_box.config(fg=COLOR_TEXT_MUTED)

    search_box.bind("<FocusIn>", on_search_focus_in)
    search_box.bind("<FocusOut>", on_search_focus_out)
    search_box.bind("<KeyRelease>", lambda e: refresh_table(tree, stat_vars, search_box))

    # All Action Buttons on Right
    del_btn = tk.Button(action_bar, text="Delete", font=("Consolas", 9, "bold"), relief="flat",
                        bg=COLOR_CARD_BG, fg="#F87171", activebackground="#7F1D1D", padx=12, pady=5,
                        cursor="hand2", command=lambda: handle_delete(tree, stat_vars, search_box))
    del_btn.pack(side="right", padx=(6, 0))

    toggle_btn = tk.Button(action_bar, text="Toggle Status", font=("Consolas", 9, "bold"), relief="flat",
                           bg=COLOR_CARD_BG, fg=COLOR_TEXT_MUTED, activebackground=COLOR_DARK_GREEN,
                           padx=12, pady=5, cursor="hand2", command=lambda: handle_toggle_status(tree, stat_vars, search_box))
    toggle_btn.pack(side="right", padx=(6, 0))

    edit_btn = tk.Button(action_bar, text="Edit", font=("Consolas", 9, "bold"), relief="flat",
                         bg=COLOR_CARD_BG, fg=COLOR_ACCENT_GREEN, activebackground=COLOR_DARK_GREEN,
                         padx=14, pady=5, cursor="hand2", command=lambda: handle_edit(root, tree, stat_vars, search_box))
    edit_btn.pack(side="right", padx=(6, 0))

    add_btn = tk.Button(action_bar, text="+ Add Book", font=("Consolas", 9, "bold"), relief="flat",
                        bg=COLOR_ACCENT_GREEN, fg=COLOR_BG_DARKEST, activebackground=COLOR_MUTED_GREEN,
                        padx=16, pady=5, cursor="hand2", command=lambda: handle_add(root, tree, stat_vars, search_box))
    add_btn.pack(side="right", padx=(6, 0))

    # 4. GREEN & BLACK STYLED TREEVIEW TABLE
    table_card = tk.Frame(books_view, bg=COLOR_CARD_BG, highlightbackground=COLOR_CARD_BORDER, highlightthickness=1)
    table_card.pack(fill="both", expand=True)

    style = ttk.Style()
    style.theme_use("clam")
    style.configure("Treeview",
                    background=COLOR_CARD_BG,
                    foreground=COLOR_TEXT_WHITE,
                    rowheight=32,
                    fieldbackground=COLOR_CARD_BG,
                    font=("Consolas", 9),
                    borderwidth=0)
    style.configure("Treeview.Heading",
                    background=COLOR_INPUT_BG,
                    foreground=COLOR_ACCENT_GREEN,
                    font=("Consolas", 8, "bold"),
                    relief="flat",
                    borderwidth=0)
    style.map("Treeview",
              background=[("selected", COLOR_DARK_GREEN)],
              foreground=[("selected", COLOR_ACCENT_GREEN)])

    cols = ("id", "title", "author", "year", "isbn", "status")
    tree = ttk.Treeview(table_card, columns=cols, show="headings", selectmode="browse")

    tree.heading("id", text="ID")
    tree.heading("title", text="TITLE")
    tree.heading("author", text="AUTHOR")
    tree.heading("year", text="YEAR")
    tree.heading("isbn", text="ISBN")
    tree.heading("status", text="STATUS")

    tree.column("id", width=65, anchor="center")
    tree.column("title", width=290, anchor="w")
    tree.column("author", width=200, anchor="w")
    tree.column("year", width=80, anchor="center")
    tree.column("isbn", width=170, anchor="center")
    tree.column("status", width=110, anchor="center")

    tree.tag_configure("available", foreground=COLOR_ACCENT_GREEN)
    tree.tag_configure("borrowed", foreground=COLOR_TEXT_MUTED)

    scroll = ttk.Scrollbar(table_card, orient="vertical", command=tree.yview)
    tree.configure(yscrollcommand=scroll.set)

    tree.pack(side="left", fill="both", expand=True, padx=1, pady=1)
    scroll.pack(side="right", fill="y", pady=1)

    # Initial view & data load
    switch_view("Books", views, nav_buttons)
    refresh_table(tree, stat_vars, search_box)

    return root


if __name__ == "__main__":
    app = create_app()
    app.mainloop()
