/*
    This file is part of jellything (https://codeberg.org/metamuffin/jellything)
    which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
    Copyright (C) 2026 metamuffin <metamuffin.org>
*/
use serde::{Deserialize, Serialize};
use std::{
    collections::{HashMap, HashSet},
    fmt::Display,
};

#[rustfmt::skip]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct User {
    pub name: String,
    pub display_name: String,
    pub password: Vec<u8>,
    pub admin: bool,
    #[serde(default)] pub theme: Theme,
    #[serde(default)] pub player_preference: PlayerKind,
    #[serde(default)] pub native_secret: String,
    pub permissions: PermissionSet,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeUserData {
    pub watched: WatchedState,
    #[serde(default)]
    pub rating: i32,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum WatchedState {
    None,
    Progress(f64),
    Watched,
    Pending,
}

url_enum!(
    #[derive(Debug, Clone, Serialize, Deserialize)]
    #[serde(rename_all = "snake_case")]
    enum ApiWatchedState {
        None = "none",
        Watched = "watched",
        Pending = "pending",
    }
);

#[derive(Debug, Serialize, Deserialize)]
pub struct CreateSessionParams {
    pub username: String,
    pub password: String,
    pub expire: Option<i64>,
    pub drop_permissions: Option<HashSet<UserPermission>>,
}

url_enum!(
    #[derive(Debug, Clone, Copy, Serialize, Default, Deserialize, PartialEq)]
    #[serde(rename_all = "snake_case")]
    enum Theme {
        #[default]
        Dark = "dark",
        Light = "light",
        Purple = "purple",
        Black = "black",
    }
);

url_enum!(
    #[derive(Debug, Clone, Copy, Serialize, Default, Deserialize, PartialEq)]
    #[serde(rename_all = "snake_case")]
    enum PlayerKind {
        #[default]
        Browser = "browser",
        Native = "native",
        NativeFullscreen = "native_fullscreen",
    }
);

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PermissionSet(pub HashMap<UserPermission, bool>);

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum UserPermission {
    Admin,
    // ManageUsers,
    // GenerateInvite,
    ManageSelf,

    AccessNode(String),
    Transcode,
    FederatedContent,
}

impl UserPermission {
    pub const ALL_ENUMERABLE: &'static [UserPermission] = {
        use UserPermission::*;
        &[Admin, Transcode, ManageSelf, FederatedContent]
    };
    pub fn default_value(&self) -> bool {
        use UserPermission::*;
        matches!(self, Transcode | ManageSelf | FederatedContent)
    }
}

impl Display for UserPermission {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&match self {
            UserPermission::ManageSelf => "manage self (password, display name, etc.)".to_string(),
            UserPermission::FederatedContent => "access to federated content".to_string(),
            UserPermission::Admin => "administrative rights".to_string(),
            // UserPermission::StreamFormat(StreamFormat::Original) => {
            //     "downloading the original media".to_string()
            // }
            // UserPermission::StreamFormat(StreamFormat::Matroska) => {
            //     "downloading a remuxed WebM/Matroska version of the media ".to_string()
            // }
            // UserPermission::StreamFormat(x) => {
            //     format!("downloading media via {x:?}")
            // }
            UserPermission::Transcode => "transcoding".to_string(),
            // UserPermission::ManageUsers => format!("management of all users"),
            // UserPermission::GenerateInvite => format!("inviting new users"),
            UserPermission::AccessNode(s) => format!("access to library node {s:?}"),
        })
    }
}

impl Default for NodeUserData {
    fn default() -> Self {
        Self {
            watched: WatchedState::None,
            rating: 0,
        }
    }
}
