///|
/// Application-scoped directories: cache, config, data, etc. under a project path.
/// **Path segment:** Linux = single lowercase segment; macOS = qualifier.Org-App; Windows = Org\\\\App.
pub struct ProjectDirs {
  project_path : String
  cache_dir : String
  config_dir : String
  config_local_dir : String
  data_dir : String
  data_local_dir : String
  preference_dir : String
  runtime_dir : String?
  state_dir : String?
}

///|
fn join_hyphen(parts : Array[String]) -> String {
  parts.fold(init="", (acc, p) => if acc == "" { p } else { acc + "-" + p })
}

///|
fn replace_space_with_hyphen(s : String) -> String {
  let parts = s.split(" ").map(v => v.to_owned()).collect()
  join_hyphen(parts)
}

///|
fn project_path_linux(
  _qualifier : String,
  _organization : String,
  application : String,
) -> String {
  let lower = application[:].to_lower().to_owned()
  replace_space_with_hyphen(lower)
}

///|
fn project_path_macos(
  qualifier : String,
  organization : String,
  application : String,
) -> String {
  let q = if qualifier == "" { "" } else { qualifier + "." }
  let org_s = replace_space_with_hyphen(organization)
  let app_s = replace_space_with_hyphen(application)
  if org_s == "" {
    q + app_s
  } else {
    q + org_s + "." + app_s
  }
}

///|
fn project_path_windows(
  _qualifier : String,
  organization : String,
  application : String,
) -> String {
  if organization == "" {
    application
  } else {
    organization + path_sep() + application
  }
}

///|
/// Choose project path segment style from runtime platform.
fn project_path_segment(
  qualifier : String,
  organization : String,
  application : String,
) -> String {
  match platform() {
    Platform::Windows =>
      project_path_windows(qualifier, organization, application)
    Platform::Darwin => project_path_macos(qualifier, organization, application)
    _ => project_path_linux(qualifier, organization, application)
  }
}

///|
fn opt_join(prefix : String?, seg : String) -> String? {
  match prefix {
    Some(p) => Some(join([p, seg]))
    None => None
  }
}

///|
/// Creates ProjectDirs from qualifier, organization, and application names.
/// Returns `None` if home/base dirs are unavailable.
/// Example: `ProjectDirs::from("com", "Acme", "MyApp")` → cache/config/data under Acme\\\\MyApp (Windows) or com/acme.myapp (macOS) or myapp (Linux).
pub fn ProjectDirs::from(
  qualifier : String,
  organization : String,
  application : String,
) -> ProjectDirs? {
  match BaseDirs::new() {
    Some(base) => {
      let seg = project_path_segment(qualifier, organization, application)
      Some(ProjectDirs::{
        project_path: seg,
        cache_dir: join([base.cache_dir(), seg]),
        config_dir: join([base.config_dir(), seg]),
        config_local_dir: join([base.config_local_dir(), seg]),
        data_dir: join([base.data_dir(), seg]),
        data_local_dir: join([base.data_local_dir(), seg]),
        preference_dir: join([base.preference_dir(), seg]),
        runtime_dir: opt_join(base.runtime_dir(), seg),
        state_dir: opt_join(base.state_dir(), seg),
      })
    }
    None => None
  }
}

///|
/// Project path segment used under base dirs (e.g. "Acme\\MyApp" on Windows, "myapp" on Linux).
pub fn ProjectDirs::project_path(self : ProjectDirs) -> String {
  self.project_path
}

///|
/// App cache directory (e.g. base cache_dir + project_path).
pub fn ProjectDirs::cache_dir(self : ProjectDirs) -> String {
  self.cache_dir
}

///|
/// App config directory (roaming on Windows).
pub fn ProjectDirs::config_dir(self : ProjectDirs) -> String {
  self.config_dir
}

///|
/// App local config directory.
pub fn ProjectDirs::config_local_dir(self : ProjectDirs) -> String {
  self.config_local_dir
}

///|
/// App data directory.
pub fn ProjectDirs::data_dir(self : ProjectDirs) -> String {
  self.data_dir
}

///|
/// App local data directory.
pub fn ProjectDirs::data_local_dir(self : ProjectDirs) -> String {
  self.data_local_dir
}

///|
/// App preference/settings directory.
pub fn ProjectDirs::preference_dir(self : ProjectDirs) -> String {
  self.preference_dir
}

///|
/// App runtime directory (Unix only); None on Windows.
pub fn ProjectDirs::runtime_dir(self : ProjectDirs) -> String? {
  self.runtime_dir
}

///|
/// App state directory (Unix only); None on Windows.
pub fn ProjectDirs::state_dir(self : ProjectDirs) -> String? {
  self.state_dir
}