use chrono::NaiveDate;
use egui::TextEdit;
use egui_extras::DatePickerButton;
use serde::{Deserialize, Serialize};
use std::{io::Read, path::PathBuf, sync::LazyLock};

use crate::{PROJECT_FOLDER, util::saved_status};

#[derive(Serialize, Deserialize, Clone)]
pub struct ProjectSettings {
    date: NaiveDate,
    project_name: String,
    project_author: String,
    project_description: String,

    // AI settings
    pub ai_context: String,

    // settings
    #[serde(skip)]
    pub global_settings: EditorSettings,
    #[serde(skip)]
    pub local_overrides: EditorSettings,

    #[serde(skip)]
    pub open: bool,

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

static GLOBAL_SETTINGS_PATH: LazyLock<String> =
    LazyLock::new(|| match std::env::var("XDG_CONFIG_HOME") {
        Ok(path) => path + "/worldcoder/settings.json",
        Err(_) => {
            eprintln!(
                "XDG_CONFIG_HOME not set, using default path of ~/.config/worldcoder/settings.json"
            );
            "~/.config/worldcoder/settings.json".to_string()
        }
    });

impl ProjectSettings {
    #[allow(dead_code)]
    pub fn new() -> Self {
        Self::default()
    }

    pub fn load() -> Self {
        let project_path = PROJECT_FOLDER.join("project.json");

        let mut file = if let Ok(file) = std::fs::File::open(project_path) {
            file
        } else {
            return Self::default();
        };

        let mut contents = String::new();
        file.read_to_string(&mut contents).unwrap();
        if let Ok(mut proj) = serde_json::from_str::<Self>(&contents) {
            proj.saved = true;

            // load global settings
            proj.global_settings = EditorSettings::load_global();

            // load local overrides
            proj.local_overrides = EditorSettings::load();

            proj
        } else {
            Self::default()
        }
    }

    pub fn save(&mut self) {
        let project_path = PROJECT_FOLDER.join("project.json");
        let content = serde_json::to_string_pretty(self).unwrap();
        std::fs::write(project_path, content).unwrap();

        self.global_settings.save();
        self.local_overrides.save();

        self.saved = true;
    }

    #[allow(dead_code)]
    pub fn ui(&mut self, ui: &mut egui::Ui) {
        // save state
        saved_status(ui, self.saved, "N/A", "Project Settings");
        if ui.button("Save").clicked() {
            self.save();
        }

        ui.separator();

        // project settings
        ui.heading("Project Settings");
        egui::Grid::new("project settings")
            .striped(true)
            .num_columns(2)
            .show(ui, |ui| {
                ui.label("Project Name");
                ui.text_edit_singleline(&mut self.project_name);

                ui.end_row();

                ui.label("Project Author");
                ui.text_edit_singleline(&mut self.project_author);

                ui.end_row();

                ui.label("Project Description");
                ui.text_edit_singleline(&mut self.project_description);

                ui.end_row();

                ui.label("Date");
                ui.add(DatePickerButton::new(&mut self.date));

                ui.end_row();

                ui.label("AI Context Prompt");
                ui.add(TextEdit::multiline(&mut self.ai_context)
                    .font(egui::TextStyle::Monospace)
                    .interactive(true)
                    .frame(false)
                    .lock_focus(true)
                    .hint_text("What is this project about? what should the LLM know when generating content for this project?"));

                ui.end_row();
            });

        ui.separator();

        // local settings overrides for editor
        ui.heading("Local Overrides");
        egui::Grid::new("local overrides")
            .striped(true)
            .num_columns(2)
            .show(ui, |ui| {
                ui.label("Enable AI");
                if let Some(ai_enabled) = &mut self.local_overrides.ai_enabled {
                    ui.checkbox(ai_enabled, "Enable AI");
                    if ui.button("Remove Override").clicked() {
                        self.local_overrides.ai_enabled = None;
                    }
                } else if ui.button("Override").clicked() {
                    self.local_overrides.ai_enabled = Some(true);
                }

                ui.end_row();

                ui.label("LLM API URI");
                if let Some(llm_api_uri) = &mut self.local_overrides.llm_api_uri {
                    ui.text_edit_singleline(llm_api_uri);
                    if ui.button("Remove Override").clicked() {
                        self.local_overrides.llm_api_uri = None;
                    }
                } else if ui.button("Override").clicked() {
                    self.local_overrides.llm_api_uri = Some("http://localhost:1234".to_string());
                }

                ui.end_row();

                ui.label("LLM API Key");
                if let Some(llm_api_key) = &mut self.local_overrides.llm_api_key {
                    ui.text_edit_singleline(llm_api_key);
                    if ui.button("Remove Override").clicked() {
                        self.local_overrides.llm_api_key = None;
                    }
                } else if ui.button("Override").clicked() {
                    self.local_overrides.llm_api_key = Some("1234".to_string());
                }

                ui.end_row();
            });

        ui.separator();

        // global editor settings
        ui.heading("Global Editor Settings");
        egui::Grid::new("global settings")
            .striped(true)
            .num_columns(2)
            .show(ui, |ui| {
                ui.label("Enable AI");
                ui.checkbox(&mut self.global_settings.ai_enabled.unwrap(), "Enable AI");

                ui.end_row();

                ui.label("LLM API URI");
                ui.text_edit_singleline(self.global_settings.llm_api_uri.as_mut().unwrap());

                ui.end_row();

                ui.label("LLM API Key");
                ui.text_edit_singleline(self.global_settings.llm_api_key.as_mut().unwrap());

                ui.end_row();
            });
    }

