use std::fs;

use egui::TextEdit;
use serde::{Deserialize, Serialize, de::DeserializeOwned};

use crate::{
    FILESYSTEM, PROJECT_FOLDER,
    editors::tags::Tag,
    filesystem::{FileSystem, Id},
    util,
};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Note {
    pub name: String,
    #[serde(default)]
    pub content: String,
    #[serde(default)]
    pub subject: String,

    #[serde(default)]
    pub tags: Vec<Id>,

    pub id: Id,

    #[serde(skip)]
    pub saved: bool,
}

impl Default for Note {
    fn default() -> Self {
        Self {
            id: Id::new(),
            name: "New Note".to_string(),
            subject: "".to_string(),
            content: "".to_string(),
            tags: Vec::new(),
            saved: false,
        }
    }
}

impl Note {
    pub fn new() -> Self {
        Self {
            id: Id::new(),
            name: "New Note".to_string(),
            subject: "".to_string(),
            content: "".to_string(),
            tags: Vec::new(),
            saved: false,
        }
    }

    pub fn save(&mut self) -> std::io::Result<()> {
        let id = &self.id;
        let data = serde_json::to_string(&self)?;
        FILESYSTEM.write(id, data).unwrap();

        self.saved = true;
        Ok(())
    }

    pub fn load(id: &Id) -> std::io::Result<Self> {
        let mut note: Note = FILESYSTEM.read(id).unwrap();
        note.id = id.clone();
        note.saved = true;
        Ok(note)
    }

    pub fn ui(&mut self, ui: &mut egui::Ui) {
        if ui.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) {
            if let Err(e) = self.save() {
                eprintln!("Failed to save: {e}");
            }
        }

        util::saved_status(ui, self.saved, &self.id, &self.name);

        if ui.button("Save").clicked() {
            if let Err(e) = self.save() {
                eprintln!("Failed to save: {e}");
            }
        }

        let id = ui.make_persistent_id("note_name");
        egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true)
            .show_header(ui, |ui| {
                ui.strong("Name");
            })
            .body(|ui| {
                ui.separator();
                if TextEdit::singleline(&mut self.name)
                    .desired_width(f32::INFINITY)
                    .frame(false)
                    .show(ui)
                    .response
                    .changed()
                {
                    self.saved = false;
                }
                ui.separator();
            });

        let id = ui.make_persistent_id("note_tags");
        egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true)
            .show_header(ui, |ui| {
                ui.strong("Tags");
            })
            .body(|ui| {
                ui.separator();
                Tag::selector_ui(&mut self.tags, ui, Some(&mut self.saved));
                ui.separator();
            });

        let id = ui.make_persistent_id("note_subject");
        egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true)
            .show_header(ui, |ui| {
                ui.strong("Subject");
            })
            .body(|ui| {
                ui.separator();
                if TextEdit::singleline(&mut self.subject)
                    .desired_width(f32::INFINITY)
                    .frame(false)
                    .show(ui)
                    .response
                    .changed()
                {
                    self.saved = false;
                }
                ui.separator();
            });

        let id = ui.make_persistent_id("note_content");
        egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true)
            .show_header(ui, |ui| {
                ui.strong("Content");
            })
            .body(|ui| {
                ui.separator();
                if TextEdit::multiline(&mut self.content)
                    .desired_width(f32::INFINITY)
                    .desired_rows(5)
                    .frame(false)
                    .show(ui)
                    .response
                    .changed()
                {
                    self.saved = false;
                }
                ui.separator();
            });
    }
}
