use crate::model_ext::{AliasSuffixExt, EntityPrefixExt, MagIden, ModelPagination};
use crate::note_model::{INTERACTION_REACTION, INTERACTION_RENOTE, RENOTE, REPLY, USER};
use crate::user_model::UserData;
use chrono::{DateTime, Utc};
use ck::note;
use sea_orm::Iden;
use sea_orm::{DbErr, FromQueryResult, QueryResult};
use serde::{Deserialize, Serialize};

pub mod sub_interaction_renote {
    use sea_orm::{DeriveColumn, EnumIter, FromQueryResult};
    use serde::{Deserialize, Serialize};

    #[derive(Debug, Clone, PartialEq, Eq, FromQueryResult, Serialize, Deserialize)]
    pub struct Model {
        pub renotes: Option<i64>,
    }

    #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
    pub enum Column {
        Renotes,
    }
}

pub mod sub_interaction_reaction {
    use sea_orm::{DeriveColumn, EnumIter, FromQueryResult};
    use serde::{Deserialize, Serialize};

    #[derive(Debug, Clone, PartialEq, Eq, FromQueryResult, Serialize, Deserialize)]
    pub struct Model {
        pub reaction_name: Option<String>,
    }

    #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
    pub enum Column {
        ReactionName,
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NoteData {
    pub note: note::Model,
    pub interaction_user_renote: Option<sub_interaction_renote::Model>,
    pub interaction_user_reaction: Option<sub_interaction_reaction::Model>,
    pub user: UserData,
    pub reply: Option<Box<NoteData>>,
    pub renote: Option<Box<NoteData>>,
}

impl ModelPagination for NoteData {
    fn id(&self) -> &str {
        &self.note.id
    }

    fn time(&self) -> DateTime<Utc> {
        self.note.created_at.into()
    }
}

impl FromQueryResult for NoteData {
    fn from_query_result(res: &QueryResult, prefix: &str) -> Result<Self, DbErr> {
        let prefix = if prefix.is_empty() {
            note::Entity.base_prefix()
        } else {
            MagIden::alias(prefix)
        };

        Ok(NoteData {
            note: note::Model::from_query_result(res, &prefix.to_string())?,
            interaction_user_renote: sub_interaction_renote::Model::from_query_result_optional(
                res,
                &prefix.join_str_as_str(INTERACTION_RENOTE),
            )?,
            interaction_user_reaction: sub_interaction_reaction::Model::from_query_result_optional(
                res,
                &prefix.join_str_as_str(INTERACTION_REACTION),
            )?,
            user: UserData::from_query_result(res, &prefix.join_str_as_str(USER))?,
            reply: NoteData::from_query_result_optional(res, &prefix.join_str_as_str(REPLY))?
                .map(Box::new),
            renote: NoteData::from_query_result_optional(res, &prefix.join_str_as_str(RENOTE))?
                .map(Box::new),
        })
    }
}
