pub mod addr;
pub mod apps;
pub mod auth;
pub mod carp;
pub mod groups;
pub mod id;
pub mod moderation;
pub mod oauth;
pub mod permissions;
pub mod posts;
pub mod reactions;
pub mod requests;
pub mod socket;

use std::fmt::Display;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct ApiReturn<T>
where
    T: Serialize,
{
    pub ok: bool,
    pub message: String,
    pub payload: T,
}

#[derive(Debug)]
pub enum Error {
    MiscError(String),
    DatabaseConnection(String),
    UserNotFound,
    GeneralNotFound(String),
    RegistrationDisabled,
    DatabaseError(String),
    IncorrectPassword,
    NotAllowed,
    AlreadyAuthenticated,
    DataTooLong(String),
    DataTooShort(String),
    FileTooLarge,
    FileTooSmall,
    UsernameInUse,
    TitleInUse,
    QuestionsDisabled,
    RequiresSupporter,
    DrawingsDisabled,
    AppHitStorageLimit,
    DoesNotSupportField(String),
    Unknown,
}

impl Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&match self {
            Self::MiscError(msg) => msg.to_owned(),
            Self::DatabaseConnection(msg) => msg.to_owned(),
            Self::DatabaseError(msg) => format!("Database error: {msg}"),
            Self::UserNotFound => "Unable to find user with given parameters".to_string(),
            Self::GeneralNotFound(name) => format!("Unable to find requested {name}"),
            Self::RegistrationDisabled => "Registration is disabled".to_string(),
            Self::IncorrectPassword => "The given password is invalid".to_string(),
            Self::NotAllowed => "You are not allowed to do this".to_string(),
            Self::AlreadyAuthenticated => "Already authenticated".to_string(),
            Self::DataTooLong(name) => format!("Given {name} is too long!"),
            Self::DataTooShort(name) => format!("Given {name} is too short!"),
            Self::FileTooLarge => "Given file is too large".to_string(),
            Self::FileTooSmall => "Given file is too small".to_string(),
            Self::UsernameInUse => "Username in use".to_string(),
            Self::TitleInUse => "Title in use".to_string(),
            Self::QuestionsDisabled => "You are not allowed to ask questions there".to_string(),
            Self::RequiresSupporter => "Only site supporters can do this".to_string(),
            Self::DrawingsDisabled => "You are not allowed to submit drawings there".to_string(),
            Self::AppHitStorageLimit => "This app has already hit its storage limit, or will do so if this data is processed.".to_string(),
            Self::DoesNotSupportField(name) => format!("{name} does not support this field"),
            _ => format!("An unknown error as occurred: ({:?})", self),
        })
    }
}

impl<T> From<Error> for ApiReturn<T>
where
    T: Default + Serialize,
{
    fn from(val: Error) -> Self {
        ApiReturn {
            ok: false,
            message: val.to_string(),
            payload: T::default(),
        }
    }
}

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

pub mod uploads {
    pub use buckets_core::model::{MediaType, MediaUpload};
}
