#[cfg(feature = "backtrace")]
use std::backtrace::Backtrace;
use thiserror::Error as ThisError;
#[cfg(feature = "js-error")]
use wasm_bindgen::JsValue;

#[derive(ThisError, Debug)]
pub enum ParseError {
    #[error("{info}")]
    InvalidData {
        #[cfg(feature = "backtrace")]
        backtrace: Backtrace,
        info: String,
    },
    #[error("source")]
    Chrono {
        #[cfg(feature = "backtrace")]
        backtrace: Backtrace,
        #[from]
        source: chrono::ParseError,
    },
    #[error("source")]
    Int {
        #[cfg(feature = "backtrace")]
        backtrace: Backtrace,
        #[from]
        source: std::num::ParseIntError,
    },
}

impl From<String> for ParseError {
    fn from(info: String) -> ParseError {
        ParseError::InvalidData {
            info,
            #[cfg(feature = "backtrace")]
            backtrace: Backtrace::capture(),
        }
    }
}

impl From<&str> for ParseError {
    fn from(info: &str) -> ParseError {
        ParseError::InvalidData {
            info: info.to_string(),
            #[cfg(feature = "backtrace")]
            backtrace: Backtrace::capture(),
        }
    }
}

#[cfg(feature = "js-error")]
#[derive(Debug)]
pub struct JsError {
    inner: JsValue,
}
#[cfg(feature = "js-error")]
impl std::fmt::Display for JsError {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
        todo!()
    }
}
#[cfg(feature = "js-error")]
impl std::error::Error for JsError {}
#[cfg(feature = "js-error")]
impl From<JsValue> for JsError {
    fn from(inner: JsValue) -> Self {
        Self { inner }
    }
}

#[derive(ThisError, Debug)]
pub enum Error {
    #[error("{source}")]
    Json {
        #[cfg(feature = "backtrace")]
        backtrace: Backtrace,
        #[from]
        source: serde_json::Error,
    },
    #[cfg(feature = "hyper-requester")]
    #[error("{source}")]
    Http {
        #[cfg(feature = "backtrace")]
        backtrace: Backtrace,
        #[from]
        source: hyper::Error,
    },
    #[cfg(feature = "js-fetch-requester")]
    #[error("{source}")]
    Js {
        #[from]
        source: JsError,
    },
    #[error("{source}")]
    Parse {
        #[cfg_attr(feature = "backtrace", backtrace)]
        #[from]
        source: ParseError,
    },
    #[error("{text}")]
    Hafas { code: String, text: String },
    #[error("{0}")]
    InvalidInput(String),
}

pub type Result<T> = std::result::Result<T, Error>;
pub type ParseResult<T> = std::result::Result<T, ParseError>;
