use std::path::PathBuf;

use thiserror::Error;

pub type Result<T> = std::result::Result<T, SiteforgeError>;

#[derive(Debug, Error)]
pub enum SiteforgeError {
    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),

    #[error("HTTP error: {0}")]
    Http(#[from] reqwest::Error),

    #[error("URL parse error: {0}")]
    Url(#[from] url::ParseError),

    #[error("SQLite error: {0}")]
    Sqlite(#[from] rusqlite::Error),

    #[error("JSON error: {0}")]
    Json(#[from] serde_json::Error),

    #[error("YAML error: {0}")]
    Yaml(#[from] serde_yaml::Error),

    #[error("glob pattern error: {0}")]
    Glob(#[from] globset::Error),

    #[error("zip error: {0}")]
    Zip(#[from] zip::result::ZipError),

    #[error("missing required input: {0}")]
    MissingInput(&'static str),

    #[error("invalid archive id: {0}")]
    InvalidArchiveId(String),

    #[error("archive not found: {0}")]
    ArchiveNotFound(String),

    #[error("robots.txt disallows fetching {0}")]
    RobotsDenied(String),

    #[error("unsupported or missing content type for {0}: {1}")]
    UnsupportedContent(String, String),

    #[error("configured size limit exceeded for {path}: {size} bytes > {limit} bytes")]
    SizeLimitExceeded { path: String, size: u64, limit: u64 },

    #[error("config directory is unavailable on this platform")]
    ConfigDirUnavailable,

    #[error("failed to resolve archive path: {0}")]
    ArchivePath(PathBuf),

    #[error("OCR unavailable: {0}")]
    OcrUnavailable(String),

    #[error("terminal UI error: {0}")]
    Tui(String),

    #[error("archive interrupted: resume with `siteforge resume {0}`")]
    ArchiveInterrupted(String),

    #[error("{0}")]
    Message(String),
}

impl SiteforgeError {
    pub fn message(message: impl Into<String>) -> Self {
        Self::Message(message.into())
    }
}
