//! Typed error surface for the `org-gdocs` library.
//!
//! Every distinct failure a caller might branch on is its own variant. `anyhow`
//! is confined to the binary edge and never appears here.

use std::path::PathBuf;

/// Errors raised by `org-gdocs` library code.
#[derive(Debug, thiserror::Error)]
pub enum Error {
    /// A filesystem operation failed for the given path.
    #[error("I/O error at {path}: {source}")]
    Io {
        /// Path the failing operation targeted.
        path: PathBuf,
        /// Underlying I/O error.
        source: std::io::Error,
    },

    /// The configuration file could not be parsed as TOML.
    #[error("invalid TOML configuration: {0}")]
    ConfigToml(#[from] toml::de::Error),

    /// The configuration could not be serialized to TOML.
    #[error("could not serialize TOML configuration: {0}")]
    ConfigTomlSerialize(#[from] toml::ser::Error),

    /// A JSON value could not be (de)serialized.
    ///
    /// JSON is confined to the forced external boundaries (the Google API wire
    /// format and OAuth credential/token files, OVR-1/A5); surfaces this crate
    /// owns use s-expressions and surface [`Error::Sexp`] instead.
    #[error("JSON error: {0}")]
    Json(#[from] serde_json::Error),

    /// An s-expression (the `** Sync State` block or the CLI↔Emacs envelope, A5)
    /// could not be parsed or did not match the expected shape.
    #[error("s-expression error: {0}")]
    Sexp(#[from] crate::sexp::SexpError),

    /// A Google Docs or Drive API call failed — transport, protocol, or a
    /// non-success API response.
    ///
    /// The generated client's error type is mapped to its display string at the
    /// single seam in [`crate::google::client`] (F6) so it never leaks into this
    /// crate's public surface (EI-1).
    #[error("Google API error: {0}")]
    Google(String),

    /// The target document exposes more than one tab, which is unsupported.
    ///
    /// We operate only on the first/legacy tab (DI-6); a multi-tab document is
    /// reported rather than silently mis-indexed.
    #[error("document has multiple tabs, which is unsupported (operate on a single-tab document)")]
    MultipleTabs,

    /// The org body could not be parsed by `tftio-kb`.
    #[error("could not parse org body: {0}")]
    OrgParse(String),

    /// The org file has no linked Google Doc (`#+GDOC_ID:`).
    ///
    /// `pull`, `clean`, and `open` all require a document to have been created by
    /// a prior `push`; this is the branchable failure they surface when it has not.
    #[error("org file has no linked Google Doc (#+GDOC_ID:); run `push` first")]
    NotLinked,

    /// A required path could not be resolved (e.g. no home/config directory).
    #[error("could not resolve {0}")]
    PathResolution(String),

    /// OAuth authentication, token acquisition, or TLS setup failed.
    #[error("authentication error: {0}")]
    Auth(String),
}

/// Convenience result alias for fallible `org-gdocs` library functions.
pub type Result<T> = std::result::Result<T, Error>;
