use athena_auth_core::NativeRightModuleInput;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

use crate::plugins::helpers::SessionWithServerVersion;
use validator::Validate;

// ---------------------------------------------------------------------------
// Request types
// ---------------------------------------------------------------------------

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct SetRoleRequest {
    #[serde(rename = "userId")]
    #[validate(length(min = 1, message = "userId is required"))]
    pub user_id: String,
    #[validate(length(min = 1, message = "role is required"))]
    pub role: String,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct CreateUserRequest {
    #[validate(email(message = "Invalid email address"))]
    pub email: String,
    #[validate(length(min = 1, message = "Password is required"))]
    pub password: String,
    pub name: Option<String>,
    pub role: Option<String>,
    pub data: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct UserIdRequest {
    #[serde(rename = "userId")]
    #[validate(length(min = 1, message = "userId is required"))]
    pub user_id: String,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct BanUserRequest {
    #[serde(rename = "userId")]
    #[validate(length(min = 1, message = "userId is required"))]
    pub user_id: String,
    #[serde(rename = "banReason")]
    pub ban_reason: Option<String>,
    /// Number of seconds until the ban expires.
    #[serde(rename = "banExpiresIn")]
    pub ban_expires_in: Option<i64>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct RevokeSessionRequest {
    #[serde(rename = "sessionToken")]
    #[validate(length(min = 1, message = "sessionToken is required"))]
    pub session_token: String,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct SetUserPasswordRequest {
    #[serde(rename = "userId")]
    #[validate(length(min = 1, message = "userId is required"))]
    pub user_id: String,
    #[serde(rename = "newPassword")]
    #[validate(length(min = 1, message = "newPassword is required"))]
    pub new_password: String,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct HasPermissionRequest {
    pub permission: Option<serde_json::Value>,
    pub permissions: Option<serde_json::Value>,
    #[serde(default, rename = "grantKeys")]
    pub grant_keys: Vec<String>,
    #[serde(default, rename = "rightKeys")]
    pub right_keys: Vec<String>,
    #[serde(
        default,
        rename = "rightModules",
        alias = "grantModules",
        alias = "nativeRightModules"
    )]
    pub right_modules: Vec<NativeRightModuleInput>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct ListGrantAssignmentsQueryParams {
    #[serde(rename = "subjectKind")]
    #[validate(length(min = 1, message = "subjectKind is required"))]
    pub subject_kind: String,
    #[serde(rename = "subjectId")]
    #[validate(length(min = 1, message = "subjectId is required"))]
    pub subject_id: String,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct ReplaceGrantAssignmentsForSourceRequest {
    #[serde(rename = "subjectKind")]
    #[validate(length(min = 1, message = "subjectKind is required"))]
    pub subject_kind: String,
    #[serde(rename = "subjectId")]
    #[validate(length(min = 1, message = "subjectId is required"))]
    pub subject_id: String,
    #[serde(rename = "sourceKind")]
    #[validate(length(min = 1, message = "sourceKind is required"))]
    pub source_kind: String,
    #[serde(rename = "sourceRef")]
    #[validate(length(min = 1, message = "sourceRef is required"))]
    pub source_ref: String,
    #[serde(default, rename = "grantKeys")]
    pub grant_keys: Vec<String>,
    #[serde(default, rename = "rightKeys")]
    pub right_keys: Vec<String>,
    #[serde(
        default,
        rename = "rightModules",
        alias = "grantModules",
        alias = "nativeRightModules"
    )]
    pub right_modules: Vec<NativeRightModuleInput>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct SyncBillingGrantAssignmentsRequest {
    #[serde(rename = "subjectKind")]
    #[validate(length(min = 1, message = "subjectKind is required"))]
    pub subject_kind: String,
    #[serde(rename = "subjectId")]
    #[validate(length(min = 1, message = "subjectId is required"))]
    pub subject_id: String,
    #[serde(rename = "sourceKind")]
    #[validate(length(min = 1, message = "sourceKind is required"))]
    pub source_kind: String,
    #[serde(rename = "sourceRef")]
    #[validate(length(min = 1, message = "sourceRef is required"))]
    pub source_ref: String,
    #[serde(default, rename = "grantKeys")]
    pub grant_keys: Vec<String>,
    #[serde(default, rename = "rightKeys")]
    pub right_keys: Vec<String>,
    #[serde(
        default,
        rename = "rightModules",
        alias = "grantModules",
        alias = "nativeRightModules"
    )]
    pub right_modules: Vec<NativeRightModuleInput>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct SyncGrantAssignmentsRequest {
    #[serde(rename = "subjectKind")]
    #[validate(length(min = 1, message = "subjectKind is required"))]
    pub subject_kind: String,
    #[serde(rename = "subjectId")]
    #[validate(length(min = 1, message = "subjectId is required"))]
    pub subject_id: String,
    #[serde(rename = "sourceKind")]
    #[validate(length(min = 1, message = "sourceKind is required"))]
    pub source_kind: String,
    #[serde(rename = "sourceRef")]
    #[validate(length(min = 1, message = "sourceRef is required"))]
    pub source_ref: String,
    #[serde(default, rename = "grantKeys")]
    pub grant_keys: Vec<String>,
    #[serde(default, rename = "rightKeys")]
    pub right_keys: Vec<String>,
    #[serde(
        default,
        rename = "rightModules",
        alias = "grantModules",
        alias = "nativeRightModules"
    )]
    pub right_modules: Vec<NativeRightModuleInput>,
    pub metadata: Option<serde_json::Value>,
}

pub(crate) type ReplaceNativeRightAssignmentsForSourceRequest =
    ReplaceGrantAssignmentsForSourceRequest;
pub(crate) type SyncNativeRightAssignmentsRequest = SyncGrantAssignmentsRequest;
pub(crate) type SyncBillingRightAssignmentsRequest = SyncBillingGrantAssignmentsRequest;

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct CreateAdminApiKeyRequest {
    pub name: Option<String>,
    #[serde(rename = "expiresIn")]
    pub expires_in: Option<i64>,
    #[serde(rename = "athenaClientName")]
    pub athena_client_name: Option<String>,
    pub permissions: Option<serde_json::Value>,
    #[serde(default, rename = "grantKeys")]
    pub grant_keys: Option<Vec<String>>,
    #[serde(default, rename = "rightKeys")]
    pub right_keys: Option<Vec<String>>,
    #[serde(
        default,
        rename = "rightModules",
        alias = "grantModules",
        alias = "nativeRightModules"
    )]
    pub right_modules: Option<Vec<NativeRightModuleInput>>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct CreateAthenaClientRequest {
    #[serde(rename = "clientName")]
    #[validate(length(min = 1, message = "clientName is required"))]
    pub client_name: String,
    pub description: Option<String>,
    #[serde(rename = "isActive")]
    pub is_active: Option<bool>,
    #[serde(rename = "pgUriEnvVar")]
    pub pg_uri_env_var: Option<String>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct CreateOAuthClientRequest {
    #[serde(rename = "clientName")]
    #[validate(length(min = 1, message = "clientName is required"))]
    pub client_name: String,
    #[validate(length(min = 1, message = "provider is required"))]
    pub provider: String,
    pub description: Option<String>,
    #[serde(rename = "responseType")]
    pub response_type: Option<String>,
    #[serde(rename = "grantType")]
    pub grant_type: Option<String>,
    #[serde(rename = "tokenAuthenticationMethod")]
    pub token_authentication_method: Option<String>,
    #[serde(rename = "redirectUris")]
    #[validate(length(min = 1, message = "redirectUris must contain at least one URI"))]
    pub redirect_uris: Vec<String>,
    #[serde(rename = "clientUrl")]
    pub client_url: Option<String>,
    pub scopes: Option<Vec<String>>,
    #[serde(rename = "isActive")]
    pub is_active: Option<bool>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize)]
pub(crate) struct ListAuditLogsQueryParams {
    pub limit: Option<usize>,
    pub offset: Option<usize>,
    #[serde(rename = "actorUserId")]
    pub actor_user_id: Option<String>,
    pub action: Option<String>,
    #[serde(rename = "targetType")]
    pub target_type: Option<String>,
    #[serde(rename = "targetId")]
    pub target_id: Option<String>,
    pub success: Option<bool>,
    #[serde(rename = "createdAfter")]
    pub created_after: Option<String>,
    #[serde(rename = "createdBefore")]
    pub created_before: Option<String>,
}

#[derive(Debug, Deserialize)]
pub(crate) struct ListSentEmailsQueryParams {
    pub limit: Option<usize>,
    pub offset: Option<usize>,
    #[serde(rename = "recipientEmail")]
    pub recipient_email: Option<String>,
    pub provider: Option<String>,
    pub flow: Option<String>,
    #[serde(rename = "subjectContains")]
    pub subject_contains: Option<String>,
    #[serde(rename = "createdAfter")]
    pub created_after: Option<String>,
    #[serde(rename = "createdBefore")]
    pub created_before: Option<String>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct GetSentEmailQueryParams {
    #[validate(length(min = 1, message = "id is required"))]
    pub id: String,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct CreateSentEmailRequest {
    #[serde(rename = "recipientEmail")]
    #[validate(length(min = 1, message = "recipientEmail is required"))]
    #[validate(email(message = "Invalid recipientEmail"))]
    pub recipient_email: String,
    #[validate(length(min = 1, message = "subject is required"))]
    pub subject: String,
    #[serde(rename = "fromAddress")]
    #[validate(length(min = 1, message = "fromAddress is required"))]
    #[validate(email(message = "Invalid fromAddress"))]
    pub from_address: String,
    #[serde(rename = "fromName")]
    pub from_name: Option<String>,
    #[serde(rename = "textBody")]
    pub text_body: Option<String>,
    #[serde(rename = "htmlBody")]
    pub html_body: Option<String>,
    #[validate(length(min = 1, message = "provider is required"))]
    pub provider: String,
    pub flow: Option<String>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct UpdateSentEmailRequest {
    #[validate(length(min = 1, message = "id is required"))]
    pub id: String,
    #[serde(rename = "recipientEmail")]
    #[validate(email(message = "Invalid recipientEmail"))]
    pub recipient_email: Option<String>,
    pub subject: Option<String>,
    #[serde(rename = "fromAddress")]
    #[validate(email(message = "Invalid fromAddress"))]
    pub from_address: Option<String>,
    #[serde(
        rename = "fromName",
        default,
        deserialize_with = "deserialize_nullable_string_patch"
    )]
    pub from_name: Option<Option<String>>,
    #[serde(
        rename = "textBody",
        default,
        deserialize_with = "deserialize_nullable_string_patch"
    )]
    pub text_body: Option<Option<String>>,
    #[serde(
        rename = "htmlBody",
        default,
        deserialize_with = "deserialize_nullable_string_patch"
    )]
    pub html_body: Option<Option<String>>,
    pub provider: Option<String>,
    #[serde(
        rename = "flow",
        default,
        deserialize_with = "deserialize_nullable_string_patch"
    )]
    pub flow: Option<Option<String>>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct DeleteSentEmailRequest {
    #[validate(length(min = 1, message = "id is required"))]
    pub id: String,
}