    pub fn ai_enabled(&mut self) -> bool {
        let client = reqwest::blocking::Client::new();

        if self.global_settings.ai_enabled.unwrap() {
            return true;
        }

        if client
            .get(self.global_settings.llm_api_uri.clone().unwrap() + "/v1/models")
            .send()
            .is_ok()
        {
            self.global_settings.ai_enabled = Some(true);
            return true;
        }

        false
    }

    pub fn open(&mut self) {
        self.open = true;
    }

    pub fn _close(&mut self) {
        self.open = false;
    }
}

impl Default for ProjectSettings {
    fn default() -> Self {
        Self {
            date: chrono::Local::now().naive_local().into(),
            project_name: "New Project".to_string(),
            project_author: "Your Name".to_string(),
            project_description: "Description of your project".to_string(),

            ai_context: "".to_string(),
            global_settings: EditorSettings::new(),
            local_overrides: EditorSettings::new(),

            // window state
            open: false,
            saved: false,
        }
    }
}

#[derive(Serialize, Deserialize, Clone)]
pub struct EditorSettings {
    pub llm_api_uri: Option<String>,
    pub llm_api_key: Option<String>,
    pub ai_enabled: Option<bool>,
    pub dark_theme: Option<bool>,

    #[serde(skip)]
    is_global: bool,
}

impl Default for EditorSettings {
    fn default() -> Self {
        Self {
            llm_api_uri: Some("http://localhost:1234".to_string()),
            llm_api_key: Some("".to_string()),
            ai_enabled: Some(true),
            dark_theme: Some(true),

            // window state
            is_global: true,
        }
    }
}

impl EditorSettings {
    pub fn new() -> Self {
        Self {
            llm_api_uri: None,
            llm_api_key: None,
            ai_enabled: None,
            dark_theme: None,

            is_global: false,
        }
    }

    pub fn load() -> Self {
        let path = PROJECT_FOLDER.join("settings.json");
        let mut file = if let Ok(file) = std::fs::File::open(path) {
            file
        } else {
            return Self::default();
        };

        let mut contents = String::new();
        file.read_to_string(&mut contents).unwrap();
        serde_json::from_str(&contents).unwrap()
    }

    pub fn save(&self) {
        let content = serde_json::to_string_pretty(self).unwrap();

        let path = if self.is_global {
            PathBuf::from(GLOBAL_SETTINGS_PATH.clone())
        } else {
            PROJECT_FOLDER.join("settings.json")
        };

        std::fs::write(path, content).unwrap();
    }

    pub fn load_global() -> Self {
        let path = PathBuf::from(GLOBAL_SETTINGS_PATH.clone());

        if !path.exists() {
            std::fs::create_dir_all(path.parent().unwrap()).unwrap();
            let content = serde_json::to_string_pretty(&Self::default()).unwrap();
            std::fs::write(&path, content).unwrap();

            // return a default config
            return Self::default();
        }

        let content = std::fs::read_to_string(path).unwrap();
        serde_json::from_str(&content).unwrap()
    }
}
