use crate::{DateTimeUtc, ProjectId, RepoId, UserId};
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};

/// All possible event types for project activity feed.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ActivityEventType {
    // Git / Repo
    CommitPush,
    BranchCreate,
    BranchDelete,
    BranchRename,
    TagCreate,
    TagDelete,
    RepoCreate,
    RepoUpdate,
    RepoDelete,
    RepoStar,
    RepoUnstar,
    RepoWatch,
    RepoUnwatch,
    // Issues
    IssueOpen,
    IssueClose,
    IssueReopen,
    IssueUpdate,
    IssueDelete,
    IssueComment,
    IssueLabelAdd,
    IssueLabelRemove,
    IssueAssigneeAdd,
    IssueAssigneeRemove,
    // Pull Requests
    PrOpen,
    PrMerge,
    PrClose,
    PrUpdate,
    PrReview,
    PrReviewComment,
    // Room
    RoomMessage,
    RoomCreate,
    RoomDelete,
    RoomUpdate,
    RoomPin,
    RoomThread,
    // Project
    ProjectStar,
    ProjectUnstar,
    ProjectWatch,
    ProjectUnwatch,
    MemberAdd,
    MemberRemove,
    MemberRoleChange,
    LabelCreate,
    LabelUpdate,
    LabelDelete,
}

impl std::fmt::Display for ActivityEventType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let s = match self {
            ActivityEventType::CommitPush => "commit_push",
            ActivityEventType::BranchCreate => "branch_create",
            ActivityEventType::BranchDelete => "branch_delete",
            ActivityEventType::BranchRename => "branch_rename",
            ActivityEventType::TagCreate => "tag_create",
            ActivityEventType::TagDelete => "tag_delete",
            ActivityEventType::RepoCreate => "repo_create",
            ActivityEventType::RepoUpdate => "repo_update",
            ActivityEventType::RepoDelete => "repo_delete",
            ActivityEventType::RepoStar => "repo_star",
            ActivityEventType::RepoUnstar => "repo_unstar",
            ActivityEventType::RepoWatch => "repo_watch",
            ActivityEventType::RepoUnwatch => "repo_unwatch",
            ActivityEventType::IssueOpen => "issue_open",
            ActivityEventType::IssueClose => "issue_close",
            ActivityEventType::IssueReopen => "issue_reopen",
            ActivityEventType::IssueUpdate => "issue_update",
            ActivityEventType::IssueDelete => "issue_delete",
            ActivityEventType::IssueComment => "issue_comment",
            ActivityEventType::IssueLabelAdd => "issue_label_add",
            ActivityEventType::IssueLabelRemove => "issue_label_remove",
            ActivityEventType::IssueAssigneeAdd => "issue_assignee_add",
            ActivityEventType::IssueAssigneeRemove => "issue_assignee_remove",
            ActivityEventType::PrOpen => "pr_open",
            ActivityEventType::PrMerge => "pr_merge",
            ActivityEventType::PrClose => "pr_close",
            ActivityEventType::PrUpdate => "pr_update",
            ActivityEventType::PrReview => "pr_review",
            ActivityEventType::PrReviewComment => "pr_review_comment",
            ActivityEventType::RoomMessage => "room_message",
            ActivityEventType::RoomCreate => "room_create",
            ActivityEventType::RoomDelete => "room_delete",
            ActivityEventType::RoomUpdate => "room_update",
            ActivityEventType::RoomPin => "room_pin",
            ActivityEventType::RoomThread => "room_thread",
            ActivityEventType::ProjectStar => "project_star",
            ActivityEventType::ProjectUnstar => "project_unstar",
            ActivityEventType::ProjectWatch => "project_watch",
            ActivityEventType::ProjectUnwatch => "project_unwatch",
            ActivityEventType::MemberAdd => "member_add",
            ActivityEventType::MemberRemove => "member_remove",
            ActivityEventType::MemberRoleChange => "member_role_change",
            ActivityEventType::LabelCreate => "label_create",
            ActivityEventType::LabelUpdate => "label_update",
            ActivityEventType::LabelDelete => "label_delete",
        };
        write!(f, "{}", s)
    }
}

