use std::fmt::{self, Debug, Display, Formatter};
use chrono::NaiveDateTime;
use serde::Deserialize;
#[allow(unused_imports)] use crate::session::{SalesVia, Session, SessionStatus, ShowType};
use crate::{client::Client, error::ApiResult, session::SessionList};
#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
#[serde(rename_all = "PascalCase")]
pub enum FilmStatus {
Active,
Inactive,
Deleted,
}
#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
pub enum FilmFormat {
#[serde(rename = "2D Film")]
Film2D,
#[serde(rename = "2D Digital")]
Digital2D,
#[serde(rename = "3D Digital")]
Digital3D,
#[serde(rename = "3D HFR")]
Digital3DHFR,
#[serde(rename = "Not a Film")]
NotAFilm,
}
#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Hash)]
#[serde(transparent)]
pub struct PersonId(String);
impl PersonId {
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl Display for PersonId {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Hash)]
#[serde(rename_all = "PascalCase")]
pub struct Person {
pub id: PersonId,
pub first_name: String,
pub last_name: String,
pub role: String,
}
#[derive(Deserialize, Debug, PartialEq, Eq, Clone, Hash)]
#[serde(transparent)]
pub struct FilmId(String);
impl FilmId {
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
pub async fn fetch(&self, client: &Client) -> ApiResult<Film> {
client.get_film(self).await
}
}
impl Display for FilmId {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Deserialize, Debug, PartialEq, Eq, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct Film {
pub id: FilmId,
pub title: String,
pub short_name: String,
pub synopsis: Option<String>,
pub genre: String,
pub signage_text: String,
pub distributor: String,
pub opening_date: NaiveDateTime,
pub rating: Option<String>,
pub status: FilmStatus,
pub content: Option<String>,
pub duration: u32,
pub display_sequence: u32,
pub national_code: Option<String>,
pub format: FilmFormat,
pub is_restricted: bool,
pub people: Vec<Person>,
pub audio_language: Option<String>,
pub government_film_title: Option<String>,
pub film_poster_url: Option<String>,
pub film_poster_thumbnail_url: String,
pub backdrop_image_url: Option<String>,
pub film_trailer_url: Option<String>,
}
impl Film {
pub async fn sessions(&self, client: &Client) -> ApiResult<SessionList> {
Ok(client.list_sessions().await?.filter_by_film(&self.id))
}
pub async fn web_sessions(&self, client: &Client) -> ApiResult<SessionList> {
Ok(client.list_web_sessions().await?.filter_by_film(&self.id))
}
#[must_use]
pub fn formatted_duration(&self) -> String {
let hours = self.duration / 60;
let minutes = self.duration % 60;
if minutes == 0 {
format!("{hours}h")
} else {
format!("{hours}h {minutes}m")
}
}
}