#[derive(Debug, Deserialize)]
pub(crate) struct ListEmailSendFailuresQueryParams {
    pub limit: Option<usize>,
    pub offset: Option<usize>,
    #[serde(rename = "recipientEmail")]
    pub recipient_email: Option<String>,
    pub provider: Option<String>,
    pub flow: Option<String>,
    pub resolved: Option<bool>,
    #[serde(rename = "createdAfter")]
    pub created_after: Option<String>,
    #[serde(rename = "createdBefore")]
    pub created_before: Option<String>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct CreateEmailSendFailureRequest {
    #[serde(rename = "userId")]
    pub user_id: Option<String>,
    #[serde(rename = "recipientEmail")]
    #[validate(length(min = 1, message = "recipientEmail is required"))]
    #[validate(email(message = "Invalid recipientEmail"))]
    pub recipient_email: String,
    #[validate(length(min = 1, message = "flow is required"))]
    pub flow: String,
    pub provider: Option<String>,
    #[serde(rename = "errorMessage")]
    #[validate(length(min = 1, message = "errorMessage is required"))]
    pub error_message: String,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct GetEmailSendFailureQueryParams {
    #[validate(length(min = 1, message = "id is required"))]
    pub id: String,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct UpdateEmailSendFailureRequest {
    #[validate(length(min = 1, message = "id is required"))]
    pub id: String,
    pub resolved: Option<bool>,
    #[serde(
        rename = "resolutionNote",
        default,
        deserialize_with = "deserialize_nullable_string_patch"
    )]
    pub resolution_note: Option<Option<String>>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct DeleteEmailSendFailureRequest {
    #[validate(length(min = 1, message = "id is required"))]
    pub id: String,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct CreateEmailTemplateRequest {
    #[serde(alias = "templateKey")]
    #[validate(length(min = 1, message = "template_key is required"))]
    pub template_key: String,
    #[serde(alias = "eventType")]
    pub event_type: Option<String>,
    pub locale: Option<String>,
    #[serde(alias = "subjectTemplate")]
    #[validate(length(min = 1, message = "subject_template is required"))]
    pub subject_template: String,
    #[serde(alias = "textTemplate")]
    pub text_template: Option<String>,
    #[serde(alias = "htmlTemplate")]
    pub html_template: Option<String>,
    pub variables: Option<serde_json::Value>,
    #[serde(alias = "variableBindings")]
    pub variable_bindings: Option<serde_json::Value>,
    pub attachments: Option<serde_json::Value>,
    #[serde(alias = "attachmentFailureMode")]
    pub attachment_failure_mode: Option<String>,
    #[serde(alias = "isActive")]
    pub is_active: Option<bool>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct UpdateEmailTemplateRequest {
    #[validate(length(min = 1, message = "id is required"))]
    pub id: String,
    #[serde(alias = "templateKey")]
    pub template_key: Option<String>,
    /// `null` clears the value, omitted keeps existing.
    #[serde(
        alias = "eventType",
        default,
        deserialize_with = "deserialize_nullable_string_patch"
    )]
    pub event_type: Option<Option<String>>,
    pub locale: Option<String>,
    #[serde(alias = "subjectTemplate")]
    pub subject_template: Option<String>,
    /// `null` clears the value, omitted keeps existing.
    #[serde(
        alias = "textTemplate",
        default,
        deserialize_with = "deserialize_nullable_string_patch"
    )]
    pub text_template: Option<Option<String>>,
    /// `null` clears the value, omitted keeps existing.
    #[serde(
        alias = "htmlTemplate",
        default,
        deserialize_with = "deserialize_nullable_string_patch"
    )]
    pub html_template: Option<Option<String>>,
    pub variables: Option<serde_json::Value>,
    #[serde(alias = "variableBindings")]
    pub variable_bindings: Option<serde_json::Value>,
    #[serde(
        alias = "attachments",
        default,
        deserialize_with = "deserialize_nullable_json_patch"
    )]
    pub attachments: Option<Option<serde_json::Value>>,
    #[serde(
        alias = "attachmentFailureMode",
        default,
        deserialize_with = "deserialize_nullable_string_patch"
    )]
    pub attachment_failure_mode: Option<Option<String>>,
    #[serde(alias = "isActive")]
    pub is_active: Option<bool>,
    pub metadata: Option<serde_json::Value>,
}

