use ::chrono::Utc;
use rocket::serde::Serialize;
use rocket_db_pools::{Connection, Database};
use sqlx::{
	pool::PoolConnection,
	types::{chrono, Uuid},
	Postgres, Transaction,
};

#[derive(Database)]
#[database("dolltags")]
pub struct DollTags(sqlx::PgPool);
pub type DollTagsDb = Connection<DollTags>;
pub type DbHook = PoolConnection<Postgres>;
pub type TrxHook<'a> = Transaction<'a, Postgres>;

// Doll Profiles stuff
#[derive(Debug, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct DollProfile {
	pub id: i32,
	pub microchip_id: Option<String>,
	pub created_at: chrono::DateTime<Utc>,
	pub updated_at: Option<chrono::DateTime<Utc>>,
	pub archived_at: Option<chrono::DateTime<Utc>>,

	pub bound_to_id: Uuid,

	pub name: String,
	pub pronoun_subject: String,
	pub pronoun_object: String,
	pub pronoun_possessive: String,
	pub handler_name: String,
	pub handler_link: Option<String>,

	pub kind: Option<String>,
	pub breed: Option<String>,
	pub behaviour: Option<String>,
	pub description: Option<String>,
	pub chassis_type: Option<String>,
	pub chassis_id: Option<String>,
	pub chassis_color: Option<String>,
}

impl DollProfile {
	pub fn has_notable_traits(&self) -> bool {
		self.kind.is_some()
			|| self.breed.is_some()
			|| self.behaviour.is_some()
			|| self.chassis_type.is_some()
			|| self.chassis_id.is_some()
			|| self.chassis_color.is_some()
	}
}

#[derive(Debug)]
pub struct CreateDollProfile<'a> {
	pub id: i32,
	pub microchip_id: Option<&'a str>,
	pub bound_to_id: &'a Uuid,

	pub name: &'a str,
	pub pronoun_subject: &'a str,
	pub pronoun_object: &'a str,
	pub pronoun_possessive: &'a str,
	pub handler_name: &'a str,
	pub handler_link: Option<&'a str>,

	pub kind: Option<&'a str>,
	pub breed: Option<&'a str>,
	pub behaviour: Option<&'a str>,
	pub description: Option<&'a str>,
	pub chassis_type: Option<&'a str>,
	pub chassis_id: Option<&'a str>,
	pub chassis_color: Option<&'a str>,
}

/// A user
///
/// This type implements [`FromRequest`][rocket::request::FromRequest],
/// using it as a guard is the safe way to verify that the user is logged in
/// and that they can be logged in.
///
/// If you only need to check the login status without any security impact
/// (e.g. for page template rendering reasons), use [`Session`][crate::auth::session::Session] instead.
#[derive(Debug, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct User {
	pub id: Uuid,
	pub created_at: chrono::DateTime<Utc>,
	pub updated_at: Option<chrono::DateTime<Utc>>,

	pub username: String,
	pub password: String,
	pub email: Option<String>,

	pub enabled: bool,
	pub is_admin: bool,
}

/// The service status aggregate
#[derive(Debug, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct ServiceStatus {
	pub active_accounts_count: i64,
	pub active_tags_count: i64,
}
