//! OS-conventional paths for client-side storage.

use std::path::PathBuf;

use directories::ProjectDirs;
use thiserror::Error;

/// Directory name for pending (not-yet-uploaded) recordings inside the
/// data-local root.
const PENDING_DIR_NAME: &str = "pending";

/// Directory name for per-case marker files inside the data-local root.
const CASES_DIR_NAME: &str = "cases";

/// File name for the oneliners snapshot cache inside the data-local root.
const SNAPSHOT_CACHE_FILENAME: &str = "oneliners_cache.json";

/// File name for the single-instance advisory lock inside the data-local
/// root.
const LOCK_FILENAME: &str = "client.lock";

#[derive(Debug, Error)]
pub enum PathError {
    #[error("cannot determine OS data directory (is $HOME set?)")]
    NoDataDir,
}

/// Resolve `{data_local_dir}/{rel}` under the doctate project scope, or
/// error if the OS won't give us a data directory at all. Every public
/// path helper here delegates to this so the `ProjectDirs::from(…)`
/// triple stays in one place.
fn project_path(rel: &str) -> Result<PathBuf, PathError> {
    ProjectDirs::from("", "", "doctate")
        .map(|dirs| dirs.data_local_dir().join(rel))
        .ok_or(PathError::NoDataDir)
}

/// Directory where recordings wait for upload. Persists across app
/// restarts and crashes.
///   Linux:   `~/.local/share/doctate/pending/`
///   Windows: `%LOCALAPPDATA%\doctate\pending\`
///   macOS:   `~/Library/Application Support/doctate/pending/`
pub fn pending_dir() -> Result<PathBuf, PathError> {
    project_path(PENDING_DIR_NAME)
}

/// Directory holding one JSON marker per known case (locally created
/// and/or server-synced). Persists across app restarts.
///   Linux:   `~/.local/share/doctate/cases/`
pub fn cases_dir() -> Result<PathBuf, PathError> {
    project_path(CASES_DIR_NAME)
}

/// File path for the last-successful `/api/oneliners` response. Feeds
/// the UI at cold start before the first live poll completes.
pub fn snapshot_cache_path() -> Result<PathBuf, PathError> {
    project_path(SNAPSHOT_CACHE_FILENAME)
}

/// File path for the single-instance advisory lock. Held by the running
/// process for its entire lifetime; a second launch attempting to lock
/// the same file gets `WouldBlock` and exits cleanly.
pub fn lock_file_path() -> Result<PathBuf, PathError> {
    project_path(LOCK_FILENAME)
}