fn deserialize_nullable_string_patch<'de, D>(
    deserializer: D,
) -> Result<Option<Option<String>>, D::Error>
where
    D: serde::Deserializer<'de>,
{
    let value = serde_json::Value::deserialize(deserializer)?;
    match value {
        serde_json::Value::Null => Ok(Some(None)),
        serde_json::Value::String(text) => Ok(Some(Some(text))),
        other => Err(serde::de::Error::custom(format!(
            "expected string or null, got {other}"
        ))),
    }
}

fn deserialize_nullable_json_patch<'de, D>(
    deserializer: D,
) -> Result<Option<Option<serde_json::Value>>, D::Error>
where
    D: serde::Deserializer<'de>,
{
    let value = serde_json::Value::deserialize(deserializer)?;
    match value {
        serde_json::Value::Null => Ok(Some(None)),
        other => Ok(Some(Some(other))),
    }
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct DeleteEmailTemplateRequest {
    #[validate(length(min = 1, message = "id is required"))]
    pub id: String,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct SendEmailTemplateRequest {
    #[serde(alias = "templateId")]
    #[validate(length(min = 1, message = "template_id is required"))]
    pub template_id: String,
    #[serde(alias = "recipientEmail")]
    #[validate(length(min = 1, message = "recipient_email is required"))]
    #[validate(email(message = "Invalid recipient_email"))]
    pub recipient_email: String,
    #[serde(alias = "renderVariables")]
    pub render_variables: Option<serde_json::Value>,
    #[serde(alias = "userId")]
    pub user_id: Option<String>,
    #[serde(alias = "organizationId")]
    pub organization_id: Option<String>,
    #[serde(alias = "sessionToken")]
    pub session_token: Option<String>,
    pub attachments: Option<serde_json::Value>,
    #[serde(alias = "attachmentFailureMode")]
    pub attachment_failure_mode: Option<String>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Deserialize, Validate)]
pub(crate) struct GetEmailTemplateQueryParams {
    #[validate(length(min = 1, message = "id is required"))]
    pub id: String,
}

#[derive(Debug, Deserialize)]
pub(crate) struct ListEmailTemplatesQueryParams {
    pub limit: Option<usize>,
    pub offset: Option<usize>,
    pub template_key: Option<String>,
    pub event_type: Option<String>,
    pub locale: Option<String>,
    pub is_active: Option<bool>,
}

#[derive(Debug, Deserialize)]
pub(crate) struct ListEmailEventTypesQueryParams {
    pub limit: Option<usize>,
    pub offset: Option<usize>,
    #[serde(rename = "eventType")]
    pub event_type: Option<String>,
    pub category: Option<String>,
    #[serde(rename = "isActive")]
    pub is_active: Option<bool>,
    #[serde(rename = "isSystem")]
    pub is_system: Option<bool>,
}

// ---------------------------------------------------------------------------
// Response types
// ---------------------------------------------------------------------------

#[derive(Debug, Serialize)]
pub(crate) struct UserResponse<U: Serialize> {
    pub user: U,
}

#[derive(Debug, Serialize)]
pub(crate) struct SessionUserResponse<S: Serialize, U: Serialize> {
    pub session: SessionWithServerVersion<S>,
    pub user: U,
}

#[derive(Debug, Serialize)]
pub(crate) struct ListUsersResponse<U: Serialize> {
    pub users: Vec<U>,
    pub total: usize,
    pub limit: usize,
    pub offset: usize,
}

#[derive(Debug, Serialize)]
pub(crate) struct ListSessionsResponse<S: Serialize> {
    pub sessions: Vec<SessionWithServerVersion<S>>,
}

#[derive(Debug, Serialize)]
pub(crate) struct SuccessResponse {
    pub success: bool,
}

#[derive(Debug, Serialize)]
pub(crate) struct PermissionResponse {
    pub success: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error: Option<String>,
}

#[derive(Debug, Serialize)]
pub(crate) struct GrantCatalogModuleResponse {
    pub key: String,
    #[serde(rename = "grantCatalog")]
    pub grant_catalog: Vec<crate::plugins::grants::GrantCatalogEntry>,
    #[serde(rename = "rightsCatalog")]
    pub rights_catalog: Vec<crate::plugins::grants::GrantCatalogEntry>,
    #[serde(rename = "nativeRightCatalog")]
    pub native_right_catalog: Vec<crate::plugins::grants::NativeRightCatalogEntry>,
    #[serde(rename = "nativeRights")]
    pub native_rights: Vec<athena_rights::AthenaRightDescriptor>,
    #[serde(
        rename = "integrationContract",
        skip_serializing_if = "Option::is_none"
    )]
    pub integration_contract: Option<serde_json::Value>,
}

