import tkinter as tk
from tkinter import messagebox
from tkinter import scrolledtext
import json

class Note:
    def __init__(self, title, content):
        self.title = title
        self.content = content

class NoteTakingApp:
    def __init__(self, master):
        self.master = master
        self.master.title("Note Taking App")
        self.notes = []
        self.current_note = None

        self.create_widgets()
        self.load_notes()

    def create_widgets(self):
        self.note_listbox = tk.Listbox(self.master, width=40, height=20, bg="lightgrey", fg="black")
        self.note_listbox.grid(row=0, column=0, rowspan=6, padx=(10, 0), pady=10, sticky="ns")

        self.note_text = scrolledtext.ScrolledText(self.master, width=40, height=20, bg="white", fg="black")
        self.note_text.grid(row=0, column=1, rowspan=4, padx=(10, 0), pady=10, sticky="nsew")

        self.bold_button = tk.Button(self.master, text="Bold", command=self.bold_text, bg="lightblue", fg="black")
        self.bold_button.grid(row=4, column=1, padx=(10, 0), pady=5, sticky="w")

        self.italic_button = tk.Button(self.master, text="Italic", command=self.italic_text, bg="lightblue", fg="black")
        self.italic_button.grid(row=4, column=1, padx=(70, 0), pady=5, sticky="w")

        self.bullet_button = tk.Button(self.master, text="Bullet", command=self.bullet_text, bg="lightblue", fg="black")
        self.bullet_button.grid(row=4, column=1, padx=(130, 0), pady=5, sticky="w")

        self.delete_button = tk.Button(self.master, text="Delete Note", command=self.delete_note, bg="lightcoral", fg="black")
        self.delete_button.grid(row=5, column=1, padx=(10, 0), pady=(0, 10), sticky="w")

        self.new_note_button = tk.Button(self.master, text="New Note", command=self.new_note, bg="lightgreen", fg="black")
        self.new_note_button.grid(row=5, column=1, padx=(80, 0), pady=(0, 10), sticky="w")

        self.save_note_button = tk.Button(self.master, text="Save Note", command=self.save_note, bg="lightgreen", fg="black")
        self.save_note_button.grid(row=5, column=1, padx=(150, 0), pady=(0, 10), sticky="w")

        self.search_label = tk.Label(self.master, text="Search:", bg="lightgrey", fg="black")
        self.search_label.grid(row=6, column=0, padx=(10, 0), pady=(0, 10), sticky="w")

        self.search_entry = tk.Entry(self.master, width=30)
        self.search_entry.grid(row=6, column=1, padx=(0, 10), pady=(0, 10), sticky="w")

        self.search_button = tk.Button(self.master, text="Search", command=self.search_note, bg="lightblue", fg="black")
        self.search_button.grid(row=6, column=1, padx=(190, 0), pady=(0, 10), sticky="e")

        self.note_listbox.bind("<<ListboxSelect>>", self.load_selected_note)

    def new_note(self):
        self.current_note = None
        self.note_text.delete(1.0, tk.END)
        self.master.title("Note Taking App - New Note")

    def save_note(self):
        title = self.note_text.get(1.0, 1.30).strip()
        content = self.note_text.get(1.0, tk.END).strip()
        if title:
            note = Note(title, content)
            if self.current_note:
                self.notes[self.notes.index(self.current_note)] = note
                self.current_note = note
                self.master.title(f"Note Taking App - {self.current_note.title}")
            else:
                self.notes.append(note)
                self.current_note = note
                self.master.title(f"Note Taking App - {self.current_note.title}")
            self.update_note_listbox()
            self.save_notes()
            messagebox.showinfo("Note Saved", "Note saved successfully.")
        else:
            messagebox.showwarning("Empty Title", "Please enter a title for the note.")

    def load_selected_note(self, event):
        try:
            index = self.note_listbox.curselection()[0]
            self.current_note = self.notes[index]
            self.master.title(f"Note Taking App - {self.current_note.title}")
            self.note_text.delete(1.0, tk.END)
            self.note_text.insert(tk.END, self.current_note.content)
        except IndexError:
            pass

    def update_note_listbox(self):
        self.note_listbox.delete(0, tk.END)
        for note in self.notes:
            self.note_listbox.insert(tk.END, note.title)

    def load_notes(self):
        try:
            with open("notes.json", "r") as file:
                data = json.load(file)
                for note_data in data:
                    note = Note(note_data["title"], note_data["content"])
                    self.notes.append(note)
                self.update_note_listbox()
        except FileNotFoundError:
            pass

    def save_notes(self):
        data = [{"title": note.title, "content": note.content} for note in self.notes]
        with open("notes.json", "w") as file:
            json.dump(data, file)

    def bold_text(self):
        self.note_text.tag_add("bold", "sel.first", "sel.last")
        self.note_text.tag_configure("bold", font=("Helvetica", 12, "bold"))

    def italic_text(self):
        self.note_text.tag_add("italic", "sel.first", "sel.last")
        self.note_text.tag_configure("italic", font=("Helvetica", 12, "italic"))

    def bullet_text(self):
        self.note_text.insert(tk.INSERT, "\u2022 ", "bullet")
    def delete_note(self):
        if self.current_note:
            self.notes.remove(self.current_note)
            self.update_note_listbox()
            self.current_note = None
            self.note_text.delete(1.0, tk.END)
            self.master.title("Note Taking App")
            self.save_notes()
            messagebox.showinfo("Note Deleted")
        else:
            messagebox.showinfo("No Note Selected", "Please select a note to delete.")
    def search_note(self):
        query = self.search_entry.get().strip().lower()
        if query:
            found = False
            for note in self.notes:
                if query in note.title.lower() or query in note.content.lower():
                    self.current_note = note
                    self.master.title(f"Note Taking App - {self.current_note.title}")
                    self.note_text.delete(1.0, tk.END)
                    self.note_text.insert(tk.END, self.current_note.content)
                    found = True
                    break
            if not found:
                messagebox.showinfo("Note Not Found", "No matching note found.")
        else:
            messagebox.showwarning("Empty Search", "Please enter a search query.")
def main():
    root = tk.Tk()
    app = NoteTakingApp(root)
    root.mainloop()
if __name__ == "__main__":
    main()
