use serde::{Deserialize, Serialize};
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use tauri::{AppHandle, Manager};

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AppSettings {
    pub theme: String,
    pub default_shell: Option<String>,
    pub vigthoria_cli_path: Option<String>,
    pub show_report_panel: bool,
    pub last_workspace_id: Option<String>,
    #[serde(default = "default_hyperloop_url")]
    pub hyperloop_url: String,
    #[serde(default = "default_template_url")]
    pub template_url: String,
    #[serde(default)]
    pub comfort_prompt_enabled: bool,
    #[serde(default = "default_goa_auto_route")]
    pub goa_auto_route: bool,
    #[serde(default = "default_tools_tab")]
    pub tools_tab: String,
}

fn default_hyperloop_url() -> String {
    "https://hyperloop.vigthoria.io".into()
}

fn default_template_url() -> String {
    "https://coder.vigthoria.io/api/template-service".into()
}

fn default_tools_tab() -> String {
    "report".into()
}

fn default_goa_auto_route() -> bool {
    true
}

impl Default for AppSettings {
    fn default() -> Self {
        Self {
            theme: "vigthoria-dark".into(),
            default_shell: None,
            vigthoria_cli_path: None,
            show_report_panel: true,
            last_workspace_id: None,
            hyperloop_url: default_hyperloop_url(),
            template_url: default_template_url(),
            comfort_prompt_enabled: true,
            goa_auto_route: default_goa_auto_route(),
            tools_tab: default_tools_tab(),
        }
    }
}

pub struct SettingsStore {
    inner: parking_lot::Mutex<AppSettings>,
}

impl Default for SettingsStore {
    fn default() -> Self {
        Self {
            inner: parking_lot::Mutex::new(AppSettings::default()),
        }
    }
}

impl SettingsStore {
    pub fn load_from_disk(&self, app: &AppHandle) {
        let path = settings_path(app);
        if let Ok(raw) = fs::read_to_string(path) {
            if let Ok(parsed) = serde_json::from_str::<AppSettings>(&raw) {
                *self.inner.lock() = migrate_settings(parsed);
            }
        }
    }

    pub fn get(&self) -> AppSettings {
        self.inner.lock().clone()
    }

    pub fn save(&self, app: &AppHandle, settings: AppSettings) -> Result<AppSettings, String> {
        *self.inner.lock() = settings.clone();
        self.persist(app)?;
        Ok(settings)
    }

    pub fn persist(&self, app: &AppHandle) -> Result<(), String> {
        let path = settings_path(app);
        if let Some(parent) = path.parent() {
            fs::create_dir_all(parent).map_err(|e| e.to_string())?;
        }
        let json = serde_json::to_string_pretty(&*self.inner.lock()).map_err(|e| e.to_string())?;
        write_atomic(&path, json.as_bytes())
    }
}

fn write_atomic(path: &PathBuf, bytes: &[u8]) -> Result<(), String> {
    let parent = path.parent().ok_or_else(|| "Invalid settings path".to_string())?;
    let temp = parent.join(format!(".settings.{}.tmp", std::process::id()));
    let backup = parent.join("settings.json.previous");
    {
        let mut file = fs::File::create(&temp).map_err(|e| e.to_string())?;
        file.write_all(bytes).map_err(|e| e.to_string())?;
        file.sync_all().map_err(|e| e.to_string())?;
    }

    let had_original = path.exists();
    if had_original {
        let _ = fs::remove_file(&backup);
        fs::rename(path, &backup).map_err(|e| {
            let _ = fs::remove_file(&temp);
            format!("Failed to stage existing settings: {e}")
        })?;
    }

    if let Err(error) = fs::rename(&temp, path) {
        if had_original {
            let _ = fs::rename(&backup, path);
        }
        let _ = fs::remove_file(&temp);
        return Err(format!("Failed to commit settings: {error}"));
    }

    if had_original {
        let _ = fs::remove_file(&backup);
    }
    Ok(())
}

fn migrate_settings(mut settings: AppSettings) -> AppSettings {
    if settings.template_url.trim_end_matches('/') == "https://templates.vigthoria.io" {
        settings.template_url = default_template_url();
    }
    settings
}

fn settings_path(app: &AppHandle) -> PathBuf {
    app.path()
        .app_data_dir()
        .unwrap_or_else(|_| PathBuf::from("."))
        .join("settings.json")
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn migrates_obsolete_template_endpoint() {
        let mut settings = AppSettings::default();
        settings.template_url = "https://templates.vigthoria.io/".into();
        assert_eq!(
            migrate_settings(settings).template_url,
            "https://coder.vigthoria.io/api/template-service"
        );
    }

    #[test]
    fn atomic_writer_commits_complete_json() {
        let root = std::env::temp_dir().join(format!(
            "vigthoria-workbench-settings-test-{}",
            std::process::id()
        ));
        fs::create_dir_all(&root).unwrap();
        let path = root.join("settings.json");
        write_atomic(&path, br#"{"theme":"dark"}"#).unwrap();
        assert_eq!(fs::read_to_string(&path).unwrap(), r#"{"theme":"dark"}"#);
        write_atomic(&path, br#"{"theme":"light"}"#).unwrap();
        assert_eq!(fs::read_to_string(&path).unwrap(), r#"{"theme":"light"}"#);
        let _ = fs::remove_dir_all(root);
    }
}