#[derive(Debug, Serialize)]
pub(crate) struct GrantCatalogResponse {
    #[serde(rename = "grantCatalog")]
    pub grant_catalog: Vec<crate::plugins::grants::GrantCatalogEntry>,
    #[serde(rename = "rightsCatalog")]
    pub rights_catalog: Vec<crate::plugins::grants::GrantCatalogEntry>,
    #[serde(rename = "nativeRightCatalog")]
    pub native_right_catalog: Vec<crate::plugins::grants::NativeRightCatalogEntry>,
    #[serde(rename = "nativeRights")]
    pub native_rights: Vec<athena_rights::AthenaRightDescriptor>,
    #[serde(rename = "integrationContracts")]
    pub integration_contracts: std::collections::BTreeMap<String, serde_json::Value>,
    #[serde(rename = "catalogModules")]
    pub catalog_modules: Vec<GrantCatalogModuleResponse>,
}

#[derive(Debug, Serialize)]
pub(crate) struct SubjectGrantAssignmentsResponse {
    #[serde(rename = "subjectKind")]
    pub subject_kind: String,
    #[serde(rename = "subjectId")]
    pub subject_id: String,
    #[serde(rename = "grantKeys")]
    pub grant_keys: Vec<String>,
    #[serde(rename = "rightKeys")]
    pub right_keys: Vec<String>,
    #[serde(rename = "rightModules")]
    pub right_modules: Vec<NativeRightModuleInput>,
    #[serde(rename = "nativeRightModules")]
    pub native_right_modules: Vec<athena_rights::AthenaRightModule>,
    #[serde(rename = "grantAssignments")]
    pub grant_assignments: Vec<athena_auth_core::GrantAssignment>,
    #[serde(rename = "rightAssignments")]
    pub right_assignments: Vec<athena_auth_core::GrantAssignment>,
    #[serde(rename = "resolvedGrants")]
    pub resolved_grants: Vec<crate::plugins::grants::ResolvedGrantAssignmentView>,
    #[serde(rename = "resolvedRights")]
    pub resolved_rights: Vec<crate::plugins::grants::ResolvedGrantAssignmentView>,
    #[serde(rename = "resolvedNativeRights")]
    pub resolved_native_rights: Vec<crate::plugins::grants::ResolvedNativeRightAssignmentView>,
    #[serde(rename = "nativeRights")]
    pub native_rights: Vec<athena_rights::AthenaRightDescriptor>,
    #[serde(rename = "nativeRightAssignments")]
    pub native_right_assignments: Vec<crate::plugins::grants::NativeRightAssignmentView>,
    pub permissions: HashMap<String, Vec<String>>,
    #[serde(rename = "unknownGrantKeys")]
    pub unknown_grant_keys: Vec<String>,
    #[serde(rename = "unknownRightKeys")]
    pub unknown_right_keys: Vec<String>,
}

