use shared::types::CleanConfig;
use std::fs;
use std::path::PathBuf;
use std::sync::{Mutex, OnceLock};
use tauri::Manager;

fn get_config_path(app: &tauri::AppHandle) -> PathBuf {
  let mut path = app
    .path()
    .app_config_dir()
    .unwrap_or_else(|_| std::env::current_dir().unwrap());

  let _ = fs::create_dir_all(&path);

  path.push("config.json");

  path
}

static CONFIG_CACHE: OnceLock<Mutex<Option<CleanConfig>>> = OnceLock::new();

fn cache() -> &'static Mutex<Option<CleanConfig>> {
  CONFIG_CACHE.get_or_init(|| Mutex::new(None))
}

pub fn load_config(app: &tauri::AppHandle) -> CleanConfig {
  if let Ok(guard) = cache().lock() {
    if let Some(ref config) = *guard {
      return config.clone();
    }
  }

  let path = get_config_path(app);

  if path.exists() {
    if let Ok(content) = fs::read_to_string(&path) {
      if let Ok(config) = serde_json::from_str::<CleanConfig>(&content) {
        log::info!("Loaded configuration from {}", path.display());
        if let Ok(mut guard) = cache().lock() {
          *guard = Some(config.clone());
        }
        return config;
      }
    }
    log::warn!(
      "Configuration file at {} was malformed. Reverting to defaults.",
      path.display()
    );
  } else {
    log::info!(
      "No configuration file found at {}. Generating defaults.",
      path.display()
    );
  }

  let default_config = CleanConfig::default();
  if let Ok(mut guard) = cache().lock() {
    *guard = Some(default_config.clone());
  }
  if let Err(e) = save_config(app, &default_config) {
    log::error!("Failed to save default configuration: {}", e);
  }

  default_config
}

pub fn save_config(app: &tauri::AppHandle, config: &CleanConfig) -> Result<(), String> {
  let path = get_config_path(app);
  let content = serde_json::to_string_pretty(config).map_err(|e| e.to_string())?;

  fs::write(&path, content).map_err(|e| {
    let err_msg = format!("Failed to write configuration: {}", e);
    log::error!("{}", err_msg);
    err_msg
  })?;

  if let Ok(mut guard) = cache().lock() {
    *guard = Some(config.clone());
  }

  log::info!("Saved configuration to {}", path.display());
  Ok(())
}

#[tauri::command]
pub fn get_config(app: tauri::AppHandle) -> CleanConfig {
  load_config(&app)
}