impl std::str::FromStr for ActivityEventType {
    type Err = &'static str;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "commit_push" => Ok(ActivityEventType::CommitPush),
            "branch_create" => Ok(ActivityEventType::BranchCreate),
            "branch_delete" => Ok(ActivityEventType::BranchDelete),
            "branch_rename" => Ok(ActivityEventType::BranchRename),
            "tag_create" => Ok(ActivityEventType::TagCreate),
            "tag_delete" => Ok(ActivityEventType::TagDelete),
            "repo_create" => Ok(ActivityEventType::RepoCreate),
            "repo_update" => Ok(ActivityEventType::RepoUpdate),
            "repo_delete" => Ok(ActivityEventType::RepoDelete),
            "repo_star" => Ok(ActivityEventType::RepoStar),
            "repo_unstar" => Ok(ActivityEventType::RepoUnstar),
            "repo_watch" => Ok(ActivityEventType::RepoWatch),
            "repo_unwatch" => Ok(ActivityEventType::RepoUnwatch),
            "issue_open" => Ok(ActivityEventType::IssueOpen),
            "issue_close" => Ok(ActivityEventType::IssueClose),
            "issue_reopen" => Ok(ActivityEventType::IssueReopen),
            "issue_update" => Ok(ActivityEventType::IssueUpdate),
            "issue_delete" => Ok(ActivityEventType::IssueDelete),
            "issue_comment" => Ok(ActivityEventType::IssueComment),
            "issue_label_add" => Ok(ActivityEventType::IssueLabelAdd),
            "issue_label_remove" => Ok(ActivityEventType::IssueLabelRemove),
            "issue_assignee_add" => Ok(ActivityEventType::IssueAssigneeAdd),
            "issue_assignee_remove" => Ok(ActivityEventType::IssueAssigneeRemove),
            "pr_open" => Ok(ActivityEventType::PrOpen),
            "pr_merge" => Ok(ActivityEventType::PrMerge),
            "pr_close" => Ok(ActivityEventType::PrClose),
            "pr_update" => Ok(ActivityEventType::PrUpdate),
            "pr_review" => Ok(ActivityEventType::PrReview),
            "pr_review_comment" => Ok(ActivityEventType::PrReviewComment),
            "room_message" => Ok(ActivityEventType::RoomMessage),
            "room_create" => Ok(ActivityEventType::RoomCreate),
            "room_delete" => Ok(ActivityEventType::RoomDelete),
            "room_update" => Ok(ActivityEventType::RoomUpdate),
            "room_pin" => Ok(ActivityEventType::RoomPin),
            "room_thread" => Ok(ActivityEventType::RoomThread),
            "project_star" => Ok(ActivityEventType::ProjectStar),
            "project_unstar" => Ok(ActivityEventType::ProjectUnstar),
            "project_watch" => Ok(ActivityEventType::ProjectWatch),
            "project_unwatch" => Ok(ActivityEventType::ProjectUnwatch),
            "member_add" => Ok(ActivityEventType::MemberAdd),
            "member_remove" => Ok(ActivityEventType::MemberRemove),
            "member_role_change" => Ok(ActivityEventType::MemberRoleChange),
            "label_create" => Ok(ActivityEventType::LabelCreate),
            "label_update" => Ok(ActivityEventType::LabelUpdate),
            "label_delete" => Ok(ActivityEventType::LabelDelete),
            _ => Err("unknown activity event type"),
        }
    }
}

#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "project_activity")]
pub struct Model {
    #[sea_orm(primary_key, auto_increment = true)]
    pub id: i64,
    pub project: ProjectId,
    #[sea_orm(nullable)]
    pub repo: Option<RepoId>,
    pub actor: UserId,
    #[sea_orm(column_type = "Text")]
    pub event_type: String,
    #[sea_orm(nullable)]
    pub event_id: Option<Uuid>,
    #[sea_orm(nullable)]
    pub event_sub_id: Option<i64>,
    #[sea_orm(column_type = "Text")]
    pub title: String,
    #[sea_orm(nullable, column_type = "Text")]
    pub content: Option<String>,
    #[sea_orm(nullable, column_type = "JsonBinary")]
    pub metadata: Option<Json>,
    pub is_private: bool,
    pub created_at: DateTimeUtc,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

impl ActiveModelBehavior for ActiveModel {}