#[derive(Debug, Serialize)]
pub(crate) struct ReplaceGrantAssignmentsForSourceResponse {
    #[serde(rename = "subjectKind")]
    pub subject_kind: String,
    #[serde(rename = "subjectId")]
    pub subject_id: String,
    #[serde(rename = "sourceKind")]
    pub source_kind: String,
    #[serde(rename = "sourceRef")]
    pub source_ref: String,
    #[serde(rename = "appliedGrantKeys")]
    pub applied_grant_keys: Vec<String>,
    #[serde(rename = "appliedRightKeys")]
    pub applied_right_keys: Vec<String>,
    #[serde(rename = "appliedRightModules")]
    pub applied_right_modules: Vec<NativeRightModuleInput>,
    #[serde(rename = "appliedNativeRightModules")]
    pub applied_native_right_modules: Vec<athena_rights::AthenaRightModule>,
    #[serde(rename = "replacedAssignments")]
    pub replaced_assignments: Vec<athena_auth_core::GrantAssignment>,
    #[serde(rename = "replacedNativeRightAssignments")]
    pub replaced_native_right_assignments: Vec<crate::plugins::grants::NativeRightAssignmentView>,
    #[serde(rename = "subjectState")]
    pub subject_state: SubjectGrantAssignmentsResponse,
}

