use std::net::IpAddr;
use mas_data_model::{Client, User};
use oauth2_types::{registration::VerifiedClientMetadata, scope::Scope};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Debug, Clone, Copy)]
#[serde(rename_all = "kebab-case")]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub enum Code {
    UsernameTooShort,
    UsernameTooLong,
    UsernameInvalidChars,
    UsernameAllNumeric,
    UsernameBanned,
    UsernameNotAllowed,
    EmailDomainNotAllowed,
    EmailDomainBanned,
    EmailNotAllowed,
    EmailBanned,
}
impl Code {
    #[must_use]
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::UsernameTooShort => "username-too-short",
            Self::UsernameTooLong => "username-too-long",
            Self::UsernameInvalidChars => "username-invalid-chars",
            Self::UsernameAllNumeric => "username-all-numeric",
            Self::UsernameBanned => "username-banned",
            Self::UsernameNotAllowed => "username-not-allowed",
            Self::EmailDomainNotAllowed => "email-domain-not-allowed",
            Self::EmailDomainBanned => "email-domain-banned",
            Self::EmailNotAllowed => "email-not-allowed",
            Self::EmailBanned => "email-banned",
        }
    }
}
#[derive(Deserialize, Debug)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub struct Violation {
    pub msg: String,
    pub redirect_uri: Option<String>,
    pub field: Option<String>,
    pub code: Option<Code>,
}
#[derive(Deserialize, Debug)]
pub struct EvaluationResult {
    #[serde(rename = "result")]
    pub violations: Vec<Violation>,
}
impl std::fmt::Display for EvaluationResult {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut first = true;
        for violation in &self.violations {
            if first {
                first = false;
            } else {
                write!(f, ", ")?;
            }
            write!(f, "{}", violation.msg)?;
        }
        Ok(())
    }
}
impl EvaluationResult {
    #[must_use]
    pub fn valid(&self) -> bool {
        self.violations.is_empty()
    }
}
#[derive(Serialize, Debug, Default)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub struct Requester {
    pub ip_address: Option<IpAddr>,
    pub user_agent: Option<String>,
}
#[derive(Serialize, Debug)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub enum RegistrationMethod {
    #[serde(rename = "password")]
    Password,
    #[serde(rename = "upstream-oauth2")]
    UpstreamOAuth2,
}
#[derive(Serialize, Debug)]
#[serde(tag = "registration_method")]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub struct RegisterInput<'a> {
    pub registration_method: RegistrationMethod,
    pub username: &'a str,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub email: Option<&'a str>,
    pub requester: Requester,
}
#[derive(Serialize, Debug)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub struct ClientRegistrationInput<'a> {
    #[cfg_attr(
        feature = "jsonschema",
        schemars(with = "std::collections::HashMap<String, serde_json::Value>")
    )]
    pub client_metadata: &'a VerifiedClientMetadata,
    pub requester: Requester,
}
#[derive(Serialize, Debug)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub enum GrantType {
    AuthorizationCode,
    ClientCredentials,
    #[serde(rename = "urn:ietf:params:oauth:grant-type:device_code")]
    DeviceCode,
}
#[derive(Serialize, Debug)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub struct AuthorizationGrantInput<'a> {
    #[cfg_attr(
        feature = "jsonschema",
        schemars(with = "Option<std::collections::HashMap<String, serde_json::Value>>")
    )]
    pub user: Option<&'a User>,
    #[cfg_attr(
        feature = "jsonschema",
        schemars(with = "std::collections::HashMap<String, serde_json::Value>")
    )]
    pub client: &'a Client,
    #[cfg_attr(feature = "jsonschema", schemars(with = "String"))]
    pub scope: &'a Scope,
    pub grant_type: GrantType,
    pub requester: Requester,
}
#[derive(Serialize, Debug)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub struct EmailInput<'a> {
    pub email: &'a str,
    pub requester: Requester,
}