pub(crate) type ReplaceNativeRightAssignmentsForSourceResponse =
    ReplaceGrantAssignmentsForSourceResponse;

#[derive(Debug, Serialize)]
pub(crate) struct AdminApiKeyView {
    pub id: String,
    pub name: Option<String>,
    #[serde(rename = "userId")]
    pub user_id: String,
    pub prefix: Option<String>,
    pub enabled: bool,
    #[serde(rename = "expiresAt")]
    pub expires_at: Option<String>,
    #[serde(rename = "createdAt")]
    pub created_at: String,
    pub permissions: Option<serde_json::Value>,
    #[serde(rename = "grantKeys")]
    pub grant_keys: Vec<String>,
    #[serde(rename = "rightKeys")]
    pub right_keys: Vec<String>,
    #[serde(rename = "rightModules")]
    pub right_modules: Vec<NativeRightModuleInput>,
    #[serde(rename = "nativeRightModules")]
    pub native_right_modules: Vec<athena_rights::AthenaRightModule>,
    #[serde(rename = "nativeRights")]
    pub native_rights: Vec<athena_rights::AthenaRightDescriptor>,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Serialize)]
pub(crate) struct CreateAdminApiKeyResponse {
    pub key: String,
    #[serde(rename = "apiKey")]
    pub api_key: AdminApiKeyView,
}

#[derive(Debug, Serialize)]
pub(crate) struct AthenaClientsResponse {
    #[serde(rename = "athenaClients")]
    pub athena_clients: Vec<athena_auth_core::AthenaClient>,
}

#[derive(Debug, Serialize)]
pub(crate) struct OAuthClientsResponse {
    #[serde(rename = "oauthClients")]
    pub oauth_clients: Vec<athena_auth_core::OAuthClient>,
}

#[derive(Debug, Serialize)]
pub(crate) struct AuditLogsResponse {
    #[serde(rename = "auditLogs")]
    pub audit_logs: Vec<athena_auth_core::AdminAuditLog>,
    pub total: usize,
    pub limit: usize,
    pub offset: usize,
}

#[derive(Debug, Serialize)]
pub(crate) struct SentEmailsResponse {
    pub emails: Vec<athena_auth_core::SentEmail>,
    pub total: usize,
    pub limit: usize,
    pub offset: usize,
}

#[derive(Debug, Serialize)]
pub(crate) struct SentEmailResponse {
    pub email: athena_auth_core::SentEmail,
}

#[derive(Debug, Serialize)]
pub(crate) struct EmailSendFailuresResponse {
    #[serde(rename = "emailSendFailures")]
    pub email_send_failures: Vec<athena_auth_core::EmailSendFailure>,
    pub total: usize,
    pub limit: usize,
    pub offset: usize,
}

#[derive(Debug, Serialize)]
pub(crate) struct EmailSendFailureResponse {
    #[serde(rename = "emailSendFailure")]
    pub email_send_failure: athena_auth_core::EmailSendFailure,
}

#[derive(Debug, Serialize)]
pub(crate) struct EmailTemplateApiResponse {
    pub id: String,
    pub template_key: String,
    pub event_type: Option<String>,
    pub locale: String,
    pub subject_template: String,
    pub text_template: Option<String>,
    pub html_template: Option<String>,
    pub variables: serde_json::Value,
    pub variable_bindings: serde_json::Value,
    pub attachments: serde_json::Value,
    pub attachment_failure_mode: String,
    pub is_active: bool,
    pub metadata: serde_json::Value,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

impl From<athena_auth_core::EmailTemplate> for EmailTemplateApiResponse {
    fn from(value: athena_auth_core::EmailTemplate) -> Self {
        Self {
            id: value.id,
            template_key: value.template_key,
            event_type: value.event_type,
            locale: value.locale,
            subject_template: value.subject_template,
            text_template: value.text_template,
            html_template: value.html_template,
            variables: value.variables,
            variable_bindings: value.variable_bindings,
            attachments: value.attachments,
            attachment_failure_mode: value.attachment_failure_mode,
            is_active: value.is_active,
            metadata: value.metadata,
            created_at: value.created_at,
            updated_at: value.updated_at,
        }
    }
}

#[derive(Debug, Serialize)]
pub(crate) struct EmailTemplatesResponse {
    pub email_templates: Vec<EmailTemplateApiResponse>,
    pub total: usize,
    pub limit: usize,
    pub offset: usize,
}

#[derive(Debug, Serialize)]
pub(crate) struct EmailTemplateResponse {
    pub email_template: EmailTemplateApiResponse,
}

#[derive(Debug, Serialize)]
pub(crate) struct SendEmailTemplateResponse {
    pub success: bool,
    pub flow: String,
    pub template_id: String,
    pub template_key: String,
    pub event_type: Option<String>,
    pub recipient_email: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub subject: Option<String>,
    pub attachment_count: usize,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub delivery_metadata: Option<serde_json::Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub email_send_failure_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error: Option<String>,
}

#[derive(Debug, Serialize)]
pub(crate) struct EmailEventTypesResponse {
    #[serde(rename = "emailEventTypes")]
    pub email_event_types: Vec<athena_auth_core::EmailEventType>,
    pub total: usize,
    pub limit: usize,
    pub offset: usize,
}

/// Query parameters for `list_users`.
#[derive(Debug, Deserialize)]
pub(crate) struct ListUsersQueryParams {
    pub limit: Option<usize>,
    pub offset: Option<usize>,
    #[serde(rename = "searchField")]
    pub search_field: Option<String>,
    #[serde(rename = "searchValue")]
    pub search_value: Option<String>,
    #[serde(rename = "searchOperator")]
    pub search_operator: Option<String>,
    #[serde(rename = "sortBy")]
    pub sort_by: Option<String>,
    #[serde(rename = "sortDirection")]
    pub sort_direction: Option<String>,
    #[serde(rename = "filterField")]
    pub filter_field: Option<String>,
    #[serde(rename = "filterValue")]
    pub filter_value: Option<String>,
    #[serde(rename = "filterOperator")]
    pub filter_operator: Option<String>,
